Merge branch 'curlthreading2' of git://github.com/AlericInglewood/SingularityViewer into curlthreading

This commit is contained in:
Siana Gearz
2012-07-28 17:28:18 +02:00
15 changed files with 84 additions and 3006 deletions

View File

@@ -264,7 +264,7 @@ bool LLQueuedThread::waitForResult(LLQueuedThread::handle_t handle, bool auto_co
{
done = true; // request does not exist
}
else if (req->getStatus() == STATUS_COMPLETE)
else if (req->getStatus() == STATUS_COMPLETE && !(req->getFlags() & FLAG_LOCKED))
{
res = true;
if (auto_complete)
@@ -372,9 +372,17 @@ bool LLQueuedThread::completeRequest(handle_t handle)
#if _DEBUG
// llinfos << llformat("LLQueuedThread::Completed req [%08d]",handle) << llendl;
#endif
mRequestHash.erase(handle);
req->deleteRequest();
// check();
if (!(req->getFlags() & FLAG_LOCKED))
{
mRequestHash.erase(handle);
req->deleteRequest();
// check();
}
else
{
// Cause deletion immediately after FLAG_LOCKED is released.
req->setFlags(FLAG_AUTO_COMPLETE);
}
res = true;
}
unlockData();
@@ -421,12 +429,44 @@ S32 LLQueuedThread::processNextRequest()
if ((req->getFlags() & FLAG_ABORT) || (mStatus == QUITTING))
{
req->setStatus(STATUS_ABORTED);
// Unlock, because we can't call finishRequest() while keeping this lock:
// generateHandle() takes this lock too and is called while holding a lock
// (ie LLTextureFetchWorker::mWorkMutex) that finishRequest will lock too,
// causing a dead lock.
// Although a complete rewrite of LLQueuedThread is in order because it's
// far from robust the way it handles it's locking; the following rationale
// at least makes plausible that releasing the lock here SHOULD work if
// the original coder didn't completely fuck up: if before the QueuedRequest
// req was only accessed while keeping the lock, then it still should
// never happen that another thread is waiting for this lock in order to
// access the QueuedRequest: a few lines lower we delete it.
// In other words, if directly after releasing this lock another thread
// would access req, then that can only happen by finding it again in
// either mRequestQueue or mRequestHash. We already deleted it from the
// first, so this access would have to happen by finding it in mRequestHash.
// Such access happens in the following functions:
// 1) LLQueuedThread::shutdown -- but it does that anyway, as it doesn't use any locking.
// 2) LLQueuedThread::generateHandle -- might skip our handle while before it would block until we deleted it. Skipping it is actually better.
// 3) LLQueuedThread::waitForResult -- this now doesn't touch the req when it has the flag FLAG_LOCKED set.
// 4) LLQueuedThread::getRequest -- whereever this is used, FLAG_LOCKED is tested before using the req.
// 5) LLQueuedThread::getRequestStatus -- this is a read-only operation on the status, which should never be changed from finishRequest().
// 6) LLQueuedThread::abortRequest -- it doesn't seem to hurt to add flags (if this happens at all), while calling finishRequest().
// 7) LLQueuedThread::setFlags -- same.
// 8) LLQueuedThread::setPriority -- doesn't access req with status STATUS_ABORTED, STATUS_COMPLETE or STATUS_INPROGRESS.
// 9) LLQueuedThread::completeRequest -- now sets FLAG_AUTO_COMPLETE instead of deleting the req, if FLAG_LOCKED is set, so that deletion happens here when finishRequest returns.
req->setFlags(FLAG_LOCKED);
unlockData();
req->finishRequest(false);
if (req->getFlags() & FLAG_AUTO_COMPLETE)
lockData();
req->resetFlags(FLAG_LOCKED);
if ((req->getFlags() & FLAG_AUTO_COMPLETE))
{
req->resetFlags(FLAG_AUTO_COMPLETE);
mRequestHash.erase(req);
req->deleteRequest();
// check();
unlockData();
req->deleteRequest();
lockData();
}
continue;
}
@@ -453,14 +493,23 @@ S32 LLQueuedThread::processNextRequest()
{
lockData();
req->setStatus(STATUS_COMPLETE);
req->finishRequest(true);
if (req->getFlags() & FLAG_AUTO_COMPLETE)
{
mRequestHash.erase(req);
req->deleteRequest();
// check();
}
req->setFlags(FLAG_LOCKED);
unlockData();
req->finishRequest(true);
if ((req->getFlags() & FLAG_AUTO_COMPLETE))
{
lockData();
req->resetFlags(FLAG_AUTO_COMPLETE);
mRequestHash.erase(req);
// check();
req->resetFlags(FLAG_LOCKED);
unlockData();
req->deleteRequest();
}
else
{
req->resetFlags(FLAG_LOCKED);
}
}
else
{

View File

@@ -72,7 +72,8 @@ public:
enum flags_t {
FLAG_AUTO_COMPLETE = 1,
FLAG_AUTO_DELETE = 2, // child-class dependent
FLAG_ABORT = 4
FLAG_ABORT = 4,
FLAG_LOCKED = 8
};
typedef U32 handle_t;
@@ -124,6 +125,10 @@ public:
// NOTE: flags are |'d
mFlags |= flags;
}
void resetFlags(U32 flags)
{
mFlags &= ~flags;
}
virtual bool processRequest() = 0; // Return true when request has completed
virtual void finishRequest(bool completed); // Always called from thread after request has completed or aborted

View File

@@ -226,7 +226,8 @@ LLWorkerClass::~LLWorkerClass()
llerrs << "LLWorkerClass destroyed with stale work handle" << llendl;
}
if (workreq->getStatus() != LLWorkerThread::STATUS_ABORTED &&
workreq->getStatus() != LLWorkerThread::STATUS_COMPLETE)
workreq->getStatus() != LLWorkerThread::STATUS_COMPLETE &&
!(workreq->getFlags() & LLWorkerThread::FLAG_LOCKED))
{
llerrs << "LLWorkerClass destroyed with active worker! Worker Status: " << workreq->getStatus() << llendl;
}
@@ -350,14 +351,10 @@ bool LLWorkerClass::checkWork(bool aborting)
}
LLQueuedThread::status_t status = workreq->getStatus();
if (status == LLWorkerThread::STATUS_ABORTED)
if (status == LLWorkerThread::STATUS_COMPLETE || status == LLWorkerThread::STATUS_ABORTED)
{
complete = true;
abort = true;
}
else if (status == LLWorkerThread::STATUS_COMPLETE)
{
complete = true;
complete = !(workreq->getFlags() & LLWorkerThread::FLAG_LOCKED);
abort = status == LLWorkerThread::STATUS_ABORTED;
}
else
{

View File

@@ -67,8 +67,6 @@ set(llmessage_SOURCE_FILES
llsdmessage.cpp
llsdmessagebuilder.cpp
llsdmessagereader.cpp
llsdrpcclient.cpp
llsdrpcserver.cpp
llservicebuilder.cpp
llservice.cpp
llstoredmessage.cpp
@@ -168,8 +166,6 @@ set(llmessage_HEADER_FILES
llsdmessage.h
llsdmessagebuilder.h
llsdmessagereader.h
llsdrpcclient.h
llsdrpcserver.h
llservice.h
llservicebuilder.h
llstoredmessage.h

View File

@@ -887,6 +887,8 @@ static int curl_debug_callback(CURL*, curl_infotype infotype, char* buf, size_t
marker << (void*)request->get_lockobj();
libcw_do.push_marker();
libcw_do.marker().assign(marker.str().data(), marker.str().size());
if (!debug::channels::dc::curlio.is_on())
debug::channels::dc::curlio.on();
LibcwDoutScopeBegin(LIBCWD_DEBUGCHANNELS, libcw_do, dc::curlio|cond_nonewline_cf(infotype == CURLINFO_TEXT))
switch (infotype)
{
@@ -1116,7 +1118,7 @@ CurlResponderBuffer::CurlResponderBuffer()
curl_easy_request_w->send_events_to(this);
}
#define llmaybeerrs lllog(LLApp::isExiting() ? LLError::LEVEL_WARN : LLError::LEVEL_ERROR, NULL, NULL, false)
#define llmaybeerrs lllog(LLApp::isRunning ? LLError::LEVEL_ERROR : LLError::LEVEL_WARN, NULL, NULL, false)
// The callbacks need to be revoked when the CurlResponderBuffer is destructed (because that is what the callbacks use).
// The AIThreadSafeSimple<CurlResponderBuffer> is destructed first (right to left), so when we get here then the

View File

@@ -1,255 +0,0 @@
/**
* @file llsdrpcclient.cpp
* @author Phoenix
* @date 2005-11-05
* @brief Implementation of the llsd client classes.
*
* $LicenseInfo:firstyear=2005&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "llsdrpcclient.h"
#include "llbufferstream.h"
#include "llfasttimer.h"
#include "llfiltersd2xmlrpc.h"
#include "llmemtype.h"
#include "llpumpio.h"
#include "llsd.h"
#include "llsdserialize.h"
#include "llurlrequest.h"
/**
* String constants
*/
static std::string LLSDRPC_RESPONSE_NAME("response");
static std::string LLSDRPC_FAULT_NAME("fault");
/**
* LLSDRPCResponse
*/
LLSDRPCResponse::LLSDRPCResponse() :
mIsError(false),
mIsFault(false)
{
LLMemType m1(LLMemType::MTYPE_IO_SD_CLIENT);
}
// virtual
LLSDRPCResponse::~LLSDRPCResponse()
{
LLMemType m1(LLMemType::MTYPE_IO_SD_CLIENT);
}
bool LLSDRPCResponse::extractResponse(const LLSD& sd)
{
LLMemType m1(LLMemType::MTYPE_IO_SD_CLIENT);
bool rv = true;
if(sd.has(LLSDRPC_RESPONSE_NAME))
{
mReturnValue = sd[LLSDRPC_RESPONSE_NAME];
mIsFault = false;
}
else if(sd.has(LLSDRPC_FAULT_NAME))
{
mReturnValue = sd[LLSDRPC_FAULT_NAME];
mIsFault = true;
}
else
{
mReturnValue.clear();
mIsError = true;
rv = false;
}
return rv;
}
static LLFastTimer::DeclareTimer FTM_SDRPC_RESPONSE("SDRPC Response");
// virtual
LLIOPipe::EStatus LLSDRPCResponse::process_impl(
const LLChannelDescriptors& channels,
buffer_ptr_t& buffer,
bool& eos,
LLSD& context,
LLPumpIO* pump)
{
LLFastTimer t(FTM_SDRPC_RESPONSE);
PUMP_DEBUG;
LLMemType m1(LLMemType::MTYPE_IO_SD_CLIENT);
if(mIsError)
{
error(pump);
}
else if(mIsFault)
{
fault(pump);
}
else
{
response(pump);
}
PUMP_DEBUG;
return STATUS_DONE;
}
/**
* LLSDRPCClient
*/
LLSDRPCClient::LLSDRPCClient() :
mState(STATE_NONE),
mQueue(EPBQ_PROCESS)
{
LLMemType m1(LLMemType::MTYPE_IO_SD_CLIENT);
}
// virtual
LLSDRPCClient::~LLSDRPCClient()
{
LLMemType m1(LLMemType::MTYPE_IO_SD_CLIENT);
}
bool LLSDRPCClient::call(
const std::string& uri,
const std::string& method,
const LLSD& parameter,
LLSDRPCResponse* response,
EPassBackQueue queue)
{
LLMemType m1(LLMemType::MTYPE_IO_SD_CLIENT);
//llinfos << "RPC: " << uri << "." << method << "(" << *parameter << ")"
// << llendl;
if(method.empty() || !response)
{
return false;
}
mState = STATE_READY;
mURI.assign(uri);
std::stringstream req;
req << LLSDRPC_REQUEST_HEADER_1 << method
<< LLSDRPC_REQUEST_HEADER_2;
LLSDSerialize::toNotation(parameter, req);
req << LLSDRPC_REQUEST_FOOTER;
mRequest = req.str();
mQueue = queue;
mResponse = response;
return true;
}
bool LLSDRPCClient::call(
const std::string& uri,
const std::string& method,
const std::string& parameter,
LLSDRPCResponse* response,
EPassBackQueue queue)
{
LLMemType m1(LLMemType::MTYPE_IO_SD_CLIENT);
//llinfos << "RPC: " << uri << "." << method << "(" << parameter << ")"
// << llendl;
if(method.empty() || parameter.empty() || !response)
{
return false;
}
mState = STATE_READY;
mURI.assign(uri);
std::stringstream req;
req << LLSDRPC_REQUEST_HEADER_1 << method
<< LLSDRPC_REQUEST_HEADER_2 << parameter
<< LLSDRPC_REQUEST_FOOTER;
mRequest = req.str();
mQueue = queue;
mResponse = response;
return true;
}
static LLFastTimer::DeclareTimer FTM_PROCESS_SDRPC_CLIENT("SDRPC Client");
// virtual
LLIOPipe::EStatus LLSDRPCClient::process_impl(
const LLChannelDescriptors& channels,
buffer_ptr_t& buffer,
bool& eos,
LLSD& context,
LLPumpIO* pump)
{
LLFastTimer t(FTM_PROCESS_SDRPC_CLIENT);
PUMP_DEBUG;
LLMemType m1(LLMemType::MTYPE_IO_SD_CLIENT);
if((STATE_NONE == mState) || (!pump))
{
// You should have called the call() method already.
return STATUS_PRECONDITION_NOT_MET;
}
EStatus rv = STATUS_DONE;
switch(mState)
{
case STATE_READY:
{
PUMP_DEBUG;
// lldebugs << "LLSDRPCClient::process_impl STATE_READY" << llendl;
buffer->append(
channels.out(),
(U8*)mRequest.c_str(),
mRequest.length());
context[CONTEXT_DEST_URI_SD_LABEL] = mURI;
mState = STATE_WAITING_FOR_RESPONSE;
break;
}
case STATE_WAITING_FOR_RESPONSE:
{
PUMP_DEBUG;
// The input channel has the sd response in it.
//lldebugs << "LLSDRPCClient::process_impl STATE_WAITING_FOR_RESPONSE"
// << llendl;
LLBufferStream resp(channels, buffer.get());
LLSD sd;
LLSDSerialize::fromNotation(sd, resp, buffer->count(channels.in()));
LLSDRPCResponse* response = (LLSDRPCResponse*)mResponse.get();
if (!response)
{
mState = STATE_DONE;
break;
}
response->extractResponse(sd);
if(EPBQ_PROCESS == mQueue)
{
LLPumpIO::chain_t chain;
chain.push_back(mResponse);
pump->addChain(chain, DEFAULT_CHAIN_EXPIRY_SECS);
}
else
{
pump->respond(mResponse.get());
}
mState = STATE_DONE;
break;
}
case STATE_DONE:
default:
PUMP_DEBUG;
llinfos << "invalid state to process" << llendl;
rv = STATUS_ERROR;
break;
}
return rv;
}

View File

@@ -1,329 +0,0 @@
/**
* @file llsdrpcclient.h
* @author Phoenix
* @date 2005-11-05
* @brief Implementation and helpers for structure data RPC clients.
*
* $LicenseInfo:firstyear=2005&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLSDRPCCLIENT_H
#define LL_LLSDRPCCLIENT_H
/**
* This file declares classes to encapsulate a basic structured data
* remote procedure client.
*/
#include "llchainio.h"
#include "llfiltersd2xmlrpc.h"
#include "lliopipe.h"
#include "llurlrequest.h"
/**
* @class LLSDRPCClientResponse
* @brief Abstract base class to represent a response from an SD server.
*
* This is used as a base class for callbacks generated from an
* structured data remote procedure call. The
* <code>extractResponse</code> method will deal with the llsdrpc method
* call overhead, and keep track of what to call during the next call
* into <code>process</code>. If you use this as a base class, you
* need to implement <code>response</code>, <code>fault</code>, and
* <code>error</code> to do something useful. When in those methods,
* you can parse and utilize the mReturnValue member data.
*/
class LLSDRPCResponse : public LLIOPipe
{
public:
LLSDRPCResponse();
virtual ~LLSDRPCResponse();
/**
* @brief This method extracts the response out of the sd passed in
*
* Any appropriate data found in the sd passed in will be
* extracted and managed by this object - not copied or cloned. It
* will still be up to the caller to delete the pointer passed in.
* @param sd The raw structured data response from the remote server.
* @return Returns true if this was able to parse the structured data.
*/
bool extractResponse(const LLSD& sd);
protected:
/**
* @brief Method called when the response is ready.
*/
virtual bool response(LLPumpIO* pump) = 0;
/**
* @brief Method called when a fault is generated by the remote server.
*/
virtual bool fault(LLPumpIO* pump) = 0;
/**
* @brief Method called when there was an error
*/
virtual bool error(LLPumpIO* pump) = 0;
protected:
/* @name LLIOPipe virtual implementations
*/
//@{
/**
* @brief Process the data in buffer
*/
virtual EStatus process_impl(
const LLChannelDescriptors& channels,
buffer_ptr_t& buffer,
bool& eos,
LLSD& context,
LLPumpIO* pump);
//@}
protected:
LLSD mReturnValue;
bool mIsError;
bool mIsFault;
};
/**
* @class LLSDRPCClient
* @brief Client class for a structured data remote procedure call.
*
* This class helps deal with making structured data calls to a remote
* server. You can visualize the calls as:
* <code>
* response = uri.method(parameter)
* </code>
* where you pass in everything to <code>call</code> and this class
* takes care of the rest of the details.
* In typical usage, you will derive a class from this class and
* provide an API more useful for the specific application at
* hand. For example, if you were writing a service to send an instant
* message, you could create an API for it to send the messsage, and
* that class would do the work of translating it into the method and
* parameter, find the destination, and invoke <code>call</call> with
* a useful implementation of LLSDRPCResponse passed in to handle the
* response from the network.
*/
class LLSDRPCClient : public LLIOPipe
{
public:
LLSDRPCClient();
virtual ~LLSDRPCClient();
/**
* @brief Enumeration for tracking which queue to process the
* response.
*/
enum EPassBackQueue
{
EPBQ_PROCESS,
EPBQ_CALLBACK,
};
/**
* @brief Call a method on a remote LLSDRPCServer
*
* @param uri The remote object to call, eg,
* http://localhost/usher. If you are using a factory with a fixed
* url, the uri passed in will probably be ignored.
* @param method The method to call on the remote object
* @param parameter The parameter to pass into the remote
* object. It is up to the caller to delete the value passed in.
* @param response The object which gets the response.
* @param queue Specifies to call the response on the process or
* callback queue.
* @return Returns true if this object will be able to make the RPC call.
*/
bool call(
const std::string& uri,
const std::string& method,
const LLSD& parameter,
LLSDRPCResponse* response,
EPassBackQueue queue);
/**
* @brief Call a method on a remote LLSDRPCServer
*
* @param uri The remote object to call, eg,
* http://localhost/usher. If you are using a factory with a fixed
* url, the uri passed in will probably be ignored.
* @param method The method to call on the remote object
* @param parameter The seriailized parameter to pass into the
* remote object.
* @param response The object which gets the response.
* @param queue Specifies to call the response on the process or
* callback queue.
* @return Returns true if this object will be able to make the RPC call.
*/
bool call(
const std::string& uri,
const std::string& method,
const std::string& parameter,
LLSDRPCResponse* response,
EPassBackQueue queue);
protected:
/**
* @brief Enumeration for tracking client state.
*/
enum EState
{
STATE_NONE,
STATE_READY,
STATE_WAITING_FOR_RESPONSE,
STATE_DONE
};
/* @name LLIOPipe virtual implementations
*/
//@{
/**
* @brief Process the data in buffer
*/
virtual EStatus process_impl(
const LLChannelDescriptors& channels,
buffer_ptr_t& buffer,
bool& eos,
LLSD& context,
LLPumpIO* pump);
//@}
protected:
EState mState;
std::string mURI;
std::string mRequest;
EPassBackQueue mQueue;
LLIOPipe::ptr_t mResponse;
};
/**
* @class LLSDRPCClientFactory
* @brief Basic implementation for making an SD RPC client factory
*
* This class eases construction of a basic sd rpc client. Here is an
* example of it's use:
* <code>
* class LLUsefulService : public LLService { ... }
* LLService::registerCreator(
* "useful",
* LLService::creator_t(new LLSDRPCClientFactory<LLUsefulService>))
* </code>
*/
template<class Client>
class LLSDRPCClientFactory : public LLChainIOFactory
{
public:
LLSDRPCClientFactory() {}
LLSDRPCClientFactory(const std::string& fixed_url) : mURL(fixed_url) {}
virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const
{
lldebugs << "LLSDRPCClientFactory::build" << llendl;
LLURLRequest* http;
try
{
http = new LLURLRequest(LLURLRequest::HTTP_POST);
}
catch(AICurlNoEasyHandle const& error)
{
llwarns << "Creating LLURLRequest failed: " << error.what() << llendl ;
return false;
}
LLIOPipe::ptr_t service(new Client);
chain.push_back(service);
LLIOPipe::ptr_t http_pipe(http);
http->addHeader("Content-Type: text/llsd");
if(mURL.empty())
{
chain.push_back(LLIOPipe::ptr_t(new LLContextURLExtractor(http)));
}
else
{
http->setURL(mURL);
}
chain.push_back(http_pipe);
chain.push_back(service);
return true;
}
protected:
std::string mURL;
};
/**
* @class LLXMLSDRPCClientFactory
* @brief Basic implementation for making an XMLRPC to SD RPC client factory
*
* This class eases construction of a basic sd rpc client which uses
* xmlrpc as a serialization grammar. Here is an example of it's use:
* <code>
* class LLUsefulService : public LLService { ... }
* LLService::registerCreator(
* "useful",
* LLService::creator_t(new LLXMLSDRPCClientFactory<LLUsefulService>))
* </code>
*/
template<class Client>
class LLXMLSDRPCClientFactory : public LLChainIOFactory
{
public:
LLXMLSDRPCClientFactory() {}
LLXMLSDRPCClientFactory(const std::string& fixed_url) : mURL(fixed_url) {}
virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const
{
lldebugs << "LLXMLSDRPCClientFactory::build" << llendl;
LLURLRequest* http;
try
{
http = new LLURLRequest(LLURLRequest::HTTP_POST);
}
catch(AICurlNoEasyHandle const& error)
{
llwarns << "Creating LLURLRequest failed: " << error.what() << llendl ;
return false ;
}
LLIOPipe::ptr_t service(new Client);
chain.push_back(service);
LLIOPipe::ptr_t http_pipe(http);
http->addHeader("Content-Type: text/xml");
if(mURL.empty())
{
chain.push_back(LLIOPipe::ptr_t(new LLContextURLExtractor(http)));
}
else
{
http->setURL(mURL);
}
chain.push_back(LLIOPipe::ptr_t(new LLFilterSD2XMLRPCRequest(NULL)));
chain.push_back(http_pipe);
chain.push_back(LLIOPipe::ptr_t(new LLFilterXMLRPCResponse2LLSD));
chain.push_back(service);
return true;
}
protected:
std::string mURL;
};
#endif // LL_LLSDRPCCLIENT_H

View File

@@ -1,347 +0,0 @@
/**
* @file llsdrpcserver.cpp
* @author Phoenix
* @date 2005-10-11
* @brief Implementation of the LLSDRPCServer and related classes.
*
* $LicenseInfo:firstyear=2005&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "llsdrpcserver.h"
#include "llbuffer.h"
#include "llbufferstream.h"
#include "llfasttimer.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;
}
}
static LLFastTimer::DeclareTimer FTM_PROCESS_SDRPC_SERVER("SDRPC Server");
// virtual
LLIOPipe::EStatus LLSDRPCServer::process_impl(
const LLChannelDescriptors& channels,
buffer_ptr_t& buffer,
bool& eos,
LLSD& context,
LLPumpIO* pump)
{
LLFastTimer t(FTM_PROCESS_SDRPC_SERVER);
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,
buffer->count(channels.in()));
// { '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
}

View File

@@ -1,360 +0,0 @@
/**
* @file llsdrpcserver.h
* @author Phoenix
* @date 2005-10-11
* @brief Declaration of the structured data remote procedure call server.
*
* $LicenseInfo:firstyear=2005&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLSDRPCSERVER_H
#define LL_LLSDRPCSERVER_H
/**
* I've set this up to be pretty easy to use when you want to make a
* structured data rpc server which responds to methods by
* name. Derive a class from the LLSDRPCServer, and during
* construction (or initialization if you have the luxury) map method
* names to pointers to member functions. This will look a lot like:
*
* <code>
* class LLMessageAgents : public LLSDRPCServer {<br>
* public:<br>
* typedef LLSDRPCServer<LLUsher> mem_fn_t;<br>
* LLMessageAgents() {<br>
* mMethods["message"] = new mem_fn_t(this, &LLMessageAgents::rpc_IM);<br>
* mMethods["alert"] = new mem_fn_t(this, &LLMessageAgents::rpc_Alrt);<br>
* }<br>
* protected:<br>
* rpc_IM(const LLSD& params,
* const LLChannelDescriptors& channels,
* LLBufferArray* data)
* {...}<br>
* rpc_Alert(const LLSD& params,
* const LLChannelDescriptors& channels,
* LLBufferArray* data)
* {...}<br>
* };<br>
* </code>
*
* The params are an array where each element in the array is a single
* parameter in the call.
*
* It is up to you to pack a valid serialized llsd response into the
* data object passed into the method, but you can use the helper
* methods below to help.
*/
#include <map>
#include "lliopipe.h"
#include "lliohttpserver.h"
#include "llfiltersd2xmlrpc.h"
class LLSD;
/**
* @brief Enumeration for specifying server method call status. This
* enumeration controls how the server class will manage the pump
* process/callback mechanism.
*/
enum ESDRPCSStatus
{
// The call went ok, but the response is not yet ready. The
// method will arrange for the clearLock() call to be made at
// a later date, after which, once the chain is being pumped
// again, deferredResponse() will be called to gather the result
ESDRPCS_DEFERRED,
// The LLSDRPCServer would like to handle the method on the
// callback queue of the pump.
ESDRPCS_CALLBACK,
// The method call finished and generated output.
ESDRPCS_DONE,
// Method failed for some unspecified reason - you should avoid
// this. A generic fault will be sent to the output.
ESDRPCS_ERROR,
ESDRPCS_COUNT,
};
/**
* @class LLSDRPCMethodCallBase
* @brief Base class for calling a member function in an sd rpcserver
* implementation.
*/
class LLSDRPCMethodCallBase
{
public:
LLSDRPCMethodCallBase() {}
virtual ~LLSDRPCMethodCallBase() {}
virtual ESDRPCSStatus call(
const LLSD& params,
const LLChannelDescriptors& channels,
LLBufferArray* response) = 0;
protected:
};
/**
* @class LLSDRPCMethodCall
* @brief Class which implements member function calls.
*/
template<class Server>
class LLSDRPCMethodCall : public LLSDRPCMethodCallBase
{
public:
typedef ESDRPCSStatus (Server::*mem_fn)(
const LLSD& params,
const LLChannelDescriptors& channels,
LLBufferArray* data);
LLSDRPCMethodCall(Server* s, mem_fn fn) :
mServer(s),
mMemFn(fn)
{
}
virtual ~LLSDRPCMethodCall() {}
virtual ESDRPCSStatus call(
const LLSD& params,
const LLChannelDescriptors& channels,
LLBufferArray* data)
{
return (*mServer.*mMemFn)(params, channels, data);
}
protected:
Server* mServer;
mem_fn mMemFn;
//bool (Server::*mMemFn)(const LLSD& params, LLBufferArray& data);
};
/**
* @class LLSDRPCServer
* @brief Basic implementation of a structure data rpc server
*
* The rpc server is also designed to appropriately straddle the pump
* <code>process()</code> and <code>callback()</code> to specify which
* thread you want to work on when handling a method call. The
* <code>mMethods</code> methods are called from
* <code>process()</code>, while the <code>mCallbackMethods</code> are
* called when a pump is in a <code>callback()</code> cycle.
*/
class LLSDRPCServer : public LLIOPipe
{
public:
LLSDRPCServer();
virtual ~LLSDRPCServer();
/**
* enumeration for generic fault codes
*/
enum
{
FAULT_BAD_REQUEST = 2000,
FAULT_NO_RESPONSE = 2001,
};
/**
* @brief Call this method to return an rpc fault.
*
* @param channel The channel for output on the data buffer
* @param data buffer which will recieve the final output
* @param code The fault code
* @param msg The fault message
*/
static void buildFault(
const LLChannelDescriptors& channels,
LLBufferArray* data,
S32 code,
const std::string& msg);
/**
* @brief Call this method to build an rpc response.
*
* @param channel The channel for output on the data buffer
* @param data buffer which will recieve the final output
* @param response The return value from the method call
*/
static void buildResponse(
const LLChannelDescriptors& channels,
LLBufferArray* data,
const LLSD& response);
protected:
/* @name LLIOPipe virtual implementations
*/
//@{
/**
* @brief Process the data in buffer
*/
virtual EStatus process_impl(
const LLChannelDescriptors& channels,
buffer_ptr_t& buffer,
bool& eos,
LLSD& context,
LLPumpIO* pump);
//@}
protected:
/**
* @brief Enumeration to track the state of the rpc server instance
*/
enum EState
{
STATE_NONE,
STATE_CALLBACK,
STATE_DEFERRED,
STATE_DONE
};
/**
* @brief This method is called when an http post comes in.
*
* The default behavior is to look at the method name, look up the
* method in the method table, and call it. If the method is not
* found, this function will build a fault response. You can
* implement your own version of this function if you want to hard
* wire some behavior or optimize things a bit.
* @param method The method name being called
* @param params The parameters
* @param channel The channel for output on the data buffer
* @param data The http data
* @return Returns the status of the method call, done/deferred/etc
*/
virtual ESDRPCSStatus callMethod(
const std::string& method,
const LLSD& params,
const LLChannelDescriptors& channels,
LLBufferArray* data);
/**
* @brief This method is called when a pump callback is processed.
*
* The default behavior is to look at the method name, look up the
* method in the callback method table, and call it. If the method
* is not found, this function will build a fault response. You
* can implement your own version of this function if you want to
* hard wire some behavior or optimize things a bit.
* @param method The method name being called
* @param params The parameters
* @param channel The channel for output on the data buffer
* @param data The http data
* @return Returns the status of the method call, done/deferred/etc
*/
virtual ESDRPCSStatus callbackMethod(
const std::string& method,
const LLSD& params,
const LLChannelDescriptors& channels,
LLBufferArray* data);
/**
* @brief Called after a deferred service is unlocked
*
* If a method returns ESDRPCS_DEFERRED, then the service chain
* will be locked and not processed until some other system calls
* clearLock() on the service instance again. At that point,
* once the pump starts processing the chain again, this method
* will be called so the service can output the final result
* into the buffers.
*/
virtual ESDRPCSStatus deferredResponse(
const LLChannelDescriptors& channels,
LLBufferArray* data);
// donovan put this public here 7/27/06
public:
/**
* @brief unlock a service that as ESDRPCS_DEFERRED
*/
void clearLock();
protected:
EState mState;
LLSD mRequest;
LLPumpIO* mPump;
S32 mLock;
typedef std::map<std::string, LLSDRPCMethodCallBase*> method_map_t;
method_map_t mMethods;
method_map_t mCallbackMethods;
};
/**
* @name Helper Templates for making LLHTTPNodes
*
* These templates help in creating nodes for handing a service from
* either SDRPC or XMLRPC, given a single implementation of LLSDRPCServer.
*
* To use it:
* \code
* class LLUsefulServer : public LLSDRPCServer { ... }
*
* LLHTTPNode& root = LLCreateHTTPWireServer(...);
* root.addNode("llsdrpc/useful", new LLSDRPCNode<LLUsefulServer>);
* root.addNode("xmlrpc/useful", new LLXMLRPCNode<LLUsefulServer>);
* \endcode
*/
//@{
template<class Server>
class LLSDRPCServerFactory : public LLChainIOFactory
{
public:
virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const
{
lldebugs << "LLXMLSDRPCServerFactory::build" << llendl;
chain.push_back(LLIOPipe::ptr_t(new Server));
return true;
}
};
template<class Server>
class LLSDRPCNode : public LLHTTPNodeForFactory<
LLSDRPCServerFactory<Server> >
{
};
template<class Server>
class LLXMLRPCServerFactory : public LLChainIOFactory
{
public:
virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const
{
lldebugs << "LLXMLSDRPCServerFactory::build" << llendl;
chain.push_back(LLIOPipe::ptr_t(new LLFilterXMLRPCRequest2LLSD));
chain.push_back(LLIOPipe::ptr_t(new Server));
chain.push_back(LLIOPipe::ptr_t(new LLFilterSD2XMLRPCResponse));
return true;
}
};
template<class Server>
class LLXMLRPCNode : public LLHTTPNodeForFactory<
LLXMLRPCServerFactory<Server> >
{
};
//@}
#endif // LL_LLSDRPCSERVER_H

View File

@@ -52,7 +52,6 @@ static const U32 HTTP_STATUS_PIPE_ERROR = 499;
/**
* String constants
*/
const std::string CONTEXT_DEST_URI_SD_LABEL("dest_uri");
const std::string CONTEXT_TRANSFERED_BYTES("transfered_bytes");
@@ -715,42 +714,6 @@ static size_t headerCallback(char* header_line, size_t size, size_t nmemb, void*
return header_len;
}
static LLFastTimer::DeclareTimer FTM_PROCESS_URL_EXTRACTOR("URL Extractor");
/**
* LLContextURLExtractor
*/
// virtual
LLIOPipe::EStatus LLContextURLExtractor::process_impl(
const LLChannelDescriptors& channels,
buffer_ptr_t& buffer,
bool& eos,
LLSD& context,
LLPumpIO* pump)
{
LLFastTimer t(FTM_PROCESS_URL_EXTRACTOR);
PUMP_DEBUG;
LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
// The destination host is in the context.
if(context.isUndefined() || !mRequest)
{
return STATUS_PRECONDITION_NOT_MET;
}
// copy in to out, since this just extract the URL and does not
// actually change the data.
LLChangeChannel change(channels.in(), channels.out());
std::for_each(buffer->beginSegment(), buffer->endSegment(), change);
// find the context url
if(context.has(CONTEXT_DEST_URI_SD_LABEL))
{
mRequest->setURL(context[CONTEXT_DEST_URI_SD_LABEL].asString());
return STATUS_DONE;
}
return STATUS_ERROR;
}
/**
* LLURLRequestComplete
*/

View File

@@ -42,7 +42,6 @@
extern const std::string CONTEXT_REQUEST;
extern const std::string CONTEXT_DEST_URI_SD_LABEL;
extern const std::string CONTEXT_RESPONSE;
extern const std::string CONTEXT_TRANSFERED_BYTES;
@@ -276,42 +275,6 @@ private:
LLURLRequest(const LLURLRequest&);
};
/**
* @class LLContextURLExtractor
* @brief This class unpacks the url out of a agent usher service so
* it can be packed into a LLURLRequest object.
* @see LLIOPipe
*
* This class assumes that the context is a map that contains an entry
* named CONTEXT_DEST_URI_SD_LABEL.
*/
class LLContextURLExtractor : public LLIOPipe
{
public:
LLContextURLExtractor(LLURLRequest* req) : mRequest(req) {}
~LLContextURLExtractor() {}
protected:
/* @name LLIOPipe virtual implementations
*/
//@{
/**
* @brief Process the data in buffer
*/
virtual EStatus process_impl(
const LLChannelDescriptors& channels,
buffer_ptr_t& buffer,
bool& eos,
LLSD& context,
LLPumpIO* pump);
//@}
protected:
LLURLRequest* mRequest;
};
/**
* @class LLURLRequestComplete
* @brief Class which can optionally be used with an LLURLRequest to
@@ -384,11 +347,4 @@ protected:
EStatus mRequestStatus;
};
/**
* External constants
*/
extern const std::string CONTEXT_DEST_URI_SD_LABEL;
#endif // LL_LLURLREQUEST_H

View File

@@ -175,7 +175,7 @@ BOOL LLVFile::isReadComplete()
{
LLVFSThread::Request* req = (LLVFSThread::Request*)sVFSThread->getRequest(mHandle);
LLVFSThread::status_t status = req->getStatus();
if (status == LLVFSThread::STATUS_COMPLETE)
if (status == LLVFSThread::STATUS_COMPLETE && !(req->getFlags() & LLVFSThread::FLAG_LOCKED))
{
mBytesRead = req->getBytesRead();
mPosition += mBytesRead;

View File

@@ -253,7 +253,9 @@ extern S32 gStartImageHeight;
// local globals
//
#ifdef CWDEBUG
static bool gCurlIo;
#endif
static LLHost gAgentSimHost;
static BOOL gSkipOptionalUpdate = FALSE;
@@ -1334,6 +1336,9 @@ bool idle_startup()
llinfos << "Authenticating with " << grid_uri << llendl;
// Always write curl I/O debug info for the login attempt.
Debug(gCurlIo = dc::curl.is_on() && !dc::curlio.is_on(); if (gCurlIo) dc::curlio.on());
// TODO if statement here to use web_login_key
// OGPX : which routine would this end up in? the LLSD or XMLRPC, or ....?
LLUserAuth::getInstance()->authenticate(
@@ -1408,6 +1413,7 @@ bool idle_startup()
LL_DEBUGS("AppInit") << "downloading..." << LL_ENDL;
return FALSE;
}
Debug(if (gCurlIo) dc::curlio.off()); // Login succeeded: restore dc::curlio to original state.
LLStartUp::setStartupState( STATE_LOGIN_PROCESS_RESPONSE );
progress += 0.01f;
set_startup_status(progress, LLTrans::getString("LoginProcessingResponse"), auth_message);

View File

@@ -28,7 +28,6 @@ include_directories(
set(test_SOURCE_FILES
common.cpp
inventory.cpp
io.cpp
# llapp_tut.cpp # Temporarily removed until thread issues can be solved
llbase64_tut.cpp
llblowfish_tut.cpp

File diff suppressed because one or more lines are too long