Compare commits
29 Commits
curlthread
...
shycurl
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
68ad5411c9 | ||
|
|
6ed9a62501 | ||
|
|
89be317a00 | ||
|
|
1ad4597d7a | ||
|
|
c65b659538 | ||
|
|
3c23163a29 | ||
|
|
c3900ee4f3 | ||
|
|
9c5da9e42c | ||
|
|
efa970c6a5 | ||
|
|
179f04739d | ||
|
|
b2f513caae | ||
|
|
9c1e74b0c0 | ||
|
|
e53af58d4a | ||
|
|
d9cb2ce6c7 | ||
|
|
a967f2b037 | ||
|
|
db5a7578c9 | ||
|
|
15086833a3 | ||
|
|
72a9b6b7fe | ||
|
|
0d3fab40e5 | ||
|
|
4e4d554ea4 | ||
|
|
c7bdaf6632 | ||
|
|
92c7792e95 | ||
|
|
1e81966b89 | ||
|
|
b785b9d219 | ||
|
|
85da7163a7 | ||
|
|
f3f8bee83b | ||
|
|
7843f51110 | ||
|
|
8bfdc98ef4 | ||
|
|
6673c89791 |
@@ -77,7 +77,6 @@ if (VIEWER)
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}llcrashlogger)
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}llplugin)
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}llui)
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}llxuixml)
|
||||
|
||||
# viewer plugins directory
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}plugins)
|
||||
|
||||
@@ -190,10 +190,10 @@ if (LINUX)
|
||||
endif (NOT STANDALONE)
|
||||
if (${ARCH} STREQUAL "x86_64")
|
||||
add_definitions(-DLINUX64=1 -pipe)
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fomit-frame-pointer -mmmx -msse -mfpmath=sse -msse2 -ffast-math -ftree-vectorize -fweb -fexpensive-optimizations -frename-registers")
|
||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -fomit-frame-pointer -mmmx -msse -mfpmath=sse -msse2 -ffast-math -ftree-vectorize -fweb -fexpensive-optimizations -frename-registers")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -fomit-frame-pointer -mmmx -msse -mfpmath=sse -msse2 -ffast-math -ftree-vectorize -fweb -fexpensive-optimizations -frename-registers")
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -fomit-frame-pointer -mmmx -msse -mfpmath=sse -msse2 -ffast-math -ftree-vectorize -fweb -fexpensive-optimizations -frename-registers")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fomit-frame-pointer -ffast-math -funroll-loops")
|
||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -fomit-frame-pointer -ffast-math -funroll-loops")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -ffast-math")
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -ffast-math")
|
||||
else (${ARCH} STREQUAL "x86_64")
|
||||
if (NOT STANDALONE)
|
||||
set(MARCH_FLAG " -march=pentium4")
|
||||
@@ -327,7 +327,7 @@ else (STANDALONE)
|
||||
glib-2.0
|
||||
gstreamer-0.10
|
||||
gtk-2.0
|
||||
llfreetype2
|
||||
freetype2
|
||||
pango-1.0
|
||||
)
|
||||
endif (STANDALONE)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# -*- cmake -*-
|
||||
include(Prebuilt)
|
||||
|
||||
set(CURL_FIND_QUIETLY OFF)
|
||||
set(CURL_FIND_QUIETLY ON)
|
||||
set(CURL_FIND_REQUIRED ON)
|
||||
|
||||
if (STANDALONE)
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
# -*- cmake -*-
|
||||
|
||||
set(LLXUIXML_INCLUDE_DIRS
|
||||
${LIBS_OPEN_DIR}/llxuixml
|
||||
)
|
||||
|
||||
set(LLXUIXML_LIBRARIES llxuixml)
|
||||
@@ -15,5 +15,5 @@ else (STANDALONE)
|
||||
else(LINUX)
|
||||
set(PNG_LIBRARIES png15)
|
||||
endif()
|
||||
set(PNG_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/libpng15)
|
||||
set(PNG_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/)
|
||||
endif (STANDALONE)
|
||||
|
||||
@@ -173,8 +173,6 @@ void stop_recording_backtraces(void)
|
||||
channel_ct backtrace DDCN("BACKTRACE"); //!< This debug channel is used for backtraces.
|
||||
channel_ct statemachine DDCN("STATEMACHINE"); //!< This debug channel is used for output related to class AIStateMachine.
|
||||
channel_ct caps DDCN("CAPS"); //!< This debug channel is used for output related to Capabilities.
|
||||
channel_ct curl DDCN("CURL"); //!< This debug channel is used for output related to Curl.
|
||||
channel_ct curlio DDCN("CURLIO"); //!< This debug channel is used to print debug output of libcurl.
|
||||
|
||||
} // namespace dc
|
||||
} // namespace DEBUGCHANNELS
|
||||
|
||||
@@ -118,8 +118,6 @@ extern CWD_API channel_ct sdl;
|
||||
extern CWD_API channel_ct backtrace;
|
||||
extern CWD_API channel_ct statemachine;
|
||||
extern CWD_API channel_ct caps;
|
||||
extern CWD_API channel_ct curl;
|
||||
extern CWD_API channel_ct curlio;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -43,11 +43,11 @@
|
||||
#include "lluuid.h"
|
||||
#include "llframetimer.h"
|
||||
#include "llassettype.h"
|
||||
#include "llextendedstatus.h"
|
||||
|
||||
#include "lllistener.h"
|
||||
|
||||
const F32 LL_WIND_UPDATE_INTERVAL = 0.1f;
|
||||
const F32 LL_ROLLOFF_MULTIPLIER_UNDER_WATER = 5.f; // How much sounds are weaker under water
|
||||
const F32 LL_WIND_UNDERWATER_CENTER_FREQ = 20.f;
|
||||
|
||||
const F32 ATTACHED_OBJECT_TIMEOUT = 5.0f;
|
||||
|
||||
@@ -72,6 +72,8 @@ bool attemptDelayLoad()
|
||||
|
||||
FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int outchannels);
|
||||
|
||||
FMOD::ChannelGroup *LLAudioEngine_FMODEX::mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT] = {0};
|
||||
|
||||
LLAudioEngine_FMODEX::LLAudioEngine_FMODEX(bool enable_profiler)
|
||||
{
|
||||
mInited = false;
|
||||
@@ -159,7 +161,13 @@ bool LLAudioEngine_FMODEX::init(const S32 num_channels, void* userdata)
|
||||
|
||||
U32 fmod_flags = FMOD_INIT_NORMAL;
|
||||
if(mEnableProfiler)
|
||||
{
|
||||
fmod_flags |= FMOD_INIT_ENABLE_PROFILE;
|
||||
mSystem->createChannelGroup("None", &mChannelGroups[AUDIO_TYPE_NONE]);
|
||||
mSystem->createChannelGroup("SFX", &mChannelGroups[AUDIO_TYPE_SFX]);
|
||||
mSystem->createChannelGroup("UI", &mChannelGroups[AUDIO_TYPE_UI]);
|
||||
mSystem->createChannelGroup("Ambient", &mChannelGroups[AUDIO_TYPE_AMBIENT]);
|
||||
}
|
||||
|
||||
#if LL_LINUX
|
||||
bool audio_ok = false;
|
||||
@@ -604,6 +612,9 @@ void LLAudioChannelFMODEX::play()
|
||||
Check_FMOD_Error(mChannelp->setPaused(false), "FMOD::Channel::pause");
|
||||
|
||||
getSource()->setPlayedOnce(true);
|
||||
|
||||
if(LLAudioEngine_FMODEX::mChannelGroups[getSource()->getType()])
|
||||
mChannelp->setChannelGroup(LLAudioEngine_FMODEX::mChannelGroups[getSource()->getType()]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ namespace FMOD
|
||||
{
|
||||
class System;
|
||||
class Channel;
|
||||
class ChannelGroup;
|
||||
class Sound;
|
||||
class DSP;
|
||||
}
|
||||
@@ -83,6 +84,9 @@ protected:
|
||||
FMOD::DSP *mWindDSP;
|
||||
FMOD::System *mSystem;
|
||||
bool mEnableProfiler;
|
||||
|
||||
public:
|
||||
static FMOD::ChannelGroup *mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT];
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -106,6 +106,15 @@ void LLListener_FMODEX::commitDeferredChanges()
|
||||
|
||||
void LLListener_FMODEX::setRolloffFactor(F32 factor)
|
||||
{
|
||||
//An internal FMODEx optimization skips 3D updates if there have not been changes to the 3D sound environment.
|
||||
//Sadly, a change in rolloff is not accounted for, thus we must touch the listener properties as well.
|
||||
//In short: Changing the position ticks a dirtyflag inside fmodex, which makes it not skip 3D processing next update call.
|
||||
if(mRolloffFactor != factor)
|
||||
{
|
||||
LLVector3 pos = mVelocity - LLVector3(0.f,0.f,.1f);
|
||||
mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)pos.mV, NULL, NULL, NULL);
|
||||
mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mVelocity.mV, NULL, NULL, NULL);
|
||||
}
|
||||
mRolloffFactor = factor;
|
||||
mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor);
|
||||
}
|
||||
|
||||
@@ -172,7 +172,6 @@ void LLStreamingAudio_FMODEX::update()
|
||||
|
||||
if(mFMODInternetStreamChannelp)
|
||||
{
|
||||
//llinfos << "progress = " << progress << llendl;
|
||||
if(!mMetaData)
|
||||
mMetaData = new LLSD;
|
||||
|
||||
@@ -484,4 +483,4 @@ void LLStreamingAudio_FMODEX::setBufferSizes(U32 streambuffertime, U32 decodebuf
|
||||
settings.cbsize=sizeof(settings);
|
||||
settings.defaultDecodeBufferSize = decodebuffertime;//ms
|
||||
mSystem->setAdvancedSettings(&settings);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,6 @@
|
||||
|
||||
#include "llcharacter.h"
|
||||
#include "llstring.h"
|
||||
#include "llfasttimer.h"
|
||||
|
||||
#define SKEL_HEADER "Linden Skeleton 1.0"
|
||||
|
||||
|
||||
@@ -250,9 +250,9 @@ BOOL LLHeadRotMotion::onUpdate(F32 time, U8* joint_mask)
|
||||
head_rot_local = nlerp(head_slerp_amt, mLastHeadRot, head_rot_local);
|
||||
mLastHeadRot = head_rot_local;
|
||||
|
||||
if(mNeckState->getJoint() && mNeckState->getJoint()->getParent()) //Guess this has crashed? Taken from snowglobe -Shyotl
|
||||
// Set the head rotation.
|
||||
if(mNeckState->getJoint() && mNeckState->getJoint()->getParent())
|
||||
{
|
||||
// Set the head rotation.
|
||||
LLQuaternion torsoRotLocal = mNeckState->getJoint()->getParent()->getWorldRotation() * currentInvRootRotWorld;
|
||||
head_rot_local = head_rot_local * ~torsoRotLocal;
|
||||
mNeckState->setRotation( nlerp(NECK_LAG, LLQuaternion::DEFAULT, head_rot_local) );
|
||||
|
||||
@@ -637,9 +637,9 @@ void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_ty
|
||||
motionp->fadeIn();
|
||||
}
|
||||
|
||||
// **********************
|
||||
//**********************
|
||||
// MOTION INACTIVE
|
||||
// **********************
|
||||
//**********************
|
||||
if (motionp->isStopped() && mAnimTime > motionp->getStopTime() + motionp->getEaseOutDuration())
|
||||
{
|
||||
// this motion has gone on too long, deactivate it
|
||||
@@ -659,9 +659,9 @@ void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_ty
|
||||
}
|
||||
}
|
||||
|
||||
// **********************
|
||||
//**********************
|
||||
// MOTION EASE OUT
|
||||
// **********************
|
||||
//**********************
|
||||
else if (motionp->isStopped() && mAnimTime > motionp->getStopTime())
|
||||
{
|
||||
// is this the first iteration in the ease out phase?
|
||||
@@ -684,9 +684,9 @@ void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_ty
|
||||
update_result = motionp->onUpdate(mAnimTime - motionp->mActivationTimestamp, last_joint_signature);
|
||||
}
|
||||
|
||||
// **********************
|
||||
//**********************
|
||||
// MOTION ACTIVE
|
||||
// **********************
|
||||
//**********************
|
||||
else if (mAnimTime > motionp->mActivationTimestamp + motionp->getEaseInDuration())
|
||||
{
|
||||
posep->setWeight(motionp->getFadeWeight());
|
||||
@@ -707,9 +707,9 @@ void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_ty
|
||||
update_result = motionp->onUpdate(mAnimTime - motionp->mActivationTimestamp, last_joint_signature);
|
||||
}
|
||||
|
||||
// **********************
|
||||
//**********************
|
||||
// MOTION EASE IN
|
||||
// **********************
|
||||
//**********************
|
||||
else if (mAnimTime >= motionp->mActivationTimestamp)
|
||||
{
|
||||
if (mLastTime < motionp->mActivationTimestamp)
|
||||
|
||||
@@ -93,6 +93,7 @@ class LLVisualParam
|
||||
{
|
||||
public:
|
||||
typedef boost::function<LLVisualParam*(S32)> visual_param_mapper;
|
||||
|
||||
LLVisualParam();
|
||||
virtual ~LLVisualParam();
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@ include_directories(
|
||||
)
|
||||
|
||||
set(llcommon_SOURCE_FILES
|
||||
aiframetimer.cpp
|
||||
imageids.cpp
|
||||
aiframetimer.cpp
|
||||
imageids.cpp
|
||||
indra_constants.cpp
|
||||
llallocator.cpp
|
||||
llallocator_heap_profile.cpp
|
||||
@@ -24,7 +24,7 @@ set(llcommon_SOURCE_FILES
|
||||
llapr.cpp
|
||||
llaprpool.cpp
|
||||
llassettype.cpp
|
||||
llavatarname.cpp
|
||||
llavatarname.cpp
|
||||
llbase32.cpp
|
||||
llbase64.cpp
|
||||
llcommon.cpp
|
||||
@@ -53,6 +53,7 @@ set(llcommon_SOURCE_FILES
|
||||
llformat.cpp
|
||||
llframetimer.cpp
|
||||
llheartbeat.cpp
|
||||
llinitparam.cpp
|
||||
llinstancetracker.cpp
|
||||
llindraconfigfile.cpp
|
||||
llliveappconfig.cpp
|
||||
@@ -171,6 +172,7 @@ set(llcommon_HEADER_FILES
|
||||
llheartbeat.h
|
||||
llhttpstatuscodes.h
|
||||
llindexedqueue.h
|
||||
llinitparam.h
|
||||
llinstancetracker.h
|
||||
llindraconfigfile.h
|
||||
llkeythrottle.h
|
||||
@@ -212,6 +214,7 @@ set(llcommon_HEADER_FILES
|
||||
llsingleton.h
|
||||
llskiplist.h
|
||||
llskipmap.h
|
||||
llsortedvector.h
|
||||
llstack.h
|
||||
llstacktrace.h
|
||||
llstat.h
|
||||
@@ -226,6 +229,7 @@ set(llcommon_HEADER_FILES
|
||||
llthreadsafequeue.h
|
||||
lltimer.h
|
||||
lltreeiterators.h
|
||||
lltypeinfolookup.h
|
||||
lluri.h
|
||||
lluuid.h
|
||||
lluuidhashmap.h
|
||||
|
||||
@@ -33,6 +33,11 @@
|
||||
#ifndef LL_LINDEN_COMMON_H
|
||||
#define LL_LINDEN_COMMON_H
|
||||
|
||||
// *NOTE: Please keep includes here to a minimum!
|
||||
//
|
||||
// Files included here are included in every library .cpp file and
|
||||
// are not precompiled.
|
||||
|
||||
#include "cwdebug.h"
|
||||
|
||||
#if defined(LL_WINDOWS) && defined(_DEBUG)
|
||||
@@ -55,34 +60,11 @@
|
||||
#include <ctime>
|
||||
#include <iosfwd>
|
||||
|
||||
// Work around Microsoft compiler warnings in STL headers
|
||||
#ifdef LL_WINDOWS
|
||||
#pragma warning (disable : 4702) // unreachable code
|
||||
#pragma warning (disable : 4244) // conversion from time_t to S32
|
||||
#endif // LL_WINDOWS
|
||||
|
||||
// *TODO: Eliminate these, most library .cpp files don't need them.
|
||||
// Add them to llviewerprecompiledheaders.h if necessary.
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#ifdef LL_WINDOWS
|
||||
// Reenable warnings we disabled above
|
||||
#pragma warning (3 : 4702) // unreachable code, we like level 3, not 4
|
||||
// moved msvc warnings to llpreprocessor.h *TODO - delete this comment after merge conflicts are unlikely -brad
|
||||
#endif // LL_WINDOWS
|
||||
|
||||
// Linden only libs in alpha-order other than stdtypes.h
|
||||
// *NOTE: Please keep includes here to a minimum, see above.
|
||||
#include "stdtypes.h"
|
||||
#include "lldefs.h"
|
||||
#include "llerror.h"
|
||||
#include "llextendedstatus.h"
|
||||
// Don't do this, adds 15K lines of header code to every library file.
|
||||
//#include "llfasttimer.h"
|
||||
#include "llfile.h"
|
||||
#include "llformat.h"
|
||||
|
||||
#endif
|
||||
|
||||
@@ -297,20 +297,6 @@ void LLApp::startErrorThread()
|
||||
}
|
||||
}
|
||||
|
||||
void LLApp::stopErrorThread()
|
||||
{
|
||||
LLApp::setStopped(); // Signal error thread that we stopped.
|
||||
int count = 0;
|
||||
while (mThreadErrorp && !mThreadErrorp->isStopped() && ++count < 100)
|
||||
{
|
||||
ms_sleep(10);
|
||||
}
|
||||
if (mThreadErrorp && !mThreadErrorp->isStopped())
|
||||
{
|
||||
llwarns << "Failed to stop Error Thread." << llendl;
|
||||
}
|
||||
}
|
||||
|
||||
void LLApp::setErrorHandler(LLAppErrorHandler handler)
|
||||
{
|
||||
LLApp::sErrorHandler = handler;
|
||||
|
||||
@@ -264,10 +264,6 @@ protected:
|
||||
* @ brief This method is called once as soon as logging is initialized.
|
||||
*/
|
||||
void startErrorThread();
|
||||
/**
|
||||
* @brief This method is called at the end, just prior to deinitializing curl.
|
||||
*/
|
||||
void stopErrorThread();
|
||||
|
||||
private:
|
||||
void setupErrorHandling(); // Do platform-specific error-handling setup (signals, structured exceptions)
|
||||
|
||||
@@ -114,7 +114,7 @@ const int LL_ERR_PRICE_MISMATCH = -23018;
|
||||
: liru_slashpos2 == std::string::npos ? std::string(__FILE__)/*Apparently, we're in / or perhaps the top of the drive, print as is*/\
|
||||
: std::string(__FILE__).substr(1+liru_slashpos2))/*print foo/bar.cpp or perhaps foo\bar.cpp*/
|
||||
|
||||
#define llassert_always(func) do { if (LL_UNLIKELY(!(func))) llerrs << "\nASSERT(" #func ")\nfile:" << liru_assert_strip << " line:" << std::dec << __LINE__ << llendl; } while(0)
|
||||
#define llassert_always(func) if (LL_UNLIKELY(!(func))) llerrs <<"\nASSERT(" #func ")\nfile:"<<liru_assert_strip<<" line:"<<__LINE__ << llendl;
|
||||
|
||||
#ifdef SHOW_ASSERT
|
||||
#define llassert(func) llassert_always(func)
|
||||
|
||||
@@ -194,17 +194,17 @@ void LLErrorThread::run()
|
||||
if (LLApp::isError())
|
||||
{
|
||||
// The app is in an error state, run the application's error handler.
|
||||
Dout(dc::notice, "thread_error - An error has occurred, running error callback!");
|
||||
//llinfos << "thread_error - An error has occurred, running error callback!" << llendl;
|
||||
// Run the error handling callback
|
||||
LLApp::runErrorHandler();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Everything is okay, a clean exit.
|
||||
Dout(dc::notice, "thread_error - Application exited cleanly");
|
||||
//llinfos << "thread_error - Application exited cleanly" << llendl;
|
||||
}
|
||||
|
||||
Dout(dc::notice, "thread_error - Exiting");
|
||||
//llinfos << "thread_error - Exiting" << llendl;
|
||||
LLApp::sErrorThreadRunning = FALSE;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include "llerror.h"
|
||||
#include "lltypeinfolookup.h"
|
||||
|
||||
namespace LLInitParam
|
||||
{
|
||||
@@ -205,7 +206,7 @@ namespace LLInitParam
|
||||
mutable std::string mValueName;
|
||||
};
|
||||
|
||||
class Parser
|
||||
class LL_COMMON_API Parser
|
||||
{
|
||||
LOG_CLASS(Parser);
|
||||
|
||||
@@ -227,9 +228,9 @@ namespace LLInitParam
|
||||
typedef bool (*parser_write_func_t)(Parser& parser, const void*, name_stack_t&);
|
||||
typedef boost::function<void (name_stack_t&, S32, S32, const possible_values_t*)> parser_inspect_func_t;
|
||||
|
||||
typedef std::map<const std::type_info*, parser_read_func_t, CompareTypeID> parser_read_func_map_t;
|
||||
typedef std::map<const std::type_info*, parser_write_func_t, CompareTypeID> parser_write_func_map_t;
|
||||
typedef std::map<const std::type_info*, parser_inspect_func_t, CompareTypeID> parser_inspect_func_map_t;
|
||||
typedef LLTypeInfoLookup<parser_read_func_t> parser_read_func_map_t;
|
||||
typedef LLTypeInfoLookup<parser_write_func_t> parser_write_func_map_t;
|
||||
typedef LLTypeInfoLookup<parser_inspect_func_t> parser_inspect_func_map_t;
|
||||
|
||||
Parser(parser_read_func_map_t& read_map, parser_write_func_map_t& write_map, parser_inspect_func_map_t& inspect_map)
|
||||
: mParseSilently(false),
|
||||
@@ -301,7 +302,7 @@ namespace LLInitParam
|
||||
class Param;
|
||||
|
||||
// various callbacks and constraints associated with an individual param
|
||||
struct ParamDescriptor
|
||||
struct LL_COMMON_API ParamDescriptor
|
||||
{
|
||||
struct UserData
|
||||
{
|
||||
@@ -341,7 +342,7 @@ namespace LLInitParam
|
||||
typedef boost::shared_ptr<ParamDescriptor> ParamDescriptorPtr;
|
||||
|
||||
// each derived Block class keeps a static data structure maintaining offsets to various params
|
||||
class BlockDescriptor
|
||||
class LL_COMMON_API BlockDescriptor
|
||||
{
|
||||
public:
|
||||
BlockDescriptor();
|
||||
@@ -369,7 +370,7 @@ namespace LLInitParam
|
||||
class BaseBlock* mCurrentBlockPtr; // pointer to block currently being constructed
|
||||
};
|
||||
|
||||
class BaseBlock
|
||||
class LL_COMMON_API BaseBlock
|
||||
{
|
||||
public:
|
||||
//TODO: implement in terms of owned_ptr
|
||||
@@ -566,7 +567,7 @@ namespace LLInitParam
|
||||
static bool equals(const BaseBlock::Lazy<T>& a, const BaseBlock::Lazy<T>& b) { return !a.empty() || !b.empty(); }
|
||||
};
|
||||
|
||||
class Param
|
||||
class LL_COMMON_API Param
|
||||
{
|
||||
public:
|
||||
void setProvided(bool is_provided = true)
|
||||
@@ -1253,15 +1254,16 @@ namespace LLInitParam
|
||||
return mValues.back();
|
||||
}
|
||||
|
||||
void add(const value_t& item)
|
||||
self_t& add(const value_t& item)
|
||||
{
|
||||
param_value_t param_value;
|
||||
param_value.setValue(item);
|
||||
mValues.push_back(param_value);
|
||||
setProvided();
|
||||
return *this;
|
||||
}
|
||||
|
||||
void add(const typename name_value_lookup_t::name_t& name)
|
||||
self_t& add(const typename name_value_lookup_t::name_t& name)
|
||||
{
|
||||
value_t value;
|
||||
|
||||
@@ -1271,6 +1273,8 @@ namespace LLInitParam
|
||||
add(value);
|
||||
mValues.back().setValueName(name);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// implicit conversion
|
||||
@@ -1441,13 +1445,14 @@ namespace LLInitParam
|
||||
return mValues.back();
|
||||
}
|
||||
|
||||
void add(const value_t& item)
|
||||
self_t& add(const value_t& item)
|
||||
{
|
||||
mValues.push_back(item);
|
||||
setProvided();
|
||||
return *this;
|
||||
}
|
||||
|
||||
void add(const typename name_value_lookup_t::name_t& name)
|
||||
self_t& add(const typename name_value_lookup_t::name_t& name)
|
||||
{
|
||||
value_t value;
|
||||
|
||||
@@ -1457,6 +1462,7 @@ namespace LLInitParam
|
||||
add(value);
|
||||
mValues.back().setValueName(name);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// implicit conversion
|
||||
@@ -2057,8 +2063,8 @@ namespace LLInitParam
|
||||
|
||||
|
||||
// block param interface
|
||||
bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool new_name);
|
||||
void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const;
|
||||
LL_COMMON_API bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool new_name);
|
||||
LL_COMMON_API void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const;
|
||||
bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const
|
||||
{
|
||||
//TODO: implement LLSD params as schema type Any
|
||||
@@ -251,7 +251,7 @@ bool LLQueuedThread::addRequest(QueuedRequest* req)
|
||||
// MAIN thread
|
||||
bool LLQueuedThread::waitForResult(LLQueuedThread::handle_t handle, bool auto_complete)
|
||||
{
|
||||
llassert (handle != nullHandle());
|
||||
llassert (handle != nullHandle())
|
||||
bool res = false;
|
||||
bool waspaused = isPaused();
|
||||
bool done = false;
|
||||
|
||||
@@ -111,8 +111,6 @@ public:
|
||||
return mPriority > second.mPriority;
|
||||
}
|
||||
|
||||
virtual void deleteRequest(); // Only method to delete a request
|
||||
|
||||
protected:
|
||||
status_t setStatus(status_t newstatus)
|
||||
{
|
||||
@@ -132,6 +130,7 @@ public:
|
||||
|
||||
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
|
||||
virtual void deleteRequest(); // Only method to delete a request
|
||||
|
||||
void setPriority(U32 pri)
|
||||
{
|
||||
|
||||
152
indra/llcommon/llsortedvector.h
Normal file
152
indra/llcommon/llsortedvector.h
Normal file
@@ -0,0 +1,152 @@
|
||||
/**
|
||||
* @file llsortedvector.h
|
||||
* @author Nat Goodspeed
|
||||
* @date 2012-04-08
|
||||
* @brief LLSortedVector class wraps a vector that we maintain in sorted
|
||||
* order so we can perform binary-search lookups.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
||||
* Copyright (c) 2012, Linden Research, Inc.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#if ! defined(LL_LLSORTEDVECTOR_H)
|
||||
#define LL_LLSORTEDVECTOR_H
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
/**
|
||||
* LLSortedVector contains a std::vector<std::pair> that we keep sorted on the
|
||||
* first of the pair. This makes insertion somewhat more expensive than simple
|
||||
* std::vector::push_back(), but allows us to use binary search for lookups.
|
||||
* It's intended for small aggregates where lookup is far more performance-
|
||||
* critical than insertion; in such cases a binary search on a small, sorted
|
||||
* std::vector can be more performant than a std::map lookup.
|
||||
*/
|
||||
template <typename KEY, typename VALUE>
|
||||
class LLSortedVector
|
||||
{
|
||||
public:
|
||||
typedef LLSortedVector<KEY, VALUE> self;
|
||||
typedef KEY key_type;
|
||||
typedef VALUE mapped_type;
|
||||
typedef std::pair<key_type, mapped_type> value_type;
|
||||
typedef std::vector<value_type> PairVector;
|
||||
typedef typename PairVector::iterator iterator;
|
||||
typedef typename PairVector::const_iterator const_iterator;
|
||||
|
||||
/// Empty
|
||||
LLSortedVector() {}
|
||||
|
||||
/// Fixed initial size
|
||||
LLSortedVector(std::size_t size):
|
||||
mVector(size)
|
||||
{}
|
||||
|
||||
/// Bulk load
|
||||
template <typename ITER>
|
||||
LLSortedVector(ITER begin, ITER end):
|
||||
mVector(begin, end)
|
||||
{
|
||||
// Allow caller to dump in a bunch of (pairs convertible to)
|
||||
// value_type if desired, but make sure we sort afterwards.
|
||||
std::sort(mVector.begin(), mVector.end());
|
||||
}
|
||||
|
||||
/// insert(key, value)
|
||||
std::pair<iterator, bool> insert(const key_type& key, const mapped_type& value)
|
||||
{
|
||||
return insert(value_type(key, value));
|
||||
}
|
||||
|
||||
/// insert(value_type)
|
||||
std::pair<iterator, bool> insert(const value_type& pair)
|
||||
{
|
||||
typedef std::pair<iterator, bool> iterbool;
|
||||
iterator found = std::lower_bound(mVector.begin(), mVector.end(), pair,
|
||||
less<value_type>());
|
||||
// have to check for end() before it's even valid to dereference
|
||||
if (found == mVector.end())
|
||||
{
|
||||
std::size_t index(mVector.size());
|
||||
mVector.push_back(pair);
|
||||
// don't forget that push_back() invalidates 'found'
|
||||
return iterbool(mVector.begin() + index, true);
|
||||
}
|
||||
if (found->first == pair.first)
|
||||
{
|
||||
return iterbool(found, false);
|
||||
}
|
||||
// remember that insert() invalidates 'found' -- save index
|
||||
std::size_t index(found - mVector.begin());
|
||||
mVector.insert(found, pair);
|
||||
// okay, convert from index back to iterator
|
||||
return iterbool(mVector.begin() + index, true);
|
||||
}
|
||||
|
||||
iterator begin() { return mVector.begin(); }
|
||||
iterator end() { return mVector.end(); }
|
||||
const_iterator begin() const { return mVector.begin(); }
|
||||
const_iterator end() const { return mVector.end(); }
|
||||
|
||||
bool empty() const { return mVector.empty(); }
|
||||
std::size_t size() const { return mVector.size(); }
|
||||
|
||||
/// find
|
||||
iterator find(const key_type& key)
|
||||
{
|
||||
iterator found = std::lower_bound(mVector.begin(), mVector.end(),
|
||||
value_type(key, mapped_type()),
|
||||
less<value_type>());
|
||||
if (found == mVector.end() || found->first != key)
|
||||
return mVector.end();
|
||||
return found;
|
||||
}
|
||||
|
||||
const_iterator find(const key_type& key) const
|
||||
{
|
||||
return const_cast<self*>(this)->find(key);
|
||||
}
|
||||
|
||||
private:
|
||||
// Define our own 'less' comparator so we can specialize without messing
|
||||
// with std::less.
|
||||
template <typename T>
|
||||
struct less: public std::less<T> {};
|
||||
|
||||
// Specialize 'less' for an LLSortedVector::value_type involving
|
||||
// std::type_info*. This is one of LLSortedVector's foremost use cases. We
|
||||
// specialize 'less' rather than just defining a specific comparator
|
||||
// because LLSortedVector should be usable for other key_types as well.
|
||||
template <typename T>
|
||||
struct less< std::pair<std::type_info*, T> >:
|
||||
public std::binary_function<std::pair<std::type_info*, T>,
|
||||
std::pair<std::type_info*, T>,
|
||||
bool>
|
||||
{
|
||||
bool operator()(const std::pair<std::type_info*, T>& lhs,
|
||||
const std::pair<std::type_info*, T>& rhs) const
|
||||
{
|
||||
return lhs.first->before(*rhs.first);
|
||||
}
|
||||
};
|
||||
|
||||
// Same as above, but with const std::type_info*.
|
||||
template <typename T>
|
||||
struct less< std::pair<const std::type_info*, T> >:
|
||||
public std::binary_function<std::pair<const std::type_info*, T>,
|
||||
std::pair<const std::type_info*, T>,
|
||||
bool>
|
||||
{
|
||||
bool operator()(const std::pair<const std::type_info*, T>& lhs,
|
||||
const std::pair<const std::type_info*, T>& rhs) const
|
||||
{
|
||||
return lhs.first->before(*rhs.first);
|
||||
}
|
||||
};
|
||||
|
||||
PairVector mVector;
|
||||
};
|
||||
|
||||
#endif /* ! defined(LL_LLSORTEDVECTOR_H) */
|
||||
@@ -42,10 +42,10 @@ template <class Object> class LLStrider
|
||||
U8* mBytep;
|
||||
};
|
||||
U32 mSkip;
|
||||
//U32 mTypeSize;
|
||||
|
||||
public:
|
||||
|
||||
LLStrider() { mObjectp = NULL; /*mTypeSize = */mSkip = sizeof(Object); }
|
||||
LLStrider() { mObjectp = NULL; mSkip = sizeof(Object); }
|
||||
~LLStrider() { }
|
||||
|
||||
const LLStrider<Object>& operator = (Object *first) { mObjectp = first; return *this;}
|
||||
@@ -60,9 +60,6 @@ public:
|
||||
return ret;
|
||||
}
|
||||
|
||||
//void setTypeSize (S32 typeBytes){ mTypeSize = (typeBytes ? typeBytes : sizeof(Object)); }
|
||||
|
||||
//bool isStrided() const { return mTypeSize != mSkip; }
|
||||
void skip(const U32 index) { mBytep += mSkip*index;}
|
||||
U32 getSkip() const { return mSkip; }
|
||||
Object* get() { return mObjectp; }
|
||||
@@ -70,72 +67,9 @@ public:
|
||||
Object& operator *() { return *mObjectp; }
|
||||
Object* operator ++(int) { Object* old = mObjectp; mBytep += mSkip; return old; }
|
||||
Object* operator +=(int i) { mBytep += mSkip*i; return mObjectp; }
|
||||
|
||||
Object& operator[](U32 index) { return *(Object*)(mBytep + (mSkip * index)); }
|
||||
/*void assignArray(U8* __restrict source, const size_t elem_size, const size_t elem_count)
|
||||
{
|
||||
llassert_always(sizeof(Object) <= elem_size);
|
||||
|
||||
U8* __restrict dest = mBytep; //refer to dest instead of mBytep to benefit from __restrict hint
|
||||
const U32 bytes = elem_size * elem_count; //total bytes to copy from source to dest
|
||||
|
||||
//stride == sizeof(element) implies entire buffer is unstrided and thus memcpy-able, provided source buffer elements match in size.
|
||||
//Because LLStrider is often passed an LLVector3 even if the reprensentation is LLVector4 in the vertex buffer, mTypeSize is set to
|
||||
//the TRUE vbo datatype size via VertexBufferStrider::get
|
||||
if(!isStrided() && mTypeSize == elem_size)
|
||||
{
|
||||
if(bytes >= sizeof(LLVector4) * 4) //Should be able to pull at least 3 16byte blocks from this. Smaller isn't really beneficial.
|
||||
{
|
||||
U8* __restrict aligned_source = LL_NEXT_ALIGNED_ADDRESS(source);
|
||||
U8* __restrict aligned_dest = LL_NEXT_ALIGNED_ADDRESS(dest);
|
||||
const U32 source_offset = aligned_source - source; //Offset to first aligned location in source buffer.
|
||||
const U32 dest_offset = aligned_dest - dest; //Offset to first aligned location in dest buffer.
|
||||
llassert_always(source_offset < 16);
|
||||
llassert_always(dest_offset < 16);
|
||||
if(source_offset == dest_offset) //delta to aligned location matches between source and destination! _mm_*_ps should be viable.
|
||||
{
|
||||
const U32 end_offset = (bytes - source_offset) % sizeof(LLVector4); //buffers may not neatly end on a 16byte alignment boundary.
|
||||
const U32 aligned_bytes = bytes - source_offset - end_offset; //how many bytes to copy from aligned start to aligned end.
|
||||
|
||||
llassert_always(aligned_bytes > 0);
|
||||
|
||||
if(source_offset) //memcpy up to the aligned location if needed
|
||||
memcpy(dest,source,source_offset);
|
||||
LLVector4a::memcpyNonAliased16((F32*) aligned_dest, (F32*) aligned_source, aligned_bytes);
|
||||
if(end_offset) //memcpy to the very end if needed.
|
||||
memcpy(aligned_dest+aligned_bytes,aligned_source+aligned_bytes,end_offset);
|
||||
}
|
||||
else //buffers non-uniformly offset from aligned location. Using _mm_*u_ps.
|
||||
{
|
||||
U32 end = bytes/sizeof(LLVector4); //sizeof(LLVector4) = 16 bytes = 128 bits
|
||||
|
||||
llassert_always(end > 0);
|
||||
|
||||
__m128* dst = (__m128*) dest;
|
||||
__m128* src = (__m128*) source;
|
||||
|
||||
for (U32 i = 0; i < end; i++) //copy 128bit chunks
|
||||
{
|
||||
__m128 res = _mm_loadu_ps((F32*)&src[i]);
|
||||
_mm_storeu_ps((F32*)&dst[i], res);
|
||||
}
|
||||
end*=16;//Convert to real byte offset
|
||||
if(end < bytes) //just memcopy the rest
|
||||
memcpy(dest+end,source+end,bytes-end);
|
||||
}
|
||||
}
|
||||
else //Too small. just do a simple memcpy.
|
||||
memcpy(dest,source,bytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
for(U32 i=0;i<elem_count;i++)
|
||||
{
|
||||
memcpy(dest,source,sizeof(Object));
|
||||
dest+=mSkip;
|
||||
source+=elem_size;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
};
|
||||
|
||||
#endif // LL_LLSTRIDER_H
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
|
||||
#include "llstring.h"
|
||||
#include "llerror.h"
|
||||
#include "llfasttimer.h"
|
||||
|
||||
#if LL_WINDOWS
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
@@ -604,16 +603,10 @@ std::string utf8str_removeCRLF(const std::string& utf8str)
|
||||
}
|
||||
const char CR = 13;
|
||||
|
||||
S32 i = utf8str.find(CR);
|
||||
if(i == std::string::npos)
|
||||
return utf8str; //Save us from a reserve call.
|
||||
|
||||
std::string out;
|
||||
out.reserve(utf8str.length());
|
||||
const S32 len = (S32)utf8str.length();
|
||||
if(i)
|
||||
out.assign(utf8str,0,i); //Copy previous text to buffer
|
||||
for( ++i; i < len; i++ )
|
||||
for( S32 i = 0; i < len; i++ )
|
||||
{
|
||||
if( utf8str[i] != CR )
|
||||
{
|
||||
|
||||
@@ -35,11 +35,10 @@
|
||||
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <locale>
|
||||
#include <iomanip>
|
||||
#include "llsd.h"
|
||||
#include "llfasttimer.h"
|
||||
|
||||
#if LL_LINUX || LL_SOLARIS
|
||||
#include <wctype.h>
|
||||
@@ -47,6 +46,7 @@
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
#if LL_SOLARIS
|
||||
// stricmp and strnicmp do not exist on Solaris:
|
||||
@@ -246,40 +246,77 @@ private:
|
||||
static std::string sLocale;
|
||||
|
||||
public:
|
||||
typedef typename std::basic_string<T>::size_type size_type;
|
||||
typedef std::basic_string<T> string_type;
|
||||
typedef typename string_type::size_type size_type;
|
||||
|
||||
public:
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Static Utility functions that operate on std::strings
|
||||
|
||||
static const std::basic_string<T> null;
|
||||
static const string_type null;
|
||||
|
||||
typedef std::map<LLFormatMapString, LLFormatMapString> format_map_t;
|
||||
LL_COMMON_API static void getTokens(const std::basic_string<T>& instr, std::vector<std::basic_string<T> >& tokens, const std::basic_string<T>& delims);
|
||||
LL_COMMON_API static void formatNumber(std::basic_string<T>& numStr, std::basic_string<T> decimals);
|
||||
LL_COMMON_API static bool formatDatetime(std::basic_string<T>& replacement, std::basic_string<T> token, std::basic_string<T> param, S32 secFromEpoch);
|
||||
LL_COMMON_API static S32 format(std::basic_string<T>& s, const format_map_t& substitutions);
|
||||
LL_COMMON_API static S32 format(std::basic_string<T>& s, const LLSD& substitutions);
|
||||
LL_COMMON_API static bool simpleReplacement(std::basic_string<T>& replacement, std::basic_string<T> token, const format_map_t& substitutions);
|
||||
LL_COMMON_API static bool simpleReplacement(std::basic_string<T>& replacement, std::basic_string<T> token, const LLSD& substitutions);
|
||||
/// considers any sequence of delims as a single field separator
|
||||
LL_COMMON_API static void getTokens(const string_type& instr,
|
||||
std::vector<string_type >& tokens,
|
||||
const string_type& delims);
|
||||
/// like simple scan overload, but returns scanned vector
|
||||
static std::vector<string_type> getTokens(const string_type& instr,
|
||||
const string_type& delims);
|
||||
/// add support for keep_delims and quotes (either could be empty string)
|
||||
static void getTokens(const string_type& instr,
|
||||
std::vector<string_type>& tokens,
|
||||
const string_type& drop_delims,
|
||||
const string_type& keep_delims,
|
||||
const string_type& quotes=string_type());
|
||||
/// like keep_delims-and-quotes overload, but returns scanned vector
|
||||
static std::vector<string_type> getTokens(const string_type& instr,
|
||||
const string_type& drop_delims,
|
||||
const string_type& keep_delims,
|
||||
const string_type& quotes=string_type());
|
||||
/// add support for escapes (could be empty string)
|
||||
static void getTokens(const string_type& instr,
|
||||
std::vector<string_type>& tokens,
|
||||
const string_type& drop_delims,
|
||||
const string_type& keep_delims,
|
||||
const string_type& quotes,
|
||||
const string_type& escapes);
|
||||
/// like escapes overload, but returns scanned vector
|
||||
static std::vector<string_type> getTokens(const string_type& instr,
|
||||
const string_type& drop_delims,
|
||||
const string_type& keep_delims,
|
||||
const string_type& quotes,
|
||||
const string_type& escapes);
|
||||
|
||||
LL_COMMON_API static void formatNumber(string_type& numStr, string_type decimals);
|
||||
LL_COMMON_API static bool formatDatetime(string_type& replacement, string_type token, string_type param, S32 secFromEpoch);
|
||||
LL_COMMON_API static S32 format(string_type& s, const format_map_t& substitutions);
|
||||
LL_COMMON_API static S32 format(string_type& s, const LLSD& substitutions);
|
||||
LL_COMMON_API static bool simpleReplacement(string_type& replacement, string_type token, const format_map_t& substitutions);
|
||||
LL_COMMON_API static bool simpleReplacement(string_type& replacement, string_type token, const LLSD& substitutions);
|
||||
LL_COMMON_API static void setLocale (std::string inLocale);
|
||||
LL_COMMON_API static std::string getLocale (void);
|
||||
|
||||
static bool isValidIndex(const std::basic_string<T>& string, size_type i)
|
||||
static bool isValidIndex(const string_type& string, size_type i)
|
||||
{
|
||||
return !string.empty() && (0 <= i) && (i <= string.size());
|
||||
}
|
||||
|
||||
static void trimHead(std::basic_string<T>& string);
|
||||
static void trimTail(std::basic_string<T>& string);
|
||||
static void trim(std::basic_string<T>& string) { trimHead(string); trimTail(string); }
|
||||
static void truncate(std::basic_string<T>& string, size_type count);
|
||||
static bool contains(const string_type& string, T c, size_type i=0)
|
||||
{
|
||||
return string.find(c, i) != string_type::npos;
|
||||
}
|
||||
|
||||
static void toUpper(std::basic_string<T>& string);
|
||||
static void toLower(std::basic_string<T>& string);
|
||||
static void trimHead(string_type& string);
|
||||
static void trimTail(string_type& string);
|
||||
static void trim(string_type& string) { trimHead(string); trimTail(string); }
|
||||
static void truncate(string_type& string, size_type count);
|
||||
|
||||
static void toUpper(string_type& string);
|
||||
static void toLower(string_type& string);
|
||||
|
||||
// True if this is the head of s.
|
||||
static BOOL isHead( const std::basic_string<T>& string, const T* s );
|
||||
static BOOL isHead( const string_type& string, const T* s );
|
||||
|
||||
/**
|
||||
* @brief Returns true if string starts with substr
|
||||
@@ -287,8 +324,8 @@ public:
|
||||
* If etither string or substr are empty, this method returns false.
|
||||
*/
|
||||
static bool startsWith(
|
||||
const std::basic_string<T>& string,
|
||||
const std::basic_string<T>& substr);
|
||||
const string_type& string,
|
||||
const string_type& substr);
|
||||
|
||||
/**
|
||||
* @brief Returns true if string ends in substr
|
||||
@@ -296,19 +333,32 @@ public:
|
||||
* If etither string or substr are empty, this method returns false.
|
||||
*/
|
||||
static bool endsWith(
|
||||
const std::basic_string<T>& string,
|
||||
const std::basic_string<T>& substr);
|
||||
const string_type& string,
|
||||
const string_type& substr);
|
||||
|
||||
static void addCRLF(std::basic_string<T>& string);
|
||||
static void removeCRLF(std::basic_string<T>& string);
|
||||
static void addCRLF(string_type& string);
|
||||
static void removeCRLF(string_type& string);
|
||||
|
||||
static void replaceTabsWithSpaces( std::basic_string<T>& string, size_type spaces_per_tab );
|
||||
static void replaceNonstandardASCII( std::basic_string<T>& string, T replacement );
|
||||
static void replaceChar( std::basic_string<T>& string, T target, T replacement );
|
||||
static void replaceString( std::basic_string<T>& string, std::basic_string<T> target, std::basic_string<T> replacement );
|
||||
static void replaceTabsWithSpaces( string_type& string, size_type spaces_per_tab );
|
||||
static void replaceNonstandardASCII( string_type& string, T replacement );
|
||||
static void replaceChar( string_type& string, T target, T replacement );
|
||||
static void replaceString( string_type& string, string_type target, string_type replacement );
|
||||
|
||||
static BOOL containsNonprintable(const std::basic_string<T>& string);
|
||||
static void stripNonprintable(std::basic_string<T>& string);
|
||||
static BOOL containsNonprintable(const string_type& string);
|
||||
static void stripNonprintable(string_type& string);
|
||||
|
||||
/**
|
||||
* Double-quote an argument string if needed, unless it's already
|
||||
* double-quoted. Decide whether it's needed based on the presence of any
|
||||
* character in @a triggers (default space or double-quote). If we quote
|
||||
* it, escape any embedded double-quote with the @a escape string (default
|
||||
* backslash).
|
||||
*
|
||||
* Passing triggers="" means always quote, unless it's already double-quoted.
|
||||
*/
|
||||
static string_type quote(const string_type& str,
|
||||
const string_type& triggers=" \"",
|
||||
const string_type& escape="\\");
|
||||
|
||||
/**
|
||||
* @brief Unsafe way to make ascii characters. You should probably
|
||||
@@ -317,18 +367,18 @@ public:
|
||||
* The 2 and 4 byte std::string probably work, so LLWStringUtil::_makeASCII
|
||||
* should work.
|
||||
*/
|
||||
static void _makeASCII(std::basic_string<T>& string);
|
||||
static void _makeASCII(string_type& string);
|
||||
|
||||
// Conversion to other data types
|
||||
static BOOL convertToBOOL(const std::basic_string<T>& string, BOOL& value);
|
||||
static BOOL convertToU8(const std::basic_string<T>& string, U8& value);
|
||||
static BOOL convertToS8(const std::basic_string<T>& string, S8& value);
|
||||
static BOOL convertToS16(const std::basic_string<T>& string, S16& value);
|
||||
static BOOL convertToU16(const std::basic_string<T>& string, U16& value);
|
||||
static BOOL convertToU32(const std::basic_string<T>& string, U32& value);
|
||||
static BOOL convertToS32(const std::basic_string<T>& string, S32& value);
|
||||
static BOOL convertToF32(const std::basic_string<T>& string, F32& value);
|
||||
static BOOL convertToF64(const std::basic_string<T>& string, F64& value);
|
||||
static BOOL convertToBOOL(const string_type& string, BOOL& value);
|
||||
static BOOL convertToU8(const string_type& string, U8& value);
|
||||
static BOOL convertToS8(const string_type& string, S8& value);
|
||||
static BOOL convertToS16(const string_type& string, S16& value);
|
||||
static BOOL convertToU16(const string_type& string, U16& value);
|
||||
static BOOL convertToU32(const string_type& string, U32& value);
|
||||
static BOOL convertToS32(const string_type& string, S32& value);
|
||||
static BOOL convertToF32(const string_type& string, F32& value);
|
||||
static BOOL convertToF64(const string_type& string, F64& value);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Utility functions for working with char*'s and strings
|
||||
@@ -336,24 +386,24 @@ public:
|
||||
// Like strcmp but also handles empty strings. Uses
|
||||
// current locale.
|
||||
static S32 compareStrings(const T* lhs, const T* rhs);
|
||||
static S32 compareStrings(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs);
|
||||
static S32 compareStrings(const string_type& lhs, const string_type& rhs);
|
||||
|
||||
// case insensitive version of above. Uses current locale on
|
||||
// Win32, and falls back to a non-locale aware comparison on
|
||||
// Linux.
|
||||
static S32 compareInsensitive(const T* lhs, const T* rhs);
|
||||
static S32 compareInsensitive(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs);
|
||||
static S32 compareInsensitive(const string_type& lhs, const string_type& rhs);
|
||||
|
||||
// Case sensitive comparison with good handling of numbers. Does not use current locale.
|
||||
// a.k.a. strdictcmp()
|
||||
static S32 compareDict(const std::basic_string<T>& a, const std::basic_string<T>& b);
|
||||
static S32 compareDict(const string_type& a, const string_type& b);
|
||||
|
||||
// Case *in*sensitive comparison with good handling of numbers. Does not use current locale.
|
||||
// a.k.a. strdictcmp()
|
||||
static S32 compareDictInsensitive(const std::basic_string<T>& a, const std::basic_string<T>& b);
|
||||
static S32 compareDictInsensitive(const string_type& a, const string_type& b);
|
||||
|
||||
// Puts compareDict() in a form appropriate for LL container classes to use for sorting.
|
||||
static BOOL precedesDict( const std::basic_string<T>& a, const std::basic_string<T>& b );
|
||||
static BOOL precedesDict( const string_type& a, const string_type& b );
|
||||
|
||||
// A replacement for strncpy.
|
||||
// If the dst buffer is dst_size bytes long or more, ensures that dst is null terminated and holds
|
||||
@@ -361,7 +411,7 @@ public:
|
||||
static void copy(T* dst, const T* src, size_type dst_size);
|
||||
|
||||
// Copies src into dst at a given offset.
|
||||
static void copyInto(std::basic_string<T>& dst, const std::basic_string<T>& src, size_type offset);
|
||||
static void copyInto(string_type& dst, const string_type& src, size_type offset);
|
||||
|
||||
static bool isPartOfWord(T c) { return (c == (T)'_') || LLStringOps::isAlnum(c); }
|
||||
|
||||
@@ -371,7 +421,7 @@ public:
|
||||
#endif
|
||||
|
||||
private:
|
||||
LL_COMMON_API static size_type getSubstitution(const std::basic_string<T>& instr, size_type& start, std::vector<std::basic_string<T> >& tokens);
|
||||
LL_COMMON_API static size_type getSubstitution(const string_type& instr, size_type& start, std::vector<string_type >& tokens);
|
||||
};
|
||||
|
||||
template<class T> const std::basic_string<T> LLStringUtilBase<T>::null;
|
||||
@@ -649,6 +699,321 @@ namespace LLStringFn
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
// static
|
||||
template <class T>
|
||||
std::vector<typename LLStringUtilBase<T>::string_type>
|
||||
LLStringUtilBase<T>::getTokens(const string_type& instr, const string_type& delims)
|
||||
{
|
||||
std::vector<string_type> tokens;
|
||||
getTokens(instr, tokens, delims);
|
||||
return tokens;
|
||||
}
|
||||
|
||||
// static
|
||||
template <class T>
|
||||
std::vector<typename LLStringUtilBase<T>::string_type>
|
||||
LLStringUtilBase<T>::getTokens(const string_type& instr,
|
||||
const string_type& drop_delims,
|
||||
const string_type& keep_delims,
|
||||
const string_type& quotes)
|
||||
{
|
||||
std::vector<string_type> tokens;
|
||||
getTokens(instr, tokens, drop_delims, keep_delims, quotes);
|
||||
return tokens;
|
||||
}
|
||||
|
||||
// static
|
||||
template <class T>
|
||||
std::vector<typename LLStringUtilBase<T>::string_type>
|
||||
LLStringUtilBase<T>::getTokens(const string_type& instr,
|
||||
const string_type& drop_delims,
|
||||
const string_type& keep_delims,
|
||||
const string_type& quotes,
|
||||
const string_type& escapes)
|
||||
{
|
||||
std::vector<string_type> tokens;
|
||||
getTokens(instr, tokens, drop_delims, keep_delims, quotes, escapes);
|
||||
return tokens;
|
||||
}
|
||||
|
||||
namespace LLStringUtilBaseImpl
|
||||
{
|
||||
|
||||
/**
|
||||
* Input string scanner helper for getTokens(), or really any other
|
||||
* character-parsing routine that may have to deal with escape characters.
|
||||
* This implementation defines the concept (also an interface, should you
|
||||
* choose to implement the concept by subclassing) and provides trivial
|
||||
* implementations for a string @em without escape processing.
|
||||
*/
|
||||
template <class T>
|
||||
struct InString
|
||||
{
|
||||
typedef std::basic_string<T> string_type;
|
||||
typedef typename string_type::const_iterator const_iterator;
|
||||
|
||||
InString(const_iterator b, const_iterator e):
|
||||
mIter(b),
|
||||
mEnd(e)
|
||||
{}
|
||||
virtual ~InString() {}
|
||||
|
||||
bool done() const { return mIter == mEnd; }
|
||||
/// Is the current character (*mIter) escaped? This implementation can
|
||||
/// answer trivially because it doesn't support escapes.
|
||||
virtual bool escaped() const { return false; }
|
||||
/// Obtain the current character and advance @c mIter.
|
||||
virtual T next() { return *mIter++; }
|
||||
/// Does the current character match specified character?
|
||||
virtual bool is(T ch) const { return (! done()) && *mIter == ch; }
|
||||
/// Is the current character any one of the specified characters?
|
||||
virtual bool oneof(const string_type& delims) const
|
||||
{
|
||||
return (! done()) && LLStringUtilBase<T>::contains(delims, *mIter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan forward from @from until either @a delim or end. This is primarily
|
||||
* useful for processing quoted substrings.
|
||||
*
|
||||
* If we do see @a delim, append everything from @from until (excluding)
|
||||
* @a delim to @a into, advance @c mIter to skip @a delim, and return @c
|
||||
* true.
|
||||
*
|
||||
* If we do not see @a delim, do not alter @a into or @c mIter and return
|
||||
* @c false. Do not pass GO, do not collect $200.
|
||||
*
|
||||
* @note The @c false case described above implements normal getTokens()
|
||||
* treatment of an unmatched open quote: treat the quote character as if
|
||||
* escaped, that is, simply collect it as part of the current token. Other
|
||||
* plausible behaviors directly affect the way getTokens() deals with an
|
||||
* unmatched quote: e.g. throwing an exception to treat it as an error, or
|
||||
* assuming a close quote beyond end of string (in which case return @c
|
||||
* true).
|
||||
*/
|
||||
virtual bool collect_until(string_type& into, const_iterator from, T delim)
|
||||
{
|
||||
const_iterator found = std::find(from, mEnd, delim);
|
||||
// If we didn't find delim, change nothing, just tell caller.
|
||||
if (found == mEnd)
|
||||
return false;
|
||||
// Found delim! Append everything between from and found.
|
||||
into.append(from, found);
|
||||
// advance past delim in input
|
||||
mIter = found + 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
const_iterator mIter, mEnd;
|
||||
};
|
||||
|
||||
/// InString subclass that handles escape characters
|
||||
template <class T>
|
||||
class InEscString: public InString<T>
|
||||
{
|
||||
public:
|
||||
typedef InString<T> super;
|
||||
typedef typename super::string_type string_type;
|
||||
typedef typename super::const_iterator const_iterator;
|
||||
using super::done;
|
||||
using super::mIter;
|
||||
using super::mEnd;
|
||||
|
||||
InEscString(const_iterator b, const_iterator e, const string_type& escapes):
|
||||
super(b, e),
|
||||
mEscapes(escapes)
|
||||
{
|
||||
// Even though we've already initialized 'mIter' via our base-class
|
||||
// constructor, set it again to check for initial escape char.
|
||||
setiter(b);
|
||||
}
|
||||
|
||||
/// This implementation uses the answer cached by setiter().
|
||||
virtual bool escaped() const { return mIsEsc; }
|
||||
virtual T next()
|
||||
{
|
||||
// If we're looking at the escape character of an escape sequence,
|
||||
// skip that character. This is the one time we can modify 'mIter'
|
||||
// without using setiter: for this one case we DO NOT CARE if the
|
||||
// escaped character is itself an escape.
|
||||
if (mIsEsc)
|
||||
++mIter;
|
||||
// If we were looking at an escape character, this is the escaped
|
||||
// character; otherwise it's just the next character.
|
||||
T result(*mIter);
|
||||
// Advance mIter, checking for escape sequence.
|
||||
setiter(mIter + 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual bool is(T ch) const
|
||||
{
|
||||
// Like base-class is(), except that an escaped character matches
|
||||
// nothing.
|
||||
return (! done()) && (! mIsEsc) && *mIter == ch;
|
||||
}
|
||||
|
||||
virtual bool oneof(const string_type& delims) const
|
||||
{
|
||||
// Like base-class oneof(), except that an escaped character matches
|
||||
// nothing.
|
||||
return (! done()) && (! mIsEsc) && LLStringUtilBase<T>::contains(delims, *mIter);
|
||||
}
|
||||
|
||||
virtual bool collect_until(string_type& into, const_iterator from, T delim)
|
||||
{
|
||||
// Deal with escapes in the characters we collect; that is, an escaped
|
||||
// character must become just that character without the preceding
|
||||
// escape. Collect characters in a separate string rather than
|
||||
// directly appending to 'into' in case we do not find delim, in which
|
||||
// case we're supposed to leave 'into' unmodified.
|
||||
string_type collected;
|
||||
// For scanning purposes, we're going to work directly with 'mIter'.
|
||||
// Save its current value in case we fail to see delim.
|
||||
const_iterator save_iter(mIter);
|
||||
// Okay, set 'mIter', checking for escape.
|
||||
setiter(from);
|
||||
while (! done())
|
||||
{
|
||||
// If we see an unescaped delim, stop and report success.
|
||||
if ((! mIsEsc) && *mIter == delim)
|
||||
{
|
||||
// Append collected chars to 'into'.
|
||||
into.append(collected);
|
||||
// Don't forget to advance 'mIter' past delim.
|
||||
setiter(mIter + 1);
|
||||
return true;
|
||||
}
|
||||
// We're not at end, and either we're not looking at delim or it's
|
||||
// escaped. Collect this character and keep going.
|
||||
collected.push_back(next());
|
||||
}
|
||||
// Here we hit 'mEnd' without ever seeing delim. Restore mIter and tell
|
||||
// caller.
|
||||
setiter(save_iter);
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
void setiter(const_iterator i)
|
||||
{
|
||||
mIter = i;
|
||||
|
||||
// Every time we change 'mIter', set 'mIsEsc' to be able to repetitively
|
||||
// answer escaped() without having to rescan 'mEscapes'. mIsEsc caches
|
||||
// contains(mEscapes, *mIter).
|
||||
|
||||
// We're looking at an escaped char if we're not already at end (that
|
||||
// is, *mIter is even meaningful); if *mIter is in fact one of the
|
||||
// specified escape characters; and if there's one more character
|
||||
// following it. That is, if an escape character is the very last
|
||||
// character of the input string, it loses its special meaning.
|
||||
mIsEsc = (! done()) &&
|
||||
LLStringUtilBase<T>::contains(mEscapes, *mIter) &&
|
||||
(mIter+1) != mEnd;
|
||||
}
|
||||
|
||||
const string_type mEscapes;
|
||||
bool mIsEsc;
|
||||
};
|
||||
|
||||
/// getTokens() implementation based on InString concept
|
||||
template <typename INSTRING, typename string_type>
|
||||
void getTokens(INSTRING& instr, std::vector<string_type>& tokens,
|
||||
const string_type& drop_delims, const string_type& keep_delims,
|
||||
const string_type& quotes)
|
||||
{
|
||||
// There are times when we want to match either drop_delims or
|
||||
// keep_delims. Concatenate them up front to speed things up.
|
||||
string_type all_delims(drop_delims + keep_delims);
|
||||
// no tokens yet
|
||||
tokens.clear();
|
||||
|
||||
// try for another token
|
||||
while (! instr.done())
|
||||
{
|
||||
// scan past any drop_delims
|
||||
while (instr.oneof(drop_delims))
|
||||
{
|
||||
// skip this drop_delim
|
||||
instr.next();
|
||||
// but if that was the end of the string, done
|
||||
if (instr.done())
|
||||
return;
|
||||
}
|
||||
// found the start of another token: make a slot for it
|
||||
tokens.push_back(string_type());
|
||||
if (instr.oneof(keep_delims))
|
||||
{
|
||||
// *iter is a keep_delim, a token of exactly 1 character. Append
|
||||
// that character to the new token and proceed.
|
||||
tokens.back().push_back(instr.next());
|
||||
continue;
|
||||
}
|
||||
// Here we have a non-delimiter token, which might consist of a mix of
|
||||
// quoted and unquoted parts. Use bash rules for quoting: you can
|
||||
// embed a quoted substring in the midst of an unquoted token (e.g.
|
||||
// ~/"sub dir"/myfile.txt); you can ram two quoted substrings together
|
||||
// to make a single token (e.g. 'He said, "'"Don't."'"'). We diverge
|
||||
// from bash in that bash considers an unmatched quote an error. Our
|
||||
// param signature doesn't allow for errors, so just pretend it's not
|
||||
// a quote and embed it.
|
||||
// At this level, keep scanning until we hit the next delimiter of
|
||||
// either type (drop_delims or keep_delims).
|
||||
while (! instr.oneof(all_delims))
|
||||
{
|
||||
// If we're looking at an open quote, search forward for
|
||||
// a close quote, collecting characters along the way.
|
||||
if (instr.oneof(quotes) &&
|
||||
instr.collect_until(tokens.back(), instr.mIter+1, *instr.mIter))
|
||||
{
|
||||
// collect_until is cleverly designed to do exactly what we
|
||||
// need here. No further action needed if it returns true.
|
||||
}
|
||||
else
|
||||
{
|
||||
// Either *iter isn't a quote, or there's no matching close
|
||||
// quote: in other words, just an ordinary char. Append it to
|
||||
// current token.
|
||||
tokens.back().push_back(instr.next());
|
||||
}
|
||||
// having scanned that segment of this token, if we've reached the
|
||||
// end of the string, we're done
|
||||
if (instr.done())
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace LLStringUtilBaseImpl
|
||||
|
||||
// static
|
||||
template <class T>
|
||||
void LLStringUtilBase<T>::getTokens(const string_type& string, std::vector<string_type>& tokens,
|
||||
const string_type& drop_delims, const string_type& keep_delims,
|
||||
const string_type& quotes)
|
||||
{
|
||||
// Because this overload doesn't support escapes, use simple InString to
|
||||
// manage input range.
|
||||
LLStringUtilBaseImpl::InString<T> instring(string.begin(), string.end());
|
||||
LLStringUtilBaseImpl::getTokens(instring, tokens, drop_delims, keep_delims, quotes);
|
||||
}
|
||||
|
||||
// static
|
||||
template <class T>
|
||||
void LLStringUtilBase<T>::getTokens(const string_type& string, std::vector<string_type>& tokens,
|
||||
const string_type& drop_delims, const string_type& keep_delims,
|
||||
const string_type& quotes, const string_type& escapes)
|
||||
{
|
||||
// This overload must deal with escapes. Delegate that to InEscString
|
||||
// (unless there ARE no escapes).
|
||||
boost::scoped_ptr< LLStringUtilBaseImpl::InString<T> > instrp;
|
||||
if (escapes.empty())
|
||||
instrp.reset(new LLStringUtilBaseImpl::InString<T>(string.begin(), string.end()));
|
||||
else
|
||||
instrp.reset(new LLStringUtilBaseImpl::InEscString<T>(string.begin(), string.end(), escapes));
|
||||
LLStringUtilBaseImpl::getTokens(*instrp, tokens, drop_delims, keep_delims, quotes);
|
||||
}
|
||||
|
||||
// static
|
||||
template<class T>
|
||||
@@ -678,7 +1043,7 @@ S32 LLStringUtilBase<T>::compareStrings(const T* lhs, const T* rhs)
|
||||
|
||||
//static
|
||||
template<class T>
|
||||
S32 LLStringUtilBase<T>::compareStrings(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs)
|
||||
S32 LLStringUtilBase<T>::compareStrings(const string_type& lhs, const string_type& rhs)
|
||||
{
|
||||
return LLStringOps::collate(lhs.c_str(), rhs.c_str());
|
||||
}
|
||||
@@ -704,8 +1069,8 @@ S32 LLStringUtilBase<T>::compareInsensitive(const T* lhs, const T* rhs )
|
||||
}
|
||||
else
|
||||
{
|
||||
std::basic_string<T> lhs_string(lhs);
|
||||
std::basic_string<T> rhs_string(rhs);
|
||||
string_type lhs_string(lhs);
|
||||
string_type rhs_string(rhs);
|
||||
LLStringUtilBase<T>::toUpper(lhs_string);
|
||||
LLStringUtilBase<T>::toUpper(rhs_string);
|
||||
result = LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str());
|
||||
@@ -715,10 +1080,10 @@ S32 LLStringUtilBase<T>::compareInsensitive(const T* lhs, const T* rhs )
|
||||
|
||||
//static
|
||||
template<class T>
|
||||
S32 LLStringUtilBase<T>::compareInsensitive(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs)
|
||||
S32 LLStringUtilBase<T>::compareInsensitive(const string_type& lhs, const string_type& rhs)
|
||||
{
|
||||
std::basic_string<T> lhs_string(lhs);
|
||||
std::basic_string<T> rhs_string(rhs);
|
||||
string_type lhs_string(lhs);
|
||||
string_type rhs_string(rhs);
|
||||
LLStringUtilBase<T>::toUpper(lhs_string);
|
||||
LLStringUtilBase<T>::toUpper(rhs_string);
|
||||
return LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str());
|
||||
@@ -729,7 +1094,7 @@ S32 LLStringUtilBase<T>::compareInsensitive(const std::basic_string<T>& lhs, con
|
||||
|
||||
//static
|
||||
template<class T>
|
||||
S32 LLStringUtilBase<T>::compareDict(const std::basic_string<T>& astr, const std::basic_string<T>& bstr)
|
||||
S32 LLStringUtilBase<T>::compareDict(const string_type& astr, const string_type& bstr)
|
||||
{
|
||||
const T* a = astr.c_str();
|
||||
const T* b = bstr.c_str();
|
||||
@@ -770,7 +1135,7 @@ S32 LLStringUtilBase<T>::compareDict(const std::basic_string<T>& astr, const std
|
||||
|
||||
// static
|
||||
template<class T>
|
||||
S32 LLStringUtilBase<T>::compareDictInsensitive(const std::basic_string<T>& astr, const std::basic_string<T>& bstr)
|
||||
S32 LLStringUtilBase<T>::compareDictInsensitive(const string_type& astr, const string_type& bstr)
|
||||
{
|
||||
const T* a = astr.c_str();
|
||||
const T* b = bstr.c_str();
|
||||
@@ -805,7 +1170,7 @@ S32 LLStringUtilBase<T>::compareDictInsensitive(const std::basic_string<T>& astr
|
||||
// Puts compareDict() in a form appropriate for LL container classes to use for sorting.
|
||||
// static
|
||||
template<class T>
|
||||
BOOL LLStringUtilBase<T>::precedesDict( const std::basic_string<T>& a, const std::basic_string<T>& b )
|
||||
BOOL LLStringUtilBase<T>::precedesDict( const string_type& a, const string_type& b )
|
||||
{
|
||||
if( a.size() && b.size() )
|
||||
{
|
||||
@@ -819,7 +1184,7 @@ BOOL LLStringUtilBase<T>::precedesDict( const std::basic_string<T>& a, const std
|
||||
|
||||
//static
|
||||
template<class T>
|
||||
void LLStringUtilBase<T>::toUpper(std::basic_string<T>& string)
|
||||
void LLStringUtilBase<T>::toUpper(string_type& string)
|
||||
{
|
||||
if( !string.empty() )
|
||||
{
|
||||
@@ -833,7 +1198,7 @@ void LLStringUtilBase<T>::toUpper(std::basic_string<T>& string)
|
||||
|
||||
//static
|
||||
template<class T>
|
||||
void LLStringUtilBase<T>::toLower(std::basic_string<T>& string)
|
||||
void LLStringUtilBase<T>::toLower(string_type& string)
|
||||
{
|
||||
if( !string.empty() )
|
||||
{
|
||||
@@ -847,7 +1212,7 @@ void LLStringUtilBase<T>::toLower(std::basic_string<T>& string)
|
||||
|
||||
//static
|
||||
template<class T>
|
||||
void LLStringUtilBase<T>::trimHead(std::basic_string<T>& string)
|
||||
void LLStringUtilBase<T>::trimHead(string_type& string)
|
||||
{
|
||||
if( !string.empty() )
|
||||
{
|
||||
@@ -862,7 +1227,7 @@ void LLStringUtilBase<T>::trimHead(std::basic_string<T>& string)
|
||||
|
||||
//static
|
||||
template<class T>
|
||||
void LLStringUtilBase<T>::trimTail(std::basic_string<T>& string)
|
||||
void LLStringUtilBase<T>::trimTail(string_type& string)
|
||||
{
|
||||
if( string.size() )
|
||||
{
|
||||
@@ -881,7 +1246,7 @@ void LLStringUtilBase<T>::trimTail(std::basic_string<T>& string)
|
||||
// Replace line feeds with carriage return-line feed pairs.
|
||||
//static
|
||||
template<class T>
|
||||
void LLStringUtilBase<T>::addCRLF(std::basic_string<T>& string)
|
||||
void LLStringUtilBase<T>::addCRLF(string_type& string)
|
||||
{
|
||||
const T LF = 10;
|
||||
const T CR = 13;
|
||||
@@ -923,7 +1288,7 @@ void LLStringUtilBase<T>::addCRLF(std::basic_string<T>& string)
|
||||
// Remove all carriage returns
|
||||
//static
|
||||
template<class T>
|
||||
void LLStringUtilBase<T>::removeCRLF(std::basic_string<T>& string)
|
||||
void LLStringUtilBase<T>::removeCRLF(string_type& string)
|
||||
{
|
||||
const T CR = 13;
|
||||
|
||||
@@ -944,10 +1309,10 @@ void LLStringUtilBase<T>::removeCRLF(std::basic_string<T>& string)
|
||||
|
||||
//static
|
||||
template<class T>
|
||||
void LLStringUtilBase<T>::replaceChar( std::basic_string<T>& string, T target, T replacement )
|
||||
void LLStringUtilBase<T>::replaceChar( string_type& string, T target, T replacement )
|
||||
{
|
||||
size_type found_pos = 0;
|
||||
while( (found_pos = string.find(target, found_pos)) != std::basic_string<T>::npos )
|
||||
while( (found_pos = string.find(target, found_pos)) != string_type::npos )
|
||||
{
|
||||
string[found_pos] = replacement;
|
||||
found_pos++; // avoid infinite defeat if target == replacement
|
||||
@@ -956,10 +1321,10 @@ void LLStringUtilBase<T>::replaceChar( std::basic_string<T>& string, T target, T
|
||||
|
||||
//static
|
||||
template<class T>
|
||||
void LLStringUtilBase<T>::replaceString( std::basic_string<T>& string, std::basic_string<T> target, std::basic_string<T> replacement )
|
||||
void LLStringUtilBase<T>::replaceString( string_type& string, string_type target, string_type replacement )
|
||||
{
|
||||
size_type found_pos = 0;
|
||||
while( (found_pos = string.find(target, found_pos)) != std::basic_string<T>::npos )
|
||||
while( (found_pos = string.find(target, found_pos)) != string_type::npos )
|
||||
{
|
||||
string.replace( found_pos, target.length(), replacement );
|
||||
found_pos += replacement.length(); // avoid infinite defeat if replacement contains target
|
||||
@@ -968,7 +1333,7 @@ void LLStringUtilBase<T>::replaceString( std::basic_string<T>& string, std::basi
|
||||
|
||||
//static
|
||||
template<class T>
|
||||
void LLStringUtilBase<T>::replaceNonstandardASCII( std::basic_string<T>& string, T replacement )
|
||||
void LLStringUtilBase<T>::replaceNonstandardASCII( string_type& string, T replacement )
|
||||
{
|
||||
const char LF = 10;
|
||||
const S8 MIN = 32;
|
||||
@@ -988,12 +1353,12 @@ void LLStringUtilBase<T>::replaceNonstandardASCII( std::basic_string<T>& string,
|
||||
|
||||
//static
|
||||
template<class T>
|
||||
void LLStringUtilBase<T>::replaceTabsWithSpaces( std::basic_string<T>& str, size_type spaces_per_tab )
|
||||
void LLStringUtilBase<T>::replaceTabsWithSpaces( string_type& str, size_type spaces_per_tab )
|
||||
{
|
||||
const T TAB = '\t';
|
||||
const T SPACE = ' ';
|
||||
|
||||
std::basic_string<T> out_str;
|
||||
string_type out_str;
|
||||
// Replace tabs with spaces
|
||||
for (size_type i = 0; i < str.length(); i++)
|
||||
{
|
||||
@@ -1012,7 +1377,7 @@ void LLStringUtilBase<T>::replaceTabsWithSpaces( std::basic_string<T>& str, size
|
||||
|
||||
//static
|
||||
template<class T>
|
||||
BOOL LLStringUtilBase<T>::containsNonprintable(const std::basic_string<T>& string)
|
||||
BOOL LLStringUtilBase<T>::containsNonprintable(const string_type& string)
|
||||
{
|
||||
const char MIN = 32;
|
||||
BOOL rv = FALSE;
|
||||
@@ -1029,7 +1394,7 @@ BOOL LLStringUtilBase<T>::containsNonprintable(const std::basic_string<T>& strin
|
||||
|
||||
//static
|
||||
template<class T>
|
||||
void LLStringUtilBase<T>::stripNonprintable(std::basic_string<T>& string)
|
||||
void LLStringUtilBase<T>::stripNonprintable(string_type& string)
|
||||
{
|
||||
const char MIN = 32;
|
||||
size_type j = 0;
|
||||
@@ -1060,8 +1425,43 @@ void LLStringUtilBase<T>::stripNonprintable(std::basic_string<T>& string)
|
||||
delete []c_string;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
std::basic_string<T> LLStringUtilBase<T>::quote(const string_type& str,
|
||||
const string_type& triggers,
|
||||
const string_type& escape)
|
||||
{
|
||||
size_type len(str.length());
|
||||
// If the string is already quoted, assume user knows what s/he's doing.
|
||||
if (len >= 2 && str[0] == '"' && str[len-1] == '"')
|
||||
{
|
||||
return str;
|
||||
}
|
||||
|
||||
// Not already quoted: do we need to? triggers.empty() is a special case
|
||||
// meaning "always quote."
|
||||
if ((! triggers.empty()) && str.find_first_of(triggers) == string_type::npos)
|
||||
{
|
||||
// no trigger characters, don't bother quoting
|
||||
return str;
|
||||
}
|
||||
|
||||
// For whatever reason, we must quote this string.
|
||||
string_type result;
|
||||
result.push_back('"');
|
||||
for (typename string_type::const_iterator ci(str.begin()), cend(str.end()); ci != cend; ++ci)
|
||||
{
|
||||
if (*ci == '"')
|
||||
{
|
||||
result.append(escape);
|
||||
}
|
||||
result.push_back(*ci);
|
||||
}
|
||||
result.push_back('"');
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void LLStringUtilBase<T>::_makeASCII(std::basic_string<T>& string)
|
||||
void LLStringUtilBase<T>::_makeASCII(string_type& string)
|
||||
{
|
||||
// Replace non-ASCII chars with LL_UNKNOWN_CHAR
|
||||
for (size_type i = 0; i < string.length(); i++)
|
||||
@@ -1091,7 +1491,7 @@ void LLStringUtilBase<T>::copy( T* dst, const T* src, size_type dst_size )
|
||||
|
||||
// static
|
||||
template<class T>
|
||||
void LLStringUtilBase<T>::copyInto(std::basic_string<T>& dst, const std::basic_string<T>& src, size_type offset)
|
||||
void LLStringUtilBase<T>::copyInto(string_type& dst, const string_type& src, size_type offset)
|
||||
{
|
||||
if ( offset == dst.length() )
|
||||
{
|
||||
@@ -1101,7 +1501,7 @@ void LLStringUtilBase<T>::copyInto(std::basic_string<T>& dst, const std::basic_s
|
||||
}
|
||||
else
|
||||
{
|
||||
std::basic_string<T> tail = dst.substr(offset);
|
||||
string_type tail = dst.substr(offset);
|
||||
|
||||
dst = dst.substr(0, offset);
|
||||
dst += src;
|
||||
@@ -1112,7 +1512,7 @@ void LLStringUtilBase<T>::copyInto(std::basic_string<T>& dst, const std::basic_s
|
||||
// True if this is the head of s.
|
||||
//static
|
||||
template<class T>
|
||||
BOOL LLStringUtilBase<T>::isHead( const std::basic_string<T>& string, const T* s )
|
||||
BOOL LLStringUtilBase<T>::isHead( const string_type& string, const T* s )
|
||||
{
|
||||
if( string.empty() )
|
||||
{
|
||||
@@ -1128,8 +1528,8 @@ BOOL LLStringUtilBase<T>::isHead( const std::basic_string<T>& string, const T* s
|
||||
// static
|
||||
template<class T>
|
||||
bool LLStringUtilBase<T>::startsWith(
|
||||
const std::basic_string<T>& string,
|
||||
const std::basic_string<T>& substr)
|
||||
const string_type& string,
|
||||
const string_type& substr)
|
||||
{
|
||||
if(string.empty() || (substr.empty())) return false;
|
||||
if(0 == string.find(substr)) return true;
|
||||
@@ -1139,8 +1539,8 @@ bool LLStringUtilBase<T>::startsWith(
|
||||
// static
|
||||
template<class T>
|
||||
bool LLStringUtilBase<T>::endsWith(
|
||||
const std::basic_string<T>& string,
|
||||
const std::basic_string<T>& substr)
|
||||
const string_type& string,
|
||||
const string_type& substr)
|
||||
{
|
||||
if(string.empty() || (substr.empty())) return false;
|
||||
std::string::size_type idx = string.rfind(substr);
|
||||
@@ -1150,14 +1550,14 @@ bool LLStringUtilBase<T>::endsWith(
|
||||
|
||||
|
||||
template<class T>
|
||||
BOOL LLStringUtilBase<T>::convertToBOOL(const std::basic_string<T>& string, BOOL& value)
|
||||
BOOL LLStringUtilBase<T>::convertToBOOL(const string_type& string, BOOL& value)
|
||||
{
|
||||
if( string.empty() )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
std::basic_string<T> temp( string );
|
||||
string_type temp( string );
|
||||
trim(temp);
|
||||
if(
|
||||
(temp == "1") ||
|
||||
@@ -1187,7 +1587,7 @@ BOOL LLStringUtilBase<T>::convertToBOOL(const std::basic_string<T>& string, BOOL
|
||||
}
|
||||
|
||||
template<class T>
|
||||
BOOL LLStringUtilBase<T>::convertToU8(const std::basic_string<T>& string, U8& value)
|
||||
BOOL LLStringUtilBase<T>::convertToU8(const string_type& string, U8& value)
|
||||
{
|
||||
S32 value32 = 0;
|
||||
BOOL success = convertToS32(string, value32);
|
||||
@@ -1200,7 +1600,7 @@ BOOL LLStringUtilBase<T>::convertToU8(const std::basic_string<T>& string, U8& va
|
||||
}
|
||||
|
||||
template<class T>
|
||||
BOOL LLStringUtilBase<T>::convertToS8(const std::basic_string<T>& string, S8& value)
|
||||
BOOL LLStringUtilBase<T>::convertToS8(const string_type& string, S8& value)
|
||||
{
|
||||
S32 value32 = 0;
|
||||
BOOL success = convertToS32(string, value32);
|
||||
@@ -1213,7 +1613,7 @@ BOOL LLStringUtilBase<T>::convertToS8(const std::basic_string<T>& string, S8& va
|
||||
}
|
||||
|
||||
template<class T>
|
||||
BOOL LLStringUtilBase<T>::convertToS16(const std::basic_string<T>& string, S16& value)
|
||||
BOOL LLStringUtilBase<T>::convertToS16(const string_type& string, S16& value)
|
||||
{
|
||||
S32 value32 = 0;
|
||||
BOOL success = convertToS32(string, value32);
|
||||
@@ -1226,7 +1626,7 @@ BOOL LLStringUtilBase<T>::convertToS16(const std::basic_string<T>& string, S16&
|
||||
}
|
||||
|
||||
template<class T>
|
||||
BOOL LLStringUtilBase<T>::convertToU16(const std::basic_string<T>& string, U16& value)
|
||||
BOOL LLStringUtilBase<T>::convertToU16(const string_type& string, U16& value)
|
||||
{
|
||||
S32 value32 = 0;
|
||||
BOOL success = convertToS32(string, value32);
|
||||
@@ -1239,17 +1639,17 @@ BOOL LLStringUtilBase<T>::convertToU16(const std::basic_string<T>& string, U16&
|
||||
}
|
||||
|
||||
template<class T>
|
||||
BOOL LLStringUtilBase<T>::convertToU32(const std::basic_string<T>& string, U32& value)
|
||||
BOOL LLStringUtilBase<T>::convertToU32(const string_type& string, U32& value)
|
||||
{
|
||||
if( string.empty() )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
std::basic_string<T> temp( string );
|
||||
string_type temp( string );
|
||||
trim(temp);
|
||||
U32 v;
|
||||
std::basic_istringstream<T> i_stream((std::basic_string<T>)temp);
|
||||
std::basic_istringstream<T> i_stream((string_type)temp);
|
||||
if(i_stream >> v)
|
||||
{
|
||||
value = v;
|
||||
@@ -1259,17 +1659,17 @@ BOOL LLStringUtilBase<T>::convertToU32(const std::basic_string<T>& string, U32&
|
||||
}
|
||||
|
||||
template<class T>
|
||||
BOOL LLStringUtilBase<T>::convertToS32(const std::basic_string<T>& string, S32& value)
|
||||
BOOL LLStringUtilBase<T>::convertToS32(const string_type& string, S32& value)
|
||||
{
|
||||
if( string.empty() )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
std::basic_string<T> temp( string );
|
||||
string_type temp( string );
|
||||
trim(temp);
|
||||
S32 v;
|
||||
std::basic_istringstream<T> i_stream((std::basic_string<T>)temp);
|
||||
std::basic_istringstream<T> i_stream((string_type)temp);
|
||||
if(i_stream >> v)
|
||||
{
|
||||
//TODO: figure out overflow and underflow reporting here
|
||||
@@ -1286,7 +1686,7 @@ BOOL LLStringUtilBase<T>::convertToS32(const std::basic_string<T>& string, S32&
|
||||
}
|
||||
|
||||
template<class T>
|
||||
BOOL LLStringUtilBase<T>::convertToF32(const std::basic_string<T>& string, F32& value)
|
||||
BOOL LLStringUtilBase<T>::convertToF32(const string_type& string, F32& value)
|
||||
{
|
||||
F64 value64 = 0.0;
|
||||
BOOL success = convertToF64(string, value64);
|
||||
@@ -1299,17 +1699,17 @@ BOOL LLStringUtilBase<T>::convertToF32(const std::basic_string<T>& string, F32&
|
||||
}
|
||||
|
||||
template<class T>
|
||||
BOOL LLStringUtilBase<T>::convertToF64(const std::basic_string<T>& string, F64& value)
|
||||
BOOL LLStringUtilBase<T>::convertToF64(const string_type& string, F64& value)
|
||||
{
|
||||
if( string.empty() )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
std::basic_string<T> temp( string );
|
||||
string_type temp( string );
|
||||
trim(temp);
|
||||
F64 v;
|
||||
std::basic_istringstream<T> i_stream((std::basic_string<T>)temp);
|
||||
std::basic_istringstream<T> i_stream((string_type)temp);
|
||||
if(i_stream >> v)
|
||||
{
|
||||
//TODO: figure out overflow and underflow reporting here
|
||||
@@ -1326,7 +1726,7 @@ BOOL LLStringUtilBase<T>::convertToF64(const std::basic_string<T>& string, F64&
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void LLStringUtilBase<T>::truncate(std::basic_string<T>& string, size_type count)
|
||||
void LLStringUtilBase<T>::truncate(string_type& string, size_type count)
|
||||
{
|
||||
size_type cur_size = string.size();
|
||||
string.resize(count < cur_size ? count : cur_size);
|
||||
|
||||
@@ -310,27 +310,15 @@ void LLThread::wakeLocked()
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
apr_os_thread_t LLThread::sMainThreadID;
|
||||
|
||||
void LLThread::set_main_thread_id(void)
|
||||
{
|
||||
sMainThreadID = apr_os_thread_current();
|
||||
}
|
||||
#ifdef SHOW_ASSERT
|
||||
// This allows the use of llassert(is_main_thread()) to assure the current thread is the main thread.
|
||||
static apr_os_thread_t main_thread_id;
|
||||
LL_COMMON_API bool is_main_thread(void) { return apr_os_thread_equal(main_thread_id, apr_os_thread_current()); }
|
||||
#endif
|
||||
|
||||
// The thread private handle to access the LLThreadLocalData instance.
|
||||
apr_threadkey_t* LLThreadLocalData::sThreadLocalDataKey;
|
||||
|
||||
LLThreadLocalData::LLThreadLocalData(char const* name) : mCurlMultiHandle(NULL), mCurlErrorBuffer(NULL), mName(name)
|
||||
{
|
||||
}
|
||||
|
||||
LLThreadLocalData::~LLThreadLocalData()
|
||||
{
|
||||
delete mCurlMultiHandle;
|
||||
delete [] mCurlErrorBuffer;
|
||||
}
|
||||
|
||||
//static
|
||||
void LLThreadLocalData::init(void)
|
||||
{
|
||||
@@ -348,8 +336,10 @@ void LLThreadLocalData::init(void)
|
||||
// Create the thread-local data for the main thread (this function is called by the main thread).
|
||||
LLThreadLocalData::create(NULL);
|
||||
|
||||
#ifdef SHOW_ASSERT
|
||||
// This function is called by the main thread.
|
||||
LLThread::set_main_thread_id();
|
||||
main_thread_id = apr_os_thread_current();
|
||||
#endif
|
||||
}
|
||||
|
||||
// This is called once for every thread when the thread is destructed.
|
||||
@@ -362,7 +352,7 @@ void LLThreadLocalData::destroy(void* thread_local_data)
|
||||
//static
|
||||
void LLThreadLocalData::create(LLThread* threadp)
|
||||
{
|
||||
LLThreadLocalData* new_tld = new LLThreadLocalData(threadp ? threadp->mName.c_str() : "main thread");
|
||||
LLThreadLocalData* new_tld = new LLThreadLocalData;
|
||||
if (threadp)
|
||||
{
|
||||
threadp->mThreadLocalData = new_tld;
|
||||
|
||||
@@ -40,6 +40,13 @@
|
||||
#include "llaprpool.h"
|
||||
#include "llatomic.h"
|
||||
|
||||
#ifdef SHOW_ASSERT
|
||||
extern LL_COMMON_API bool is_main_thread(void);
|
||||
#define ASSERT_SINGLE_THREAD do { static apr_os_thread_t first_thread_id = apr_os_thread_current(); llassert(apr_os_thread_equal(first_thread_id, apr_os_thread_current())); } while(0)
|
||||
#else
|
||||
#define ASSERT_SINGLE_THREAD do { } while(0)
|
||||
#endif
|
||||
|
||||
class LLThread;
|
||||
class LLMutex;
|
||||
class LLCondition;
|
||||
@@ -50,12 +57,6 @@ class LLCondition;
|
||||
#define ll_thread_local __thread
|
||||
#endif
|
||||
|
||||
class LL_COMMON_API LLThreadLocalDataMember
|
||||
{
|
||||
public:
|
||||
virtual ~LLThreadLocalDataMember() { };
|
||||
};
|
||||
|
||||
class LL_COMMON_API LLThreadLocalData
|
||||
{
|
||||
private:
|
||||
@@ -65,24 +66,16 @@ public:
|
||||
// Thread-local memory pool.
|
||||
LLAPRRootPool mRootPool;
|
||||
LLVolatileAPRPool mVolatileAPRPool;
|
||||
LLThreadLocalDataMember* mCurlMultiHandle; // Initialized by AICurlMultiHandle::getInstance
|
||||
char* mCurlErrorBuffer; // NULL, or pointing to a buffer used by libcurl.
|
||||
std::string mName; // "main thread", or a copy of LLThread::mName.
|
||||
|
||||
static void init(void);
|
||||
static void destroy(void* thread_local_data);
|
||||
static void create(LLThread* pthread);
|
||||
static LLThreadLocalData& tldata(void);
|
||||
|
||||
private:
|
||||
LLThreadLocalData(char const* name);
|
||||
~LLThreadLocalData();
|
||||
};
|
||||
|
||||
class LL_COMMON_API LLThread
|
||||
{
|
||||
private:
|
||||
static apr_os_thread_t sMainThreadID;
|
||||
static U32 sIDIter;
|
||||
static LLAtomicS32 sCount;
|
||||
static LLAtomicS32 sRunning;
|
||||
@@ -106,7 +99,6 @@ public:
|
||||
static S32 getCount() { return sCount; }
|
||||
static S32 getRunning() { return sRunning; }
|
||||
static void yield(); // Static because it can be called by the main thread, which doesn't have an LLThread data structure.
|
||||
static bool is_main_thread(void) { return apr_os_thread_equal(LLThread::sMainThreadID, apr_os_thread_current()); }
|
||||
|
||||
public:
|
||||
// PAUSE / RESUME functionality. See source code for important usage notes.
|
||||
@@ -130,9 +122,6 @@ public:
|
||||
// Return thread-local data for the current thread.
|
||||
static LLThreadLocalData& tldata(void) { return LLThreadLocalData::tldata(); }
|
||||
|
||||
// Called once, from LLThreadLocalData::init().
|
||||
static void set_main_thread_id(void);
|
||||
|
||||
U32 getID() const { return mID; }
|
||||
|
||||
private:
|
||||
@@ -176,13 +165,6 @@ protected:
|
||||
// mRunCondition->unlock();
|
||||
};
|
||||
|
||||
#ifdef SHOW_ASSERT
|
||||
LL_COMMON_API inline bool is_main_thread(void) { return LLThread::is_main_thread(); }
|
||||
#define ASSERT_SINGLE_THREAD do { static apr_os_thread_t first_thread_id = apr_os_thread_current(); llassert(apr_os_thread_equal(first_thread_id, apr_os_thread_current())); } while(0)
|
||||
#else
|
||||
#define ASSERT_SINGLE_THREAD do { } while(0)
|
||||
#endif
|
||||
|
||||
//============================================================================
|
||||
|
||||
#define MUTEX_DEBUG (LL_DEBUG || LL_RELEASE_WITH_DEBUG_INFO)
|
||||
@@ -224,11 +206,6 @@ protected:
|
||||
apr_thread_mutex_t* mAPRMutexp;
|
||||
mutable U32 mCount;
|
||||
mutable U32 mLockingThread;
|
||||
|
||||
private:
|
||||
// Disallow copy construction and assignment.
|
||||
LLMutexBase(LLMutexBase const&);
|
||||
LLMutexBase& operator=(LLMutexBase const&);
|
||||
};
|
||||
|
||||
class LL_COMMON_API LLMutex : public LLMutexBase
|
||||
@@ -248,6 +225,10 @@ public:
|
||||
|
||||
protected:
|
||||
LLAPRPool mPool;
|
||||
private:
|
||||
// Disable copy construction, as si teh bomb!!! -SG
|
||||
LLMutex(const LLMutex&);
|
||||
LLMutex& operator=(const LLMutex&);
|
||||
};
|
||||
|
||||
#if APR_HAS_THREADS
|
||||
|
||||
110
indra/llcommon/lltypeinfolookup.h
Normal file
110
indra/llcommon/lltypeinfolookup.h
Normal file
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
* @file lltypeinfolookup.h
|
||||
* @author Nat Goodspeed
|
||||
* @date 2012-04-08
|
||||
* @brief Template data structure like std::map<std::type_info*, T>
|
||||
*
|
||||
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
||||
* Copyright (c) 2012, Linden Research, Inc.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#if ! defined(LL_LLTYPEINFOLOOKUP_H)
|
||||
#define LL_LLTYPEINFOLOOKUP_H
|
||||
|
||||
#include "llsortedvector.h"
|
||||
#include <typeinfo>
|
||||
|
||||
/**
|
||||
* LLTypeInfoLookup is specifically designed for use cases for which you might
|
||||
* consider std::map<std::type_info*, VALUE>. We have several such data
|
||||
* structures in the viewer. The trouble with them is that at least on Linux,
|
||||
* you can't rely on always getting the same std::type_info* for a given type:
|
||||
* different load modules will produce different std::type_info*.
|
||||
* LLTypeInfoLookup contains a workaround to address this issue.
|
||||
*
|
||||
* Specifically, when we don't find the passed std::type_info*,
|
||||
* LLTypeInfoLookup performs a linear search over registered entries to
|
||||
* compare name() strings. Presuming that this succeeds, we cache the new
|
||||
* (previously unrecognized) std::type_info* to speed future lookups.
|
||||
*
|
||||
* This worst-case fallback search (linear search with string comparison)
|
||||
* should only happen the first time we look up a given type from a particular
|
||||
* load module other than the one from which we initially registered types.
|
||||
* (However, a lookup which wouldn't succeed anyway will always have
|
||||
* worst-case performance.) This class is probably best used with less than a
|
||||
* few dozen different types.
|
||||
*/
|
||||
template <typename VALUE>
|
||||
class LLTypeInfoLookup
|
||||
{
|
||||
public:
|
||||
typedef LLTypeInfoLookup<VALUE> self;
|
||||
typedef LLSortedVector<const std::type_info*, VALUE> vector_type;
|
||||
typedef typename vector_type::key_type key_type;
|
||||
typedef typename vector_type::mapped_type mapped_type;
|
||||
typedef typename vector_type::value_type value_type;
|
||||
typedef typename vector_type::iterator iterator;
|
||||
typedef typename vector_type::const_iterator const_iterator;
|
||||
|
||||
LLTypeInfoLookup() {}
|
||||
|
||||
iterator begin() { return mVector.begin(); }
|
||||
iterator end() { return mVector.end(); }
|
||||
const_iterator begin() const { return mVector.begin(); }
|
||||
const_iterator end() const { return mVector.end(); }
|
||||
bool empty() const { return mVector.empty(); }
|
||||
std::size_t size() const { return mVector.size(); }
|
||||
|
||||
std::pair<iterator, bool> insert(const std::type_info* key, const VALUE& value)
|
||||
{
|
||||
return insert(value_type(key, value));
|
||||
}
|
||||
|
||||
std::pair<iterator, bool> insert(const value_type& pair)
|
||||
{
|
||||
return mVector.insert(pair);
|
||||
}
|
||||
|
||||
// const find() forwards to non-const find(): this can alter mVector!
|
||||
const_iterator find(const std::type_info* key) const
|
||||
{
|
||||
return const_cast<self*>(this)->find(key);
|
||||
}
|
||||
|
||||
// non-const find() caches previously-unknown type_info* to speed future
|
||||
// lookups.
|
||||
iterator find(const std::type_info* key)
|
||||
{
|
||||
iterator found = mVector.find(key);
|
||||
if (found != mVector.end())
|
||||
{
|
||||
// If LLSortedVector::find() found, great, we're done.
|
||||
return found;
|
||||
}
|
||||
// Here we didn't find the passed type_info*. On Linux, though, even
|
||||
// for the same type, typeid(sametype) produces a different type_info*
|
||||
// when used in different load modules. So the fact that we didn't
|
||||
// find the type_info* we seek doesn't mean this type isn't
|
||||
// registered. Scan for matching name() string.
|
||||
for (typename vector_type::iterator ti(mVector.begin()), tend(mVector.end());
|
||||
ti != tend; ++ti)
|
||||
{
|
||||
if (std::string(ti->first->name()) == key->name())
|
||||
{
|
||||
// This unrecognized 'key' is for the same type as ti->first.
|
||||
// To speed future lookups, insert a new entry that lets us
|
||||
// look up ti->second using this same 'key'.
|
||||
return insert(key, ti->second).first;
|
||||
}
|
||||
}
|
||||
// We simply have never seen a type with this type_info* from any load
|
||||
// module.
|
||||
return mVector.end();
|
||||
}
|
||||
|
||||
private:
|
||||
vector_type mVector;
|
||||
};
|
||||
|
||||
#endif /* ! defined(LL_LLTYPEINFOLOOKUP_H) */
|
||||
@@ -460,7 +460,7 @@ typedef struct _ASTAT_
|
||||
}ASTAT, * PASTAT;
|
||||
|
||||
// static
|
||||
S32 LLUUID::getNodeID(unsigned char * node_id)
|
||||
S32 LLUUID::getNodeID(unsigned char *node_id)
|
||||
{
|
||||
ASTAT Adapter;
|
||||
NCB Ncb;
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include "stdtypes.h"
|
||||
#include "llpreprocessor.h"
|
||||
|
||||
|
||||
@@ -371,9 +371,6 @@ void LLCrashLogger::updateApplication(const std::string& message)
|
||||
|
||||
bool LLCrashLogger::init()
|
||||
{
|
||||
// Initialize curl
|
||||
AICurlInterface::initCurl();
|
||||
|
||||
// We assume that all the logs we're looking for reside on the current drive
|
||||
gDirUtilp->initAppDirs("SecondLife");
|
||||
|
||||
|
||||
@@ -35,8 +35,8 @@
|
||||
|
||||
#include "lluuid.h"
|
||||
#include "llstring.h"
|
||||
#include "llmemtype.h"
|
||||
#include "llthread.h"
|
||||
#include "llmemtype.h"
|
||||
#include "aithreadsafe.h"
|
||||
|
||||
const S32 MIN_IMAGE_MIP = 2; // 4x4, only used for expand/contract power of 2
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#ifndef LL_LLPNGWRAPPER_H
|
||||
#define LL_LLPNGWRAPPER_H
|
||||
|
||||
#include "png.h"
|
||||
#include "libpng15/png.h"
|
||||
#include "llimage.h"
|
||||
|
||||
class LLPngWrapper
|
||||
|
||||
@@ -1700,6 +1700,6 @@ LLPointer<LLInventoryCategory> ll_create_category_from_sd(const LLSD& sd_cat)
|
||||
LLAssetType::lookup(sd_cat[INV_ASSET_TYPE_LABEL].asString()));
|
||||
rv->setPreferredType(
|
||||
LLFolderType::lookup(
|
||||
sd_cat[INV_PREFERRED_TYPE_LABEL].asString()));
|
||||
sd_cat[INV_PREFERRED_TYPE_LABEL].asString()));
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ DEFAULT_ASSET_FOR_INV_TYPE[LLAssetType::AT_COUNT] =
|
||||
LLInventoryType::IT_NONE, // 46 AT_NONE
|
||||
LLInventoryType::IT_NONE, // 47 AT_NONE
|
||||
LLInventoryType::IT_NONE, // 48 AT_NONE
|
||||
LLInventoryType::IT_MESH // 49 AT_MESH
|
||||
LLInventoryType::IT_MESH // 49 AT_MESH
|
||||
};
|
||||
|
||||
// static
|
||||
|
||||
@@ -51,7 +51,7 @@ const S32 PARCEL_UNIT_AREA = 16;
|
||||
const F32 PARCEL_HEIGHT = 50.f;
|
||||
|
||||
//Height above ground which parcel boundries exist for explicitly banned avatars
|
||||
const F32 BAN_HEIGHT = 768.f;
|
||||
const F32 BAN_HEIGHT = 5000.f;
|
||||
|
||||
// Maximum number of entries in an access list
|
||||
const S32 PARCEL_MAX_ACCESS_LIST = 300;
|
||||
@@ -260,7 +260,7 @@ public:
|
||||
void setMediaURLResetTimer(F32 time);
|
||||
virtual void setLocalID(S32 local_id);
|
||||
|
||||
// blow away all the extra crap lurking in parcels, including urls, access lists, etc
|
||||
// blow away all the extra stuff lurking in parcels, including urls, access lists, etc
|
||||
void clearParcel();
|
||||
|
||||
// This value is not persisted out to the parcel file, it is only
|
||||
@@ -686,6 +686,7 @@ public:
|
||||
std::map<LLUUID,LLAccessEntry> mBanList;
|
||||
std::map<LLUUID,LLAccessEntry> mTempBanList;
|
||||
std::map<LLUUID,LLAccessEntry> mTempAccessList;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -32,9 +32,6 @@
|
||||
#ifndef LL_LLPERMISSIONSFLAGS_H
|
||||
#define LL_LLPERMISSIONSFLAGS_H
|
||||
|
||||
// llpermissionsflags.h
|
||||
// Copyright 2002, Linden Research, Inc.
|
||||
//
|
||||
// Flags for various permissions bits.
|
||||
// Shared between viewer and simulator.
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
#include "lltransactiontypes.h"
|
||||
|
||||
#include "../newview/hippogridmanager.h"
|
||||
|
||||
|
||||
const U8 TRANSACTION_FLAGS_NONE = 0;
|
||||
const U8 TRANSACTION_FLAG_SOURCE_GROUP = 1;
|
||||
const U8 TRANSACTION_FLAG_DEST_GROUP = 2;
|
||||
|
||||
@@ -74,6 +74,7 @@ const S32 TRANS_CLASSIFIED_RENEW = 2005;
|
||||
// automatically end up in the list below :-(
|
||||
// So make sure you check the transaction_description table
|
||||
const S32 TRANS_RECURRING_GENERIC = 2100;
|
||||
|
||||
// Codes 3000-3999 reserved for inventory transactions
|
||||
const S32 TRANS_GIVE_INVENTORY = 3000;
|
||||
|
||||
|
||||
@@ -29,8 +29,7 @@ set(llmessage_SOURCE_FILES
|
||||
llchainio.cpp
|
||||
llcircuit.cpp
|
||||
llclassifiedflags.cpp
|
||||
aicurl.cpp
|
||||
aicurlthread.cpp
|
||||
llcurl.cpp
|
||||
lldatapacker.cpp
|
||||
lldispatcher.cpp
|
||||
llfiltersd2xmlrpc.cpp
|
||||
@@ -67,6 +66,8 @@ set(llmessage_SOURCE_FILES
|
||||
llsdmessage.cpp
|
||||
llsdmessagebuilder.cpp
|
||||
llsdmessagereader.cpp
|
||||
llsdrpcclient.cpp
|
||||
llsdrpcserver.cpp
|
||||
llservicebuilder.cpp
|
||||
llservice.cpp
|
||||
llstoredmessage.cpp
|
||||
@@ -116,9 +117,6 @@ set(llmessage_HEADER_FILES
|
||||
llcircuit.h
|
||||
llclassifiedflags.h
|
||||
llcurl.h
|
||||
aicurl.h
|
||||
aicurlprivate.h
|
||||
aicurlthread.h
|
||||
lldatapacker.h
|
||||
lldbstrings.h
|
||||
lldispatcher.h
|
||||
@@ -166,6 +164,8 @@ set(llmessage_HEADER_FILES
|
||||
llsdmessage.h
|
||||
llsdmessagebuilder.h
|
||||
llsdmessagereader.h
|
||||
llsdrpcclient.h
|
||||
llsdrpcserver.h
|
||||
llservice.h
|
||||
llservicebuilder.h
|
||||
llstoredmessage.h
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,322 +0,0 @@
|
||||
/**
|
||||
* @file aicurl.h
|
||||
* @brief Thread safe wrapper for libcurl.
|
||||
*
|
||||
* Copyright (c) 2012, Aleric Inglewood.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution.
|
||||
*
|
||||
* CHANGELOG
|
||||
* and additional copyright holders.
|
||||
*
|
||||
* 17/03/2012
|
||||
* Initial version, written by Aleric Inglewood @ SL
|
||||
*/
|
||||
|
||||
#ifndef AICURL_H
|
||||
#define AICURL_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <stdexcept>
|
||||
#include <boost/intrusive_ptr.hpp>
|
||||
#include <boost/utility.hpp>
|
||||
#include <curl/curl.h> // CURL, CURLM, CURLMcode, CURLoption, curl_*_callback
|
||||
|
||||
// Make sure we don't use this option: it is not thread-safe.
|
||||
#undef CURLOPT_DNS_USE_GLOBAL_CACHE
|
||||
|
||||
#include "stdtypes.h" // U32
|
||||
#include "lliopipe.h" // LLIOPipe::buffer_ptr_t
|
||||
#include "llatomic.h" // LLAtomicU32
|
||||
#include "aithreadsafe.h"
|
||||
|
||||
class LLSD;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Exceptions.
|
||||
//
|
||||
|
||||
// A general curl exception.
|
||||
//
|
||||
class AICurlError : public std::runtime_error {
|
||||
public:
|
||||
AICurlError(std::string const& message) : std::runtime_error(message) { }
|
||||
};
|
||||
|
||||
class AICurlNoEasyHandle : public AICurlError {
|
||||
public:
|
||||
AICurlNoEasyHandle(std::string const& message) : AICurlError(message) { }
|
||||
};
|
||||
|
||||
class AICurlNoMultiHandle : public AICurlError {
|
||||
public:
|
||||
AICurlNoMultiHandle(std::string const& message) : AICurlError(message) { }
|
||||
};
|
||||
|
||||
// End Exceptions.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Things defined in this namespace are called from elsewhere in the viewer code.
|
||||
namespace AICurlInterface {
|
||||
|
||||
// Output parameter of AICurlPrivate::CurlEasyRequest::getResult.
|
||||
// Only used by LLXMLRPCTransaction::Impl.
|
||||
struct TransferInfo {
|
||||
TransferInfo() : mSizeDownload(0.0), mTotalTime(0.0), mSpeedDownload(0.0) { }
|
||||
F64 mSizeDownload;
|
||||
F64 mTotalTime;
|
||||
F64 mSpeedDownload;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Global functions.
|
||||
|
||||
// Called once at start of application (from newview/llappviewer.cpp by main thread (before threads are created)),
|
||||
// with main purpose to initialize curl.
|
||||
void initCurl(void (*)(void) = NULL);
|
||||
|
||||
// Called once at start of application (from LLAppViewer::initThreads), starts AICurlThread.
|
||||
void startCurlThread(void);
|
||||
|
||||
// Called once at end of application (from newview/llappviewer.cpp by main thread),
|
||||
// with purpose to stop curl threads, free curl resources and deinitialize curl.
|
||||
void cleanupCurl(void);
|
||||
|
||||
// Called from indra/llmessage/llurlrequest.cpp to print debug output regarding
|
||||
// an error code returned by EasyRequest::getResult.
|
||||
// Just returns curl_easy_strerror(errorcode).
|
||||
std::string strerror(CURLcode errorcode);
|
||||
|
||||
// Called from indra/newview/llfloaterabout.cpp for the About floater, and
|
||||
// from newview/llappviewer.cpp in behalf of debug output.
|
||||
// Just returns curl_version().
|
||||
std::string getVersionString(void);
|
||||
|
||||
// Called from newview/llappviewer.cpp (and llcrashlogger/llcrashlogger.cpp) to set
|
||||
// the Certificate Authority file used to verify HTTPS certs.
|
||||
void setCAFile(std::string const& file);
|
||||
|
||||
// Not called from anywhere.
|
||||
// Can be used to set the path to the Certificate Authority file.
|
||||
void setCAPath(std::string const& file);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Global classes.
|
||||
|
||||
// Responder - base class for Request::get* and Request::post API.
|
||||
//
|
||||
// The life cycle of classes derived from this class is as follows:
|
||||
// They are allocated with new on the line where get(), getByteRange() or post() is called,
|
||||
// and the pointer to the allocated object is then put in a reference counting ResponderPtr.
|
||||
// This ResponderPtr is passed to CurlResponderBuffer::prepRequest which stores it in its
|
||||
// member mResponder. Hence, the life time of a Responder is never longer than its
|
||||
// associated CurlResponderBuffer, however, if everything works correctly, then normally a
|
||||
// responder is deleted in CurlResponderBuffer::removed_from_multi_handle by setting
|
||||
// mReponder to NULL.
|
||||
//
|
||||
// Note that the lifetime of CurlResponderBuffer is (a bit) shorter than the associated
|
||||
// CurlEasyRequest (because of the order of base classes of ThreadSafeBufferedCurlEasyRequest)
|
||||
// and the callbacks, as set by prepRequest, only use those two.
|
||||
// A callback locks the CurlEasyRequest before actually making the callback, and the
|
||||
// destruction of CurlResponderBuffer also first locks the CurlEasyRequest, and then revokes
|
||||
// the callbacks. This assures that a Responder is never used when the objects it uses are
|
||||
// destructed. Also, if any of those are destructed then the Responder is automatically
|
||||
// destructed too.
|
||||
//
|
||||
class Responder {
|
||||
protected:
|
||||
Responder(void);
|
||||
virtual ~Responder();
|
||||
|
||||
private:
|
||||
// Associated URL, used for debug output.
|
||||
std::string mURL;
|
||||
|
||||
public:
|
||||
// Called to set the URL of the current request for this Responder,
|
||||
// used only when printing debug output regarding activity of the Responder.
|
||||
void setURL(std::string const& url);
|
||||
|
||||
public:
|
||||
// Called from LLHTTPClientURLAdaptor::complete():
|
||||
|
||||
// Derived classes can override this to get the HTML header that was received, when the message is completed.
|
||||
// The default does nothing.
|
||||
virtual void completedHeader(U32 status, std::string const& reason, LLSD const& content);
|
||||
|
||||
// Derived classes can override this to get the raw data of the body of the HTML message that was received.
|
||||
// The default is to interpret the content as LLSD and call completed().
|
||||
virtual void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, LLIOPipe::buffer_ptr_t const& buffer);
|
||||
|
||||
// Called from LLHTTPClient request calls, if an error occurs even before we can call one of the above.
|
||||
// It calls completed() with a fake status U32_MAX, as that is what some derived clients expect (bad design).
|
||||
// This means that if a derived class overrides completedRaw() it now STILL has to override completed() to catch this error.
|
||||
void fatalError(std::string const& reason);
|
||||
|
||||
// A derived class should return true if curl should follow redirections.
|
||||
// The default is not to follow redirections.
|
||||
virtual bool followRedir(void) { return false; }
|
||||
|
||||
protected:
|
||||
// ... or, derived classes can override this to get the LLSD content when the message is completed.
|
||||
// The default is to call result() (or errorWithContent() in case of a HTML status indicating an error).
|
||||
virtual void completed(U32 status, std::string const& reason, LLSD const& content);
|
||||
|
||||
// ... or, derived classes can override this to received the content of a body upon success.
|
||||
// The default does nothing.
|
||||
virtual void result(LLSD const& content);
|
||||
|
||||
// Derived classes can override this to get informed when a bad HTML status code is received.
|
||||
// The default calls error().
|
||||
virtual void errorWithContent(U32 status, std::string const& reason, LLSD const& content);
|
||||
|
||||
// ... or, derived classes can override this to get informed when a bad HTML statis code is received.
|
||||
// The default prints the error to llinfos.
|
||||
virtual void error(U32 status, std::string const& reason);
|
||||
|
||||
public:
|
||||
// Called from LLSDMessage::ResponderAdapter::listener.
|
||||
// LLSDMessage::ResponderAdapter is a hack, showing among others by fact that these functions need to be public.
|
||||
|
||||
void pubErrorWithContent(U32 status, std::string const& reason, LLSD const& content) { errorWithContent(status, reason, content); }
|
||||
void pubResult(LLSD const& content) { result(content); }
|
||||
|
||||
private:
|
||||
// Used by ResponderPtr. Object is deleted when reference count reaches zero.
|
||||
LLAtomicU32 mReferenceCount;
|
||||
|
||||
friend void intrusive_ptr_add_ref(Responder* p); // Called by boost::intrusive_ptr when a new copy of a boost::intrusive_ptr<Responder> is made.
|
||||
friend void intrusive_ptr_release(Responder* p); // Called by boost::intrusive_ptr when a boost::intrusive_ptr<Responder> is destroyed.
|
||||
// This function must delete the Responder object when the reference count reaches zero.
|
||||
};
|
||||
|
||||
// A Responder is passed around as ResponderPtr, which causes it to automatically
|
||||
// destruct when there are no pointers left pointing to it.
|
||||
typedef boost::intrusive_ptr<Responder> ResponderPtr;
|
||||
|
||||
} // namespace AICurlInterface
|
||||
|
||||
// Forward declaration (see aicurlprivate.h).
|
||||
namespace AICurlPrivate {
|
||||
class CurlEasyRequest;
|
||||
} // namespace AICurlPrivate
|
||||
|
||||
// Define access types (_crat = Const Read Access Type, _rat = Read Access Type, _wat = Write Access Type).
|
||||
// Typical usage is:
|
||||
// AICurlEasyRequest h1; // Create easy handle.
|
||||
// AICurlEasyRequest h2(h1); // Make lightweight copies.
|
||||
// AICurlEasyRequest_wat h2_w(*h2); // Lock and obtain write access to the easy handle.
|
||||
// Use *h2_w, which is a reference to the locked CurlEasyRequest instance.
|
||||
// Note: As it is not allowed to use curl easy handles in any way concurrently,
|
||||
// read access would at most give access to a CURL const*, which will turn out
|
||||
// to be completely useless; therefore it is sufficient and efficient to use
|
||||
// an AIThreadSafeSimple and it's unlikely that AICurlEasyRequest_rat will be used.
|
||||
typedef AIAccessConst<AICurlPrivate::CurlEasyRequest> AICurlEasyRequest_rat;
|
||||
typedef AIAccess<AICurlPrivate::CurlEasyRequest> AICurlEasyRequest_wat;
|
||||
|
||||
// Events generated by AICurlPrivate::CurlEasyHandle.
|
||||
struct AICurlEasyHandleEvents {
|
||||
// Events.
|
||||
virtual void added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w) = 0;
|
||||
virtual void finished(AICurlEasyRequest_wat& curl_easy_request_w) = 0;
|
||||
virtual void removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w) = 0;
|
||||
// Avoid compiler warning.
|
||||
virtual ~AICurlEasyHandleEvents() { }
|
||||
};
|
||||
|
||||
#include "aicurlprivate.h"
|
||||
|
||||
// AICurlPrivate::CurlEasyRequestPtr, a boost::intrusive_ptr, is no more threadsafe than a
|
||||
// builtin type, but wrapping it in AIThreadSafe is obviously not going to help here.
|
||||
// Therefore we use the following trick: we wrap CurlEasyRequestPtr too, and only allow
|
||||
// read accesses on it.
|
||||
|
||||
// AICurlEasyRequest: a thread safe, reference counting, auto-cleaning curl easy handle.
|
||||
class AICurlEasyRequest {
|
||||
public:
|
||||
// Initial construction is allowed (thread-safe).
|
||||
// Note: If ThreadSafeCurlEasyRequest() throws then the memory allocated is still freed.
|
||||
// 'new' never returned however and neither the constructor nor destructor of mCurlEasyRequest is called in this case.
|
||||
// This might throw AICurlNoEasyHandle.
|
||||
AICurlEasyRequest(bool buffered) :
|
||||
mCurlEasyRequest(buffered ? new AICurlPrivate::ThreadSafeBufferedCurlEasyRequest : new AICurlPrivate::ThreadSafeCurlEasyRequest) { }
|
||||
AICurlEasyRequest(AICurlEasyRequest const& orig) : mCurlEasyRequest(orig.mCurlEasyRequest) { }
|
||||
|
||||
// For the rest, only allow read operations.
|
||||
AIThreadSafeSimple<AICurlPrivate::CurlEasyRequest>& operator*(void) const { llassert(mCurlEasyRequest.get()); return *mCurlEasyRequest; }
|
||||
AIThreadSafeSimple<AICurlPrivate::CurlEasyRequest>* operator->(void) const { llassert(mCurlEasyRequest.get()); return mCurlEasyRequest.get(); }
|
||||
AIThreadSafeSimple<AICurlPrivate::CurlEasyRequest>* get(void) const { return mCurlEasyRequest.get(); }
|
||||
|
||||
// Returns true if this object points to the same CurlEasyRequest object.
|
||||
bool operator==(AICurlEasyRequest const& cer) const { return mCurlEasyRequest == cer.mCurlEasyRequest; }
|
||||
|
||||
// Returns true if this object points to a different CurlEasyRequest object.
|
||||
bool operator!=(AICurlEasyRequest const& cer) const { return mCurlEasyRequest != cer.mCurlEasyRequest; }
|
||||
|
||||
// Queue this request for insertion in the multi session.
|
||||
void addRequest(void);
|
||||
|
||||
// Queue a command to remove this request from the multi session (or cancel a queued command to add it).
|
||||
void removeRequest(void);
|
||||
|
||||
// Returns true when this AICurlEasyRequest wraps a AICurlPrivate::ThreadSafeBufferedCurlEasyRequest.
|
||||
bool isBuffered(void) const { return mCurlEasyRequest->isBuffered(); }
|
||||
|
||||
private:
|
||||
// The actual pointer to the ThreadSafeCurlEasyRequest instance.
|
||||
AICurlPrivate::CurlEasyRequestPtr mCurlEasyRequest;
|
||||
|
||||
private:
|
||||
// Assignment would not be thread-safe; we may create this object and read from it.
|
||||
// Note: Destruction is implicitly assumed thread-safe, as it would be a logic error to
|
||||
// destruct it while another thread still needs it, concurrent or not.
|
||||
AICurlEasyRequest& operator=(AICurlEasyRequest const&) { return *this; }
|
||||
|
||||
public:
|
||||
// The more exotic member functions of this class, to deal with passing this class
|
||||
// as CURLOPT_PRIVATE pointer to a curl handle and afterwards restore it.
|
||||
// For "internal use" only; don't use things from AICurlPrivate yourself.
|
||||
|
||||
// It's thread-safe to give read access the underlaying boost::intrusive_ptr.
|
||||
// It's not OK to then call get() on that and store the AICurlPrivate::ThreadSafeCurlEasyRequest* separately.
|
||||
AICurlPrivate::CurlEasyRequestPtr const& get_ptr(void) const { return mCurlEasyRequest; }
|
||||
|
||||
// If we have a correct (with regard to reference counting) AICurlPrivate::CurlEasyRequestPtr,
|
||||
// then it's OK to construct a AICurlEasyRequest from it.
|
||||
// Note that the external AICurlPrivate::CurlEasyRequestPtr needs its own locking, because
|
||||
// it's not thread-safe in itself.
|
||||
AICurlEasyRequest(AICurlPrivate::CurlEasyRequestPtr const& ptr) : mCurlEasyRequest(ptr) { }
|
||||
|
||||
// This one is obviously dangerous. It's for use only in MultiHandle::check_run_count.
|
||||
// See also the long comment in CurlEasyRequest::finalizeRequest with regard to CURLOPT_PRIVATE.
|
||||
explicit AICurlEasyRequest(AICurlPrivate::ThreadSafeCurlEasyRequest* ptr) : mCurlEasyRequest(ptr) { }
|
||||
};
|
||||
|
||||
// Write Access Type for the buffer.
|
||||
struct AICurlResponderBuffer_wat : public AIAccess<AICurlPrivate::CurlResponderBuffer> {
|
||||
explicit AICurlResponderBuffer_wat(AICurlPrivate::ThreadSafeBufferedCurlEasyRequest& lockobj) :
|
||||
AIAccess<AICurlPrivate::CurlResponderBuffer>(lockobj) { }
|
||||
AICurlResponderBuffer_wat(AIThreadSafeSimple<AICurlPrivate::CurlEasyRequest>& lockobj) :
|
||||
AIAccess<AICurlPrivate::CurlResponderBuffer>(static_cast<AICurlPrivate::ThreadSafeBufferedCurlEasyRequest&>(lockobj)) { }
|
||||
};
|
||||
|
||||
#define AICurlPrivate DONTUSE_AICurlPrivate
|
||||
|
||||
#endif
|
||||
@@ -1,414 +0,0 @@
|
||||
/**
|
||||
* @file aicurlprivate.h
|
||||
* @brief Thread safe wrapper for libcurl.
|
||||
*
|
||||
* Copyright (c) 2012, Aleric Inglewood.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution.
|
||||
*
|
||||
* CHANGELOG
|
||||
* and additional copyright holders.
|
||||
*
|
||||
* 28/04/2012
|
||||
* Initial version, written by Aleric Inglewood @ SL
|
||||
*/
|
||||
|
||||
#ifndef AICURLPRIVATE_H
|
||||
#define AICURLPRIVATE_H
|
||||
|
||||
#include <sstream>
|
||||
#include "llatomic.h"
|
||||
|
||||
namespace AICurlPrivate {
|
||||
namespace curlthread { class MultiHandle; }
|
||||
|
||||
struct Stats {
|
||||
static LLAtomicU32 easy_calls;
|
||||
static LLAtomicU32 easy_errors;
|
||||
static LLAtomicU32 easy_init_calls;
|
||||
static LLAtomicU32 easy_init_errors;
|
||||
static LLAtomicU32 easy_cleanup_calls;
|
||||
static LLAtomicU32 multi_calls;
|
||||
static LLAtomicU32 multi_errors;
|
||||
|
||||
static void print(void);
|
||||
};
|
||||
|
||||
void handle_multi_error(CURLMcode code);
|
||||
inline CURLMcode check_multi_code(CURLMcode code) { Stats::multi_calls++; if (code != CURLM_OK) handle_multi_error(code); return code; }
|
||||
|
||||
bool curlThreadIsRunning(void);
|
||||
void wakeUpCurlThread(void);
|
||||
void stopCurlThread(void);
|
||||
|
||||
class ThreadSafeCurlEasyRequest;
|
||||
class ThreadSafeBufferedCurlEasyRequest;
|
||||
|
||||
// This class wraps CURL*'s.
|
||||
// It guarantees that a pointer is cleaned up when no longer needed, as required by libcurl.
|
||||
class CurlEasyHandle : public boost::noncopyable, protected AICurlEasyHandleEvents {
|
||||
public:
|
||||
CurlEasyHandle(void);
|
||||
~CurlEasyHandle();
|
||||
|
||||
private:
|
||||
// Disallow assignment.
|
||||
CurlEasyHandle& operator=(CurlEasyHandle const*);
|
||||
|
||||
public:
|
||||
// Reset all options of a libcurl session handle.
|
||||
void reset(void) { llassert(!mActiveMultiHandle); curl_easy_reset(mEasyHandle); }
|
||||
|
||||
// Set options for a curl easy handle.
|
||||
template<typename BUILTIN>
|
||||
CURLcode setopt(CURLoption option, BUILTIN parameter);
|
||||
|
||||
// Clone a libcurl session handle using all the options previously set.
|
||||
//CurlEasyHandle(CurlEasyHandle const& orig);
|
||||
|
||||
// URL encode/decode the given string.
|
||||
char* escape(char* url, int length);
|
||||
char* unescape(char* url, int inlength , int* outlength);
|
||||
|
||||
// Extract information from a curl handle.
|
||||
CURLcode getinfo(CURLINFO info, void* data);
|
||||
#if _WIN64 || __x86_64__ || __ppc64__
|
||||
// Overload for integer types that are too small (libcurl demands a long).
|
||||
CURLcode getinfo(CURLINFO info, S32* data) { long ldata; CURLcode res = getinfo(info, &ldata); *data = static_cast<S32>(ldata); return res; }
|
||||
CURLcode getinfo(CURLINFO info, U32* data) { long ldata; CURLcode res = getinfo(info, &ldata); *data = static_cast<U32>(ldata); return res; }
|
||||
#endif
|
||||
|
||||
// Perform a file transfer (blocking).
|
||||
CURLcode perform(void);
|
||||
// Pause and unpause a connection.
|
||||
CURLcode pause(int bitmask);
|
||||
|
||||
// Called when a request is queued for removal. In that case a race between the actual removal
|
||||
// and revoking of the callbacks is harmless (and happens for the raw non-statemachine version).
|
||||
void remove_queued(void) { mQueuedForRemoval = true; }
|
||||
// In case it's added after being removed.
|
||||
void add_queued(void) { mQueuedForRemoval = false; }
|
||||
|
||||
private:
|
||||
CURL* mEasyHandle;
|
||||
CURLM* mActiveMultiHandle;
|
||||
char* mErrorBuffer;
|
||||
bool mQueuedForRemoval; // Set if the easy handle is (probably) added to the multi handle, but is queued for removal.
|
||||
#ifdef SHOW_ASSERT
|
||||
public:
|
||||
bool mRemovedPerCommand; // Set if mActiveMultiHandle was reset as per command from the main thread.
|
||||
#endif
|
||||
|
||||
private:
|
||||
// This should only be called from MultiHandle; add/remove an easy handle to/from a multi handle.
|
||||
friend class curlthread::MultiHandle;
|
||||
CURLMcode add_handle_to_multi(AICurlEasyRequest_wat& curl_easy_request_w, CURLM* multi_handle);
|
||||
CURLMcode remove_handle_from_multi(AICurlEasyRequest_wat& curl_easy_request_w, CURLM* multi_handle);
|
||||
|
||||
public:
|
||||
// Returns true if this easy handle was added to a curl multi handle.
|
||||
bool active(void) const { return mActiveMultiHandle; }
|
||||
|
||||
// If there was an error code as result, then this returns a human readable error string.
|
||||
// Only valid when setErrorBuffer was called and the curl_easy function returned an error.
|
||||
std::string getErrorString(void) const { return mErrorBuffer ? mErrorBuffer : "(null)"; }
|
||||
|
||||
// Returns true when it is expected that the parent will revoke callbacks before the curl
|
||||
// easy handle is removed from the multi handle; that usually happens when an external
|
||||
// error demands termination of the request (ie, an expiration).
|
||||
bool no_warning(void) const { return mQueuedForRemoval || LLApp::isExiting(); }
|
||||
|
||||
// Used for debugging purposes.
|
||||
bool operator==(CURL* easy_handle) const { return mEasyHandle == easy_handle; }
|
||||
|
||||
private:
|
||||
// Call this prior to every curl_easy function whose return value is passed to check_easy_code.
|
||||
void setErrorBuffer(void);
|
||||
|
||||
static void handle_easy_error(CURLcode code);
|
||||
|
||||
// Always first call setErrorBuffer()!
|
||||
static inline CURLcode check_easy_code(CURLcode code)
|
||||
{
|
||||
Stats::easy_calls++;
|
||||
if (code != CURLE_OK)
|
||||
handle_easy_error(code);
|
||||
return code;
|
||||
}
|
||||
|
||||
protected:
|
||||
// Return the underlying curl easy handle.
|
||||
CURL* getEasyHandle(void) const { return mEasyHandle; }
|
||||
|
||||
private:
|
||||
// Return, and possibly create, the curl (easy) error buffer used by the current thread.
|
||||
static char* getTLErrorBuffer(void);
|
||||
};
|
||||
|
||||
template<typename BUILTIN>
|
||||
CURLcode CurlEasyHandle::setopt(CURLoption option, BUILTIN parameter)
|
||||
{
|
||||
llassert(!mActiveMultiHandle);
|
||||
setErrorBuffer();
|
||||
return check_easy_code(curl_easy_setopt(mEasyHandle, option, parameter));
|
||||
}
|
||||
|
||||
// CurlEasyRequest adds a slightly more powerful interface that can be used
|
||||
// to set the options on a curl easy handle.
|
||||
//
|
||||
// Calling sendRequest() will then connect to the given URL and perform
|
||||
// the data exchange. If an error occurs related to this handle, it can
|
||||
// be read by calling getErrorString().
|
||||
//
|
||||
// Note that the life cycle of a CurlEasyRequest is controlled by AICurlEasyRequest:
|
||||
// a CurlEasyRequest is only ever created as base class of a ThreadSafeCurlEasyRequest,
|
||||
// which is only created by creating a AICurlEasyRequest. When the last copy of such
|
||||
// AICurlEasyRequest is deleted, then also the ThreadSafeCurlEasyRequest is deleted
|
||||
// and the CurlEasyRequest destructed.
|
||||
class CurlEasyRequest : public CurlEasyHandle {
|
||||
public:
|
||||
void setoptString(CURLoption option, std::string const& value);
|
||||
void setPost(char const* postdata, S32 size);
|
||||
void addHeader(char const* str);
|
||||
|
||||
private:
|
||||
// Callback stubs.
|
||||
static size_t headerCallback(char* ptr, size_t size, size_t nmemb, void* userdata);
|
||||
static size_t writeCallback(char* ptr, size_t size, size_t nmemb, void* userdata);
|
||||
static size_t readCallback(char* ptr, size_t size, size_t nmemb, void* userdata);
|
||||
static CURLcode SSLCtxCallback(CURL* curl, void* sslctx, void* userdata);
|
||||
|
||||
curl_write_callback mHeaderCallback;
|
||||
void* mHeaderCallbackUserData;
|
||||
curl_write_callback mWriteCallback;
|
||||
void* mWriteCallbackUserData;
|
||||
curl_read_callback mReadCallback;
|
||||
void* mReadCallbackUserData;
|
||||
curl_ssl_ctx_callback mSSLCtxCallback;
|
||||
void* mSSLCtxCallbackUserData;
|
||||
|
||||
public:
|
||||
void setHeaderCallback(curl_write_callback callback, void* userdata);
|
||||
void setWriteCallback(curl_write_callback callback, void* userdata);
|
||||
void setReadCallback(curl_read_callback callback, void* userdata);
|
||||
void setSSLCtxCallback(curl_ssl_ctx_callback callback, void* userdata);
|
||||
|
||||
// Call this if the set callbacks are about to be invalidated.
|
||||
void revokeCallbacks(void);
|
||||
|
||||
// Reset everything to the state it was in when this object was just created.
|
||||
void resetState(void);
|
||||
|
||||
private:
|
||||
// Called from applyDefaultOptions.
|
||||
void applyProxySettings(void);
|
||||
|
||||
public:
|
||||
// Set default options that we want applied to all curl easy handles.
|
||||
void applyDefaultOptions(void);
|
||||
|
||||
// Prepare the request for adding it to a multi session, or calling perform.
|
||||
// This actually adds the headers that were collected with addHeader.
|
||||
void finalizeRequest(std::string const& url);
|
||||
|
||||
// Store result code that is returned by getResult.
|
||||
void store_result(CURLcode result) { mResult = result; }
|
||||
|
||||
// Called when the curl easy handle is done.
|
||||
void done(AICurlEasyRequest_wat& curl_easy_request_w) { finished(curl_easy_request_w); }
|
||||
|
||||
// Fill info with the transfer info.
|
||||
void getTransferInfo(AICurlInterface::TransferInfo* info);
|
||||
|
||||
// If result != CURLE_FAILED_INIT then also info was filled.
|
||||
void getResult(CURLcode* result, AICurlInterface::TransferInfo* info = NULL);
|
||||
|
||||
private:
|
||||
curl_slist* mHeaders;
|
||||
bool mRequestFinalized;
|
||||
AICurlEasyHandleEvents* mEventsTarget;
|
||||
CURLcode mResult;
|
||||
|
||||
private:
|
||||
// This class may only be created by constructing a ThreadSafeCurlEasyRequest.
|
||||
friend class ThreadSafeCurlEasyRequest;
|
||||
// Throws AICurlNoEasyHandle.
|
||||
CurlEasyRequest(void) :
|
||||
mHeaders(NULL), mRequestFinalized(false), mEventsTarget(NULL), mResult(CURLE_FAILED_INIT)
|
||||
{ applyDefaultOptions(); }
|
||||
public:
|
||||
~CurlEasyRequest();
|
||||
|
||||
public:
|
||||
// Post-initialization, set the parent to pass the events to.
|
||||
void send_events_to(AICurlEasyHandleEvents* target) { mEventsTarget = target; }
|
||||
|
||||
// For debugging purposes
|
||||
bool is_finalized(void) const { return mRequestFinalized; }
|
||||
|
||||
// Return pointer to the ThreadSafe (wrapped) version of this object.
|
||||
ThreadSafeCurlEasyRequest* get_lockobj(void);
|
||||
|
||||
protected:
|
||||
// Pass events to parent.
|
||||
/*virtual*/ void added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w);
|
||||
/*virtual*/ void finished(AICurlEasyRequest_wat& curl_easy_request_w);
|
||||
/*virtual*/ void removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w);
|
||||
};
|
||||
|
||||
// Buffers used by the AICurlInterface::Request API.
|
||||
// Curl callbacks write into and read from these buffers.
|
||||
// The interface with the rest of the code is through AICurlInterface::Responder.
|
||||
//
|
||||
// The lifetime of a CurlResponderBuffer is slightly shorter than its
|
||||
// associated CurlEasyRequest; this class can only be created as base class
|
||||
// of ThreadSafeBufferedCurlEasyRequest, and is therefore constructed after
|
||||
// the construction of the associated CurlEasyRequest and destructed before it.
|
||||
// Hence, it's safe to use get_lockobj() and through that access the CurlEasyRequest
|
||||
// object at all times.
|
||||
//
|
||||
// A CurlResponderBuffer is thus created when a ThreadSafeBufferedCurlEasyRequest
|
||||
// is created which only happens by creating a AICurlEasyRequest(true) instance,
|
||||
// and when the last AICurlEasyRequest is deleted, then the ThreadSafeBufferedCurlEasyRequest
|
||||
// is deleted and the CurlResponderBuffer destructed.
|
||||
class CurlResponderBuffer : protected AICurlEasyHandleEvents {
|
||||
public:
|
||||
void resetState(AICurlEasyRequest_wat& curl_easy_request_w);
|
||||
void prepRequest(AICurlEasyRequest_wat& buffered_curl_easy_request_w, std::vector<std::string> const& headers, AICurlInterface::ResponderPtr responder, S32 time_out = 0, bool post = false);
|
||||
|
||||
std::stringstream& getInput() { return mInput; }
|
||||
std::stringstream& getHeaderOutput() { return mHeaderOutput; }
|
||||
LLIOPipe::buffer_ptr_t& getOutput() { return mOutput; }
|
||||
|
||||
// Called if libcurl doesn't deliver within CurlRequestTimeOut seconds.
|
||||
void timed_out(void);
|
||||
|
||||
// Called after removed_from_multi_handle was called.
|
||||
void processOutput(AICurlEasyRequest_wat& curl_easy_request_w);
|
||||
|
||||
protected:
|
||||
/*virtual*/ void added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w);
|
||||
/*virtual*/ void finished(AICurlEasyRequest_wat& curl_easy_request_w);
|
||||
/*virtual*/ void removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w);
|
||||
|
||||
private:
|
||||
std::stringstream mInput;
|
||||
std::stringstream mHeaderOutput;
|
||||
LLIOPipe::buffer_ptr_t mOutput;
|
||||
AICurlInterface::ResponderPtr mResponder;
|
||||
|
||||
public:
|
||||
static LLChannelDescriptors const sChannels; // Channel object for mOutput: we ONLY use channel 0, so this can be a constant.
|
||||
|
||||
private:
|
||||
// This class may only be created by constructing a ThreadSafeBufferedCurlEasyRequest.
|
||||
friend class ThreadSafeBufferedCurlEasyRequest;
|
||||
CurlResponderBuffer(void);
|
||||
public:
|
||||
~CurlResponderBuffer();
|
||||
|
||||
private:
|
||||
static size_t curlWriteCallback(char* data, size_t size, size_t nmemb, void* user_data);
|
||||
static size_t curlReadCallback(char* data, size_t size, size_t nmemb, void* user_data);
|
||||
static size_t curlHeaderCallback(char* data, size_t size, size_t nmemb, void* user_data);
|
||||
|
||||
public:
|
||||
// Return pointer to the ThreadSafe (wrapped) version of this object.
|
||||
ThreadSafeBufferedCurlEasyRequest* get_lockobj(void);
|
||||
|
||||
// Return true when prepRequest was already called and the object has not been
|
||||
// invalidated as a result of calling timed_out().
|
||||
bool isValid(void) const { return mResponder; }
|
||||
};
|
||||
|
||||
// This class wraps CurlEasyRequest for thread-safety and adds a reference counter so we can
|
||||
// copy it around cheaply and it gets destructed automatically when the last instance is deleted.
|
||||
// It guarantees that the CURL* handle is never used concurrently, which is not allowed by libcurl.
|
||||
// As AIThreadSafeSimpleDC contains a mutex, it cannot be copied. Therefore we need a reference counter for this object.
|
||||
class ThreadSafeCurlEasyRequest : public AIThreadSafeSimple<CurlEasyRequest> {
|
||||
public:
|
||||
// Throws AICurlNoEasyHandle.
|
||||
ThreadSafeCurlEasyRequest(void) : mReferenceCount(0)
|
||||
{ new (ptr()) CurlEasyRequest;
|
||||
Dout(dc::curl, "Creating ThreadSafeCurlEasyRequest with this = " << (void*)this); }
|
||||
virtual ~ThreadSafeCurlEasyRequest()
|
||||
{ Dout(dc::curl, "Destructing ThreadSafeCurlEasyRequest with this = " << (void*)this); }
|
||||
|
||||
// Returns true if this is a base class of ThreadSafeBufferedCurlEasyRequest.
|
||||
virtual bool isBuffered(void) const { return false; }
|
||||
|
||||
private:
|
||||
LLAtomicU32 mReferenceCount;
|
||||
|
||||
friend void intrusive_ptr_add_ref(ThreadSafeCurlEasyRequest* p); // Called by boost::intrusive_ptr when a new copy of a boost::intrusive_ptr<ThreadSafeCurlEasyRequest> is made.
|
||||
friend void intrusive_ptr_release(ThreadSafeCurlEasyRequest* p); // Called by boost::intrusive_ptr when a boost::intrusive_ptr<ThreadSafeCurlEasyRequest> is destroyed.
|
||||
};
|
||||
|
||||
// Same as the above but adds a CurlResponderBuffer. The latter has its own locking in order to
|
||||
// allow casting the underlying CurlEasyRequest to ThreadSafeCurlEasyRequest, independent of
|
||||
// what class it is part of: ThreadSafeCurlEasyRequest or ThreadSafeBufferedCurlEasyRequest.
|
||||
// The virtual destructor of ThreadSafeCurlEasyRequest allows to treat each easy handle transparently
|
||||
// as a ThreadSafeCurlEasyRequest object, or optionally dynamic_cast it to a ThreadSafeBufferedCurlEasyRequest.
|
||||
// Note: the order of these base classes is important: AIThreadSafeSimple<CurlResponderBuffer> is now
|
||||
// destructed before ThreadSafeCurlEasyRequest is.
|
||||
class ThreadSafeBufferedCurlEasyRequest : public ThreadSafeCurlEasyRequest, public AIThreadSafeSimple<CurlResponderBuffer> {
|
||||
public:
|
||||
// Throws AICurlNoEasyHandle.
|
||||
ThreadSafeBufferedCurlEasyRequest(void) { new (AIThreadSafeSimple<CurlResponderBuffer>::ptr()) CurlResponderBuffer; }
|
||||
|
||||
/*virtual*/ bool isBuffered(void) const { return true; }
|
||||
};
|
||||
|
||||
// The curl easy request type wrapped in a reference counting pointer.
|
||||
typedef boost::intrusive_ptr<AICurlPrivate::ThreadSafeCurlEasyRequest> CurlEasyRequestPtr;
|
||||
|
||||
// This class wraps CURLM*'s.
|
||||
// It guarantees that a pointer is cleaned up when no longer needed, as required by libcurl.
|
||||
class CurlMultiHandle : public boost::noncopyable {
|
||||
public:
|
||||
CurlMultiHandle(void);
|
||||
~CurlMultiHandle();
|
||||
|
||||
private:
|
||||
// Disallow assignment.
|
||||
CurlMultiHandle& operator=(CurlMultiHandle const*);
|
||||
|
||||
private:
|
||||
static LLAtomicU32 sTotalMultiHandles;
|
||||
|
||||
protected:
|
||||
CURLM* mMultiHandle;
|
||||
|
||||
public:
|
||||
// Set options for a curl multi handle.
|
||||
template<typename BUILTIN>
|
||||
CURLMcode setopt(CURLMoption option, BUILTIN parameter);
|
||||
|
||||
// Returns total number of existing CURLM* handles (excluding ones created outside this class).
|
||||
static U32 getTotalMultiHandles(void) { return sTotalMultiHandles; }
|
||||
};
|
||||
|
||||
template<typename BUILTIN>
|
||||
CURLMcode CurlMultiHandle::setopt(CURLMoption option, BUILTIN parameter)
|
||||
{
|
||||
return check_multi_code(curl_multi_setopt(mMultiHandle, option, parameter));
|
||||
}
|
||||
|
||||
} // namespace AICurlPrivate
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,128 +0,0 @@
|
||||
/**
|
||||
* @file aicurlthread.h
|
||||
* @brief Thread safe wrapper for libcurl.
|
||||
*
|
||||
* Copyright (c) 2012, Aleric Inglewood.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution.
|
||||
*
|
||||
* CHANGELOG
|
||||
* and additional copyright holders.
|
||||
*
|
||||
* 28/04/2012
|
||||
* Initial version, written by Aleric Inglewood @ SL
|
||||
*/
|
||||
|
||||
#ifndef AICURLTHREAD_H
|
||||
#define AICURLTHREAD_H
|
||||
|
||||
#include "aicurl.h"
|
||||
#include <vector>
|
||||
|
||||
#undef AICurlPrivate
|
||||
|
||||
namespace AICurlPrivate {
|
||||
namespace curlthread {
|
||||
|
||||
class PollSet;
|
||||
|
||||
// For ordering a std::set with AICurlEasyRequest objects.
|
||||
struct AICurlEasyRequestCompare {
|
||||
bool operator()(AICurlEasyRequest const& h1, AICurlEasyRequest const& h2) { return h1.get() < h2.get(); }
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// MultiHandle
|
||||
|
||||
// This class adds member functions that will only be called from the AICurlThread thread.
|
||||
// This class guarantees that all added easy handles will be removed from the multi handle
|
||||
// before the multi handle is cleaned up, as is required by libcurl.
|
||||
class MultiHandle : public CurlMultiHandle
|
||||
{
|
||||
public:
|
||||
MultiHandle(void);
|
||||
~MultiHandle();
|
||||
|
||||
// Add/remove an easy handle to/from a multi session.
|
||||
CURLMcode add_easy_request(AICurlEasyRequest const& easy_request);
|
||||
CURLMcode remove_easy_request(AICurlEasyRequest const& easy_request, bool as_per_command = false);
|
||||
|
||||
// Reads/writes available data from a particular socket (non-blocking).
|
||||
CURLMcode socket_action(curl_socket_t sockfd, int ev_bitmask);
|
||||
|
||||
// Set data to association with an internal socket.
|
||||
CURLMcode assign(curl_socket_t sockfd, void* sockptr);
|
||||
|
||||
// Read multi stack informationals.
|
||||
CURLMsg const* info_read(int* msgs_in_queue) const;
|
||||
|
||||
private:
|
||||
typedef std::set<AICurlEasyRequest, AICurlEasyRequestCompare> addedEasyRequests_type;
|
||||
addedEasyRequests_type mAddedEasyRequests;
|
||||
|
||||
bool mHandleAddedOrRemoved; // Set when an easy handle was added or removed, reset in check_run_count().
|
||||
int mPrevRunningHandles; // The last value of mRunningHandles that check_run_count() was called with.
|
||||
int mRunningHandles; // The last value returned by curl_multi_socket_action.
|
||||
long mTimeOut; // The last time out in ms as set by the callback CURLMOPT_TIMERFUNCTION.
|
||||
|
||||
private:
|
||||
static int socket_callback(CURL* easy, curl_socket_t s, int action, void* userp, void* socketp);
|
||||
static int timer_callback(CURLM* multi, long timeout_ms, void* userp);
|
||||
|
||||
public:
|
||||
// Returns the number of active easy handles as reported by the last call to curl_multi_socket_action.
|
||||
int getRunningHandles(void) const { return mRunningHandles; }
|
||||
|
||||
// Returns how long to wait for socket action before calling socket_action(CURL_SOCKET_TIMEOUT, 0), in ms.
|
||||
int getTimeOut(void) const { return mTimeOut; }
|
||||
|
||||
// This is called before sleeping, after calling (one or more times) socket_action.
|
||||
void check_run_count(void);
|
||||
|
||||
public:
|
||||
//-----------------------------------------------------------------------------
|
||||
// Curl socket administration:
|
||||
|
||||
PollSet* mReadPollSet;
|
||||
PollSet* mWritePollSet;
|
||||
};
|
||||
|
||||
} // namespace curlthread
|
||||
} // namespace AICurlPrivate
|
||||
|
||||
// Thread safe, noncopyable curl multi handle.
|
||||
// This class wraps MultiHandle for thread-safety.
|
||||
// AIThreadSafeSingleThreadDC cannot be copied, but that is OK as we don't need that (or want that);
|
||||
// this class provides a thread-local singleton (exactly one instance per thread), and because it
|
||||
// can't be copied, that guarantees that the CURLM* handle is never used concurrently, which is
|
||||
// not allowed by libcurl.
|
||||
class AICurlMultiHandle : public AIThreadSafeSingleThreadDC<AICurlPrivate::curlthread::MultiHandle>, public LLThreadLocalDataMember {
|
||||
public:
|
||||
static AICurlMultiHandle& getInstance(void);
|
||||
static void destroyInstance(void);
|
||||
private:
|
||||
// Use getInstance().
|
||||
AICurlMultiHandle(void) { }
|
||||
};
|
||||
|
||||
typedef AISTAccessConst<AICurlPrivate::curlthread::MultiHandle> AICurlMultiHandle_rat;
|
||||
typedef AISTAccess<AICurlPrivate::curlthread::MultiHandle> AICurlMultiHandle_wat;
|
||||
|
||||
#define AICurlPrivate DONTUSE_AICurlPrivate
|
||||
|
||||
#endif
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "llares.h"
|
||||
#include "llscopedvolatileaprpool.h"
|
||||
|
||||
#include <ares_dns.h>
|
||||
#include <ares_version.h>
|
||||
@@ -38,7 +39,6 @@
|
||||
|
||||
#include "llapr.h"
|
||||
#include "llareslistener.h"
|
||||
#include "llscopedvolatileaprpool.h"
|
||||
|
||||
#if defined(LL_WINDOWS)
|
||||
#pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally
|
||||
@@ -468,6 +468,7 @@ bool LLAres::process(U64 timeout)
|
||||
ares_socket_t socks[ARES_GETSOCK_MAXNUM];
|
||||
apr_pollfd_t aprFds[ARES_GETSOCK_MAXNUM];
|
||||
apr_int32_t nsds = 0;
|
||||
apr_status_t status;
|
||||
int nactive = 0;
|
||||
int bitmask;
|
||||
|
||||
@@ -478,8 +479,6 @@ bool LLAres::process(U64 timeout)
|
||||
return nsds > 0;
|
||||
}
|
||||
|
||||
LLScopedVolatileAPRPool scoped_pool;
|
||||
|
||||
for (int i = 0; i < ARES_GETSOCK_MAXNUM; i++)
|
||||
{
|
||||
if (ARES_GETSOCK_READABLE(bitmask, i))
|
||||
@@ -495,7 +494,7 @@ bool LLAres::process(U64 timeout)
|
||||
|
||||
apr_socket_t *aprSock = NULL;
|
||||
|
||||
apr_status_t status = apr_os_sock_put(&aprSock, (apr_os_sock_t *) &socks[i], scoped_pool);
|
||||
status = apr_os_sock_put(&aprSock, (apr_os_sock_t *) &socks[i], LLAPRRootPool::get()());
|
||||
if (status != APR_SUCCESS)
|
||||
{
|
||||
ll_apr_warn_status(status);
|
||||
@@ -504,7 +503,7 @@ bool LLAres::process(U64 timeout)
|
||||
|
||||
aprFds[nactive].desc.s = aprSock;
|
||||
aprFds[nactive].desc_type = APR_POLL_SOCKET;
|
||||
aprFds[nactive].p = scoped_pool;
|
||||
aprFds[nactive].p = LLAPRRootPool::get()();
|
||||
aprFds[nactive].rtnevents = 0;
|
||||
aprFds[nactive].client_data = &socks[i];
|
||||
|
||||
@@ -513,7 +512,7 @@ bool LLAres::process(U64 timeout)
|
||||
|
||||
if (nactive > 0)
|
||||
{
|
||||
apr_status_t status = apr_poll(aprFds, nactive, &nsds, timeout);
|
||||
status = apr_poll(aprFds, nactive, &nsds, timeout);
|
||||
|
||||
if (status != APR_SUCCESS && status != APR_TIMEUP)
|
||||
{
|
||||
|
||||
@@ -401,7 +401,7 @@ bool LLAssetStorage::findInStaticVFSAndInvokeCallback(const LLUUID& uuid, LLAsse
|
||||
if (user_data)
|
||||
{
|
||||
// The *user_data should not be passed without a callback to clean it up.
|
||||
llassert(callback != NULL);
|
||||
llassert(callback != NULL)
|
||||
}
|
||||
|
||||
BOOL exists = mStaticVFS->getExists(uuid, type);
|
||||
@@ -441,7 +441,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, LL
|
||||
if (user_data)
|
||||
{
|
||||
// The *user_data should not be passed without a callback to clean it up.
|
||||
llassert(callback != NULL);
|
||||
llassert(callback != NULL)
|
||||
}
|
||||
|
||||
if (mShutDown)
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "llbuffer.h"
|
||||
#include <iterator>
|
||||
|
||||
#include "llmath.h"
|
||||
#include "llmemtype.h"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,39 +1,382 @@
|
||||
/**
|
||||
/**
|
||||
* @file llcurl.h
|
||||
* @brief Drop in replacement for old llcurl.h.
|
||||
* @author Zero / Donovan
|
||||
* @date 2006-10-15
|
||||
* @brief A wrapper around libcurl.
|
||||
*
|
||||
* Copyright (c) 2012, Aleric Inglewood.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* $LicenseInfo:firstyear=2006&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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution.
|
||||
*
|
||||
* CHANGELOG
|
||||
* and additional copyright holders.
|
||||
*
|
||||
* 22/06/2012
|
||||
* Initial version, written by Aleric Inglewood @ SL
|
||||
* 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_LLCURL_H
|
||||
#define LL_LLCURL_H
|
||||
|
||||
#include "aicurl.h"
|
||||
#include "linden_common.h"
|
||||
|
||||
// Map interface to old LLCurl names so this can be used as a drop-in replacement.
|
||||
namespace LLCurl = AICurlInterface;
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/intrusive_ptr.hpp>
|
||||
#include <curl/curl.h> // TODO: remove dependency
|
||||
|
||||
#include "llbuffer.h"
|
||||
#include "lliopipe.h"
|
||||
#include "llsd.h"
|
||||
#include "llthread.h"
|
||||
|
||||
class LLMutex;
|
||||
|
||||
// For whatever reason, this is not typedef'd in curl.h
|
||||
typedef size_t (*curl_header_callback)(void *ptr, size_t size, size_t nmemb, void *stream);
|
||||
|
||||
class LLCurl
|
||||
{
|
||||
LOG_CLASS(LLCurl);
|
||||
|
||||
public:
|
||||
class Easy;
|
||||
class Multi;
|
||||
|
||||
static bool sMultiThreaded;
|
||||
|
||||
struct TransferInfo
|
||||
{
|
||||
TransferInfo() : mSizeDownload(0.0), mTotalTime(0.0), mSpeedDownload(0.0) {}
|
||||
F64 mSizeDownload;
|
||||
F64 mTotalTime;
|
||||
F64 mSpeedDownload;
|
||||
};
|
||||
|
||||
class Responder
|
||||
{
|
||||
//LOG_CLASS(Responder);
|
||||
public:
|
||||
|
||||
Responder();
|
||||
virtual ~Responder();
|
||||
|
||||
/**
|
||||
* @brief return true if the status code indicates success.
|
||||
*/
|
||||
static bool isGoodStatus(U32 status)
|
||||
{
|
||||
return((200 <= status) && (status < 300));
|
||||
}
|
||||
|
||||
virtual void errorWithContent(
|
||||
U32 status,
|
||||
const std::string& reason,
|
||||
const LLSD& content);
|
||||
//< called by completed() on bad status
|
||||
|
||||
virtual void error(U32 status, const std::string& reason);
|
||||
//< called by default error(status, reason, content)
|
||||
|
||||
virtual void result(const LLSD& content);
|
||||
//< called by completed for good status codes.
|
||||
|
||||
virtual void completedRaw(
|
||||
U32 status,
|
||||
const std::string& reason,
|
||||
const LLChannelDescriptors& channels,
|
||||
const LLIOPipe::buffer_ptr_t& buffer);
|
||||
/**< Override point for clients that may want to use this
|
||||
class when the response is some other format besides LLSD
|
||||
*/
|
||||
|
||||
virtual void completed(
|
||||
U32 status,
|
||||
const std::string& reason,
|
||||
const LLSD& content);
|
||||
/**< The default implemetnation calls
|
||||
either:
|
||||
* result(), or
|
||||
* error()
|
||||
*/
|
||||
|
||||
// Override to handle parsing of the header only. Note: this is the only place where the contents
|
||||
// of the header can be parsed. In the ::completed call above only the body is contained in the LLSD.
|
||||
virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content);
|
||||
|
||||
// Used internally to set the url for debugging later.
|
||||
void setURL(const std::string& url);
|
||||
|
||||
virtual bool followRedir()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
public: /* but not really -- don't touch this */
|
||||
U32 mReferenceCount;
|
||||
|
||||
private:
|
||||
std::string mURL;
|
||||
};
|
||||
typedef boost::intrusive_ptr<Responder> ResponderPtr;
|
||||
|
||||
|
||||
/**
|
||||
* @ brief Set certificate authority file used to verify HTTPS certs.
|
||||
*/
|
||||
static void setCAFile(const std::string& file);
|
||||
|
||||
/**
|
||||
* @ brief Set certificate authority path used to verify HTTPS certs.
|
||||
*/
|
||||
static void setCAPath(const std::string& path);
|
||||
|
||||
/**
|
||||
* @ brief Return human-readable string describing libcurl version.
|
||||
*/
|
||||
static std::string getVersionString();
|
||||
|
||||
/**
|
||||
* @ brief Get certificate authority file used to verify HTTPS certs.
|
||||
*/
|
||||
static const std::string& getCAFile() { return sCAFile; }
|
||||
|
||||
/**
|
||||
* @ brief Get certificate authority path used to verify HTTPS certs.
|
||||
*/
|
||||
static const std::string& getCAPath() { return sCAPath; }
|
||||
|
||||
/**
|
||||
* @ brief Initialize LLCurl class
|
||||
*/
|
||||
static void initClass(bool multi_threaded = false);
|
||||
|
||||
/**
|
||||
* @ brief Cleanup LLCurl class
|
||||
*/
|
||||
static void cleanupClass();
|
||||
|
||||
/**
|
||||
* @ brief curl error code -> string
|
||||
*/
|
||||
static std::string strerror(CURLcode errorcode);
|
||||
|
||||
// For OpenSSL callbacks
|
||||
static std::vector<LLMutex*> sSSLMutex;
|
||||
|
||||
// OpenSSL callbacks
|
||||
static void ssl_locking_callback(int mode, int type, const char *file, int line);
|
||||
static unsigned long ssl_thread_id(void);
|
||||
|
||||
private:
|
||||
static std::string sCAPath;
|
||||
static std::string sCAFile;
|
||||
static const unsigned int MAX_REDIRECTS;
|
||||
};
|
||||
|
||||
class LLCurl::Easy
|
||||
{
|
||||
LOG_CLASS(Easy);
|
||||
|
||||
private:
|
||||
Easy();
|
||||
|
||||
public:
|
||||
static Easy* getEasy();
|
||||
~Easy();
|
||||
|
||||
CURL* getCurlHandle() const { return mCurlEasyHandle; }
|
||||
|
||||
void setErrorBuffer();
|
||||
void setCA();
|
||||
|
||||
void setopt(CURLoption option, S32 value);
|
||||
// These assume the setter does not free value!
|
||||
void setopt(CURLoption option, void* value);
|
||||
void setopt(CURLoption option, char* value);
|
||||
// Copies the string so that it is gauranteed to stick around
|
||||
void setoptString(CURLoption option, const std::string& value);
|
||||
|
||||
void slist_append(const char* str);
|
||||
void setHeaders();
|
||||
|
||||
U32 report(CURLcode);
|
||||
void getTransferInfo(LLCurl::TransferInfo* info);
|
||||
|
||||
void prepRequest(const std::string& url, const std::vector<std::string>& headers, ResponderPtr, S32 time_out = 0, bool post = false);
|
||||
|
||||
const char* getErrorBuffer();
|
||||
|
||||
std::stringstream& getInput() { return mInput; }
|
||||
std::stringstream& getHeaderOutput() { return mHeaderOutput; }
|
||||
LLIOPipe::buffer_ptr_t& getOutput() { return mOutput; }
|
||||
const LLChannelDescriptors& getChannels() { return mChannels; }
|
||||
|
||||
void resetState();
|
||||
|
||||
static CURL* allocEasyHandle();
|
||||
static void releaseEasyHandle(CURL* handle);
|
||||
|
||||
private:
|
||||
friend class LLCurl;
|
||||
friend class LLCurl::Multi;
|
||||
|
||||
CURL* mCurlEasyHandle;
|
||||
struct curl_slist* mHeaders;
|
||||
|
||||
std::stringstream mRequest;
|
||||
LLChannelDescriptors mChannels;
|
||||
LLIOPipe::buffer_ptr_t mOutput;
|
||||
std::stringstream mInput;
|
||||
std::stringstream mHeaderOutput;
|
||||
char mErrorBuffer[CURL_ERROR_SIZE];
|
||||
|
||||
// Note: char*'s not strings since we pass pointers to curl
|
||||
std::vector<char*> mStrings;
|
||||
|
||||
ResponderPtr mResponder;
|
||||
|
||||
static std::set<CURL*> sFreeHandles;
|
||||
static std::set<CURL*> sActiveHandles;
|
||||
static LLMutex* sHandleMutex;
|
||||
static LLMutex* sMultiMutex;
|
||||
};
|
||||
|
||||
class LLCurl::Multi : public LLThread
|
||||
{
|
||||
LOG_CLASS(Multi);
|
||||
public:
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PERFORM_STATE_READY=0,
|
||||
PERFORM_STATE_PERFORMING=1,
|
||||
PERFORM_STATE_COMPLETED=2
|
||||
} ePerformState;
|
||||
|
||||
Multi();
|
||||
~Multi();
|
||||
|
||||
Easy* allocEasy();
|
||||
bool addEasy(Easy* easy);
|
||||
|
||||
void removeEasy(Easy* easy);
|
||||
|
||||
S32 process();
|
||||
void perform();
|
||||
void doPerform();
|
||||
|
||||
virtual void run();
|
||||
|
||||
CURLMsg* info_read(S32* msgs_in_queue);
|
||||
|
||||
S32 mQueued;
|
||||
S32 mErrorCount;
|
||||
|
||||
S32 mPerformState;
|
||||
|
||||
LLCondition* mSignal;
|
||||
bool mQuitting;
|
||||
bool mThreaded;
|
||||
|
||||
private:
|
||||
void easyFree(Easy*);
|
||||
|
||||
CURLM* mCurlMultiHandle;
|
||||
|
||||
typedef std::set<Easy*> easy_active_list_t;
|
||||
easy_active_list_t mEasyActiveList;
|
||||
typedef std::map<CURL*, Easy*> easy_active_map_t;
|
||||
easy_active_map_t mEasyActiveMap;
|
||||
typedef std::set<Easy*> easy_free_list_t;
|
||||
easy_free_list_t mEasyFreeList;
|
||||
};
|
||||
|
||||
namespace boost
|
||||
{
|
||||
void intrusive_ptr_add_ref(LLCurl::Responder* p);
|
||||
void intrusive_ptr_release(LLCurl::Responder* p);
|
||||
};
|
||||
|
||||
|
||||
class LLCurlRequest
|
||||
{
|
||||
public:
|
||||
typedef std::vector<std::string> headers_t;
|
||||
|
||||
LLCurlRequest();
|
||||
~LLCurlRequest();
|
||||
|
||||
void get(const std::string& url, LLCurl::ResponderPtr responder);
|
||||
bool getByteRange(const std::string& url, const headers_t& headers, S32 offset, S32 length, LLCurl::ResponderPtr responder);
|
||||
bool post(const std::string& url, const headers_t& headers, const LLSD& data, LLCurl::ResponderPtr responder, S32 time_out = 0);
|
||||
bool post(const std::string& url, const headers_t& headers, const std::string& data, LLCurl::ResponderPtr responder, S32 time_out = 0);
|
||||
|
||||
S32 process();
|
||||
S32 getQueued();
|
||||
|
||||
private:
|
||||
void addMulti();
|
||||
LLCurl::Easy* allocEasy();
|
||||
bool addEasy(LLCurl::Easy* easy);
|
||||
|
||||
private:
|
||||
typedef std::set<LLCurl::Multi*> curlmulti_set_t;
|
||||
curlmulti_set_t mMultiSet;
|
||||
LLCurl::Multi* mActiveMulti;
|
||||
S32 mActiveRequestCount;
|
||||
BOOL mProcessing;
|
||||
U32 mThreadID; // debug
|
||||
};
|
||||
|
||||
class LLCurlEasyRequest
|
||||
{
|
||||
public:
|
||||
LLCurlEasyRequest();
|
||||
~LLCurlEasyRequest();
|
||||
void setopt(CURLoption option, S32 value);
|
||||
void setoptString(CURLoption option, const std::string& value);
|
||||
void setPost(char* postdata, S32 size);
|
||||
void setHeaderCallback(curl_header_callback callback, void* userdata);
|
||||
void setWriteCallback(curl_write_callback callback, void* userdata);
|
||||
void setReadCallback(curl_read_callback callback, void* userdata);
|
||||
void setSSLCtxCallback(curl_ssl_ctx_callback callback, void* userdata);
|
||||
void slist_append(const char* str);
|
||||
void sendRequest(const std::string& url);
|
||||
void requestComplete();
|
||||
void perform();
|
||||
bool getResult(CURLcode* result, LLCurl::TransferInfo* info = NULL);
|
||||
std::string getErrorString();
|
||||
|
||||
LLCurl::Easy* getEasy() const { return mEasy; }
|
||||
|
||||
private:
|
||||
CURLMsg* info_read(S32* queue, LLCurl::TransferInfo* info);
|
||||
|
||||
private:
|
||||
LLCurl::Multi* mMulti;
|
||||
LLCurl::Easy* mEasy;
|
||||
bool mRequestSent;
|
||||
bool mResultReturned;
|
||||
};
|
||||
|
||||
// Provide access to LLCurl free functions outside of llcurl.cpp without polluting the global namespace.
|
||||
namespace LLCurlFF
|
||||
{
|
||||
void check_easy_code(CURLcode code);
|
||||
void check_multi_code(CURLMcode code);
|
||||
}
|
||||
|
||||
#endif // LL_LLCURL_H
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#include "lldispatcher.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include "llstl.h"
|
||||
#include "message.h"
|
||||
|
||||
|
||||
@@ -80,7 +80,6 @@
|
||||
|
||||
#include "llbuffer.h"
|
||||
#include "llbufferstream.h"
|
||||
#include "llfasttimer.h"
|
||||
#include "llmemorystream.h"
|
||||
#include "llsd.h"
|
||||
#include "llsdserialize.h"
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
#include <openssl/x509_vfy.h>
|
||||
|
||||
#include "llhttpclient.h"
|
||||
|
||||
#include "llassetstorage.h"
|
||||
@@ -40,10 +40,8 @@
|
||||
#include "message.h"
|
||||
#include <curl/curl.h>
|
||||
|
||||
|
||||
const F32 HTTP_REQUEST_EXPIRY_SECS = 60.0f;
|
||||
LLURLRequest::SSLCertVerifyCallback LLHTTPClient::mCertVerifyCallback = NULL;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Responder class moved to LLCurl
|
||||
@@ -158,9 +156,9 @@ namespace
|
||||
if(fstream.is_open())
|
||||
{
|
||||
fstream.seekg(0, std::ios::end);
|
||||
U32 fileSize = fstream.tellg();
|
||||
U32 fileSize = (U32)fstream.tellg();
|
||||
fstream.seekg(0, std::ios::beg);
|
||||
std::vector<char> fileBuffer(fileSize);
|
||||
std::vector<char> fileBuffer(fileSize); //Mem leak fix'd
|
||||
fstream.read(&fileBuffer[0], fileSize);
|
||||
ostream.write(&fileBuffer[0], fileSize);
|
||||
fstream.close();
|
||||
@@ -189,11 +187,9 @@ namespace
|
||||
|
||||
LLVFile vfile(gVFS, mUUID, mAssetType, LLVFile::READ);
|
||||
S32 fileSize = vfile.getSize();
|
||||
U8* fileBuffer;
|
||||
fileBuffer = new U8 [fileSize];
|
||||
vfile.read(fileBuffer, fileSize);
|
||||
ostream.write((char*)fileBuffer, fileSize);
|
||||
delete [] fileBuffer;
|
||||
std::vector<U8> fileBuffer(fileSize);
|
||||
vfile.read(&fileBuffer[0], fileSize);
|
||||
ostream.write((char*)&fileBuffer[0], fileSize);
|
||||
eos = true;
|
||||
return STATUS_DONE;
|
||||
}
|
||||
@@ -202,7 +198,6 @@ namespace
|
||||
LLAssetType::EType mAssetType;
|
||||
};
|
||||
|
||||
|
||||
LLPumpIO* theClientPump = NULL;
|
||||
}
|
||||
|
||||
@@ -217,48 +212,22 @@ static void request(
|
||||
Injector* body_injector,
|
||||
LLCurl::ResponderPtr responder,
|
||||
const F32 timeout = HTTP_REQUEST_EXPIRY_SECS,
|
||||
const LLSD& headers = LLSD()
|
||||
)
|
||||
const LLSD& headers = LLSD())
|
||||
{
|
||||
if (responder)
|
||||
{
|
||||
// For possible debug output from within the responder.
|
||||
responder->setURL(url);
|
||||
}
|
||||
|
||||
if (!LLHTTPClient::hasPump())
|
||||
{
|
||||
responder->fatalError("No pump");
|
||||
responder->completed(U32_MAX, "No pump", LLSD());
|
||||
return;
|
||||
}
|
||||
LLPumpIO::chain_t chain;
|
||||
|
||||
LLURLRequest* req;
|
||||
try
|
||||
{
|
||||
req = new LLURLRequest(method, url);
|
||||
}
|
||||
catch(AICurlNoEasyHandle& error)
|
||||
{
|
||||
llwarns << "Failed to create LLURLRequest: " << error.what() << llendl;
|
||||
// This is what the old LL code did: no recovery whatsoever (but also no leaks or crash).
|
||||
return ;
|
||||
}
|
||||
LLURLRequest* req = new LLURLRequest(method, url);
|
||||
|
||||
req->setSSLVerifyCallback(LLHTTPClient::getCertVerifyCallback(), (void *)req);
|
||||
|
||||
|
||||
lldebugs << LLURLRequest::actionAsVerb(method) << " " << url << " "
|
||||
<< headers << llendl;
|
||||
|
||||
// Insert custom headers if the caller sent any
|
||||
if (headers.isMap())
|
||||
{
|
||||
if (headers.has("Cookie"))
|
||||
{
|
||||
req->allowCookies();
|
||||
}
|
||||
|
||||
// Insert custom headers is the caller sent any
|
||||
if (headers.isMap())
|
||||
{
|
||||
LLSD::map_const_iterator iter = headers.beginMap();
|
||||
LLSD::map_const_iterator end = headers.endMap();
|
||||
|
||||
@@ -293,6 +262,11 @@ static void request(
|
||||
}
|
||||
}
|
||||
|
||||
if (responder)
|
||||
{
|
||||
responder->setURL(url);
|
||||
}
|
||||
|
||||
req->setCallback(new LLHTTPClientURLAdaptor(responder));
|
||||
|
||||
if (method == LLURLRequest::HTTP_POST && gMessageSystem)
|
||||
@@ -339,7 +313,7 @@ void LLHTTPClient::getByteRange(
|
||||
std::string range = llformat("bytes=%d-%d", offset, offset+bytes-1);
|
||||
headers["Range"] = range;
|
||||
}
|
||||
request(url, LLURLRequest::HTTP_GET, NULL, responder, timeout, headers);
|
||||
request(url,LLURLRequest::HTTP_GET, NULL, responder, timeout, headers);
|
||||
}
|
||||
|
||||
void LLHTTPClient::head(
|
||||
@@ -378,12 +352,12 @@ class LLHTTPBuffer
|
||||
public:
|
||||
LLHTTPBuffer() { }
|
||||
|
||||
static size_t curl_write(char* ptr, size_t size, size_t nmemb, void* user_data)
|
||||
static size_t curl_write( void *ptr, size_t size, size_t nmemb, void *user_data)
|
||||
{
|
||||
LLHTTPBuffer* self = (LLHTTPBuffer*)user_data;
|
||||
|
||||
size_t bytes = (size * nmemb);
|
||||
self->mBuffer.append(ptr,bytes);
|
||||
self->mBuffer.append((char*)ptr,bytes);
|
||||
return nmemb;
|
||||
}
|
||||
|
||||
@@ -434,91 +408,99 @@ static LLSD blocking_request(
|
||||
)
|
||||
{
|
||||
lldebugs << "blockingRequest of " << url << llendl;
|
||||
char curl_error_buffer[CURL_ERROR_SIZE] = "\0";
|
||||
CURL* curlp = curl_easy_init();
|
||||
LLHTTPBuffer http_buffer;
|
||||
std::string body_str;
|
||||
|
||||
// other request method checks root cert first, we skip?
|
||||
|
||||
// * Set curl handle options
|
||||
curl_easy_setopt(curlp, CURLOPT_NOSIGNAL, 1); // don't use SIGALRM for timeouts
|
||||
curl_easy_setopt(curlp, CURLOPT_TIMEOUT, timeout); // seconds, see warning at top of function.
|
||||
curl_easy_setopt(curlp, CURLOPT_WRITEFUNCTION, LLHTTPBuffer::curl_write);
|
||||
curl_easy_setopt(curlp, CURLOPT_WRITEDATA, &http_buffer);
|
||||
curl_easy_setopt(curlp, CURLOPT_URL, url.c_str());
|
||||
curl_easy_setopt(curlp, CURLOPT_ERRORBUFFER, curl_error_buffer);
|
||||
|
||||
// * Setup headers (don't forget to free them after the call!)
|
||||
curl_slist* headers_list = NULL;
|
||||
if (headers.isMap())
|
||||
{
|
||||
LLSD::map_const_iterator iter = headers.beginMap();
|
||||
LLSD::map_const_iterator end = headers.endMap();
|
||||
for (; iter != end; ++iter)
|
||||
{
|
||||
std::ostringstream header;
|
||||
header << iter->first << ": " << iter->second.asString() ;
|
||||
lldebugs << "header = " << header.str() << llendl;
|
||||
headers_list = curl_slist_append(headers_list, header.str().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// * Setup specific method / "verb" for the URI (currently only GET and POST supported + poppy)
|
||||
if (method == LLURLRequest::HTTP_GET)
|
||||
{
|
||||
curl_easy_setopt(curlp, CURLOPT_HTTPGET, 1);
|
||||
}
|
||||
else if (method == LLURLRequest::HTTP_POST)
|
||||
{
|
||||
curl_easy_setopt(curlp, CURLOPT_POST, 1);
|
||||
//serialize to ostr then copy to str - need to because ostr ptr is unstable :(
|
||||
std::ostringstream ostr;
|
||||
LLSDSerialize::toXML(body, ostr);
|
||||
body_str = ostr.str();
|
||||
curl_easy_setopt(curlp, CURLOPT_POSTFIELDS, body_str.c_str());
|
||||
//copied from PHP libs, correct?
|
||||
headers_list = curl_slist_append(headers_list, "Content-Type: application/llsd+xml");
|
||||
|
||||
// copied from llurlrequest.cpp
|
||||
// it appears that apache2.2.3 or django in etch is busted. If
|
||||
// we do not clear the expect header, we get a 500. May be
|
||||
// limited to django/mod_wsgi.
|
||||
headers_list = curl_slist_append(headers_list, "Expect:");
|
||||
}
|
||||
|
||||
// * Do the action using curl, handle results
|
||||
lldebugs << "HTTP body: " << body_str << llendl;
|
||||
headers_list = curl_slist_append(headers_list, "Accept: application/llsd+xml");
|
||||
CURLcode curl_result = curl_easy_setopt(curlp, CURLOPT_HTTPHEADER, headers_list);
|
||||
if ( curl_result != CURLE_OK )
|
||||
{
|
||||
llinfos << "Curl is hosed - can't add headers" << llendl;
|
||||
}
|
||||
|
||||
S32 http_status = 499;
|
||||
LLSD response = LLSD::emptyMap();
|
||||
|
||||
try
|
||||
{
|
||||
AICurlEasyRequest easy_request(false);
|
||||
AICurlEasyRequest_wat curlEasyRequest_w(*easy_request);
|
||||
|
||||
LLHTTPBuffer http_buffer;
|
||||
std::string body_str;
|
||||
|
||||
// * Set curl handle options
|
||||
curlEasyRequest_w->setopt(CURLOPT_TIMEOUT, timeout); // seconds, see warning at top of function.
|
||||
curlEasyRequest_w->setWriteCallback(&LLHTTPBuffer::curl_write, &http_buffer);
|
||||
|
||||
// * Setup headers.
|
||||
if (headers.isMap())
|
||||
{
|
||||
LLSD::map_const_iterator iter = headers.beginMap();
|
||||
LLSD::map_const_iterator end = headers.endMap();
|
||||
for (; iter != end; ++iter)
|
||||
{
|
||||
std::ostringstream header;
|
||||
header << iter->first << ": " << iter->second.asString() ;
|
||||
lldebugs << "header = " << header.str() << llendl;
|
||||
curlEasyRequest_w->addHeader(header.str().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// * Setup specific method / "verb" for the URI (currently only GET and POST supported + poppy)
|
||||
if (method == LLURLRequest::HTTP_GET)
|
||||
{
|
||||
curlEasyRequest_w->setopt(CURLOPT_HTTPGET, 1);
|
||||
}
|
||||
else if (method == LLURLRequest::HTTP_POST)
|
||||
{
|
||||
curlEasyRequest_w->setopt(CURLOPT_POST, 1);
|
||||
//serialize to ostr then copy to str - need to because ostr ptr is unstable :(
|
||||
std::ostringstream ostr;
|
||||
LLSDSerialize::toXML(body, ostr);
|
||||
body_str = ostr.str();
|
||||
curlEasyRequest_w->setopt(CURLOPT_POSTFIELDS, body_str.c_str());
|
||||
//copied from PHP libs, correct?
|
||||
curlEasyRequest_w->addHeader("Content-Type: application/llsd+xml");
|
||||
|
||||
// copied from llurlrequest.cpp
|
||||
// it appears that apache2.2.3 or django in etch is busted. If
|
||||
// we do not clear the expect header, we get a 500. May be
|
||||
// limited to django/mod_wsgi.
|
||||
curlEasyRequest_w->addHeader("Expect:");
|
||||
}
|
||||
|
||||
// * Do the action using curl, handle results
|
||||
lldebugs << "HTTP body: " << body_str << llendl;
|
||||
curlEasyRequest_w->addHeader("Accept: application/llsd+xml");
|
||||
curlEasyRequest_w->finalizeRequest(url);
|
||||
|
||||
S32 curl_success = curlEasyRequest_w->perform();
|
||||
curlEasyRequest_w->getinfo(CURLINFO_RESPONSE_CODE, &http_status);
|
||||
// if we get a non-404 and it's not a 200 OR maybe it is but you have error bits,
|
||||
if ( http_status != 404 && (http_status != 200 || curl_success != 0) )
|
||||
{
|
||||
// We expect 404s, don't spam for them.
|
||||
llwarns << "CURL REQ URL: " << url << llendl;
|
||||
llwarns << "CURL REQ METHOD TYPE: " << method << llendl;
|
||||
llwarns << "CURL REQ HEADERS: " << headers.asString() << llendl;
|
||||
llwarns << "CURL REQ BODY: " << body_str << llendl;
|
||||
llwarns << "CURL HTTP_STATUS: " << http_status << llendl;
|
||||
llwarns << "CURL ERROR: " << curlEasyRequest_w->getErrorString() << llendl;
|
||||
llwarns << "CURL ERROR BODY: " << http_buffer.asString() << llendl;
|
||||
response["body"] = http_buffer.asString();
|
||||
}
|
||||
else
|
||||
{
|
||||
response["body"] = http_buffer.asLLSD();
|
||||
lldebugs << "CURL response: " << http_buffer.asString() << llendl;
|
||||
}
|
||||
}
|
||||
catch(AICurlNoEasyHandle const& error)
|
||||
{
|
||||
response["body"] = error.what();
|
||||
}
|
||||
|
||||
S32 curl_success = curl_easy_perform(curlp);
|
||||
S32 http_status = 499;
|
||||
curl_easy_getinfo(curlp, CURLINFO_RESPONSE_CODE, &http_status);
|
||||
response["status"] = http_status;
|
||||
// if we get a non-404 and it's not a 200 OR maybe it is but you have error bits,
|
||||
if ( http_status != 404 && (http_status != 200 || curl_success != 0) )
|
||||
{
|
||||
// We expect 404s, don't spam for them.
|
||||
llwarns << "CURL REQ URL: " << url << llendl;
|
||||
llwarns << "CURL REQ METHOD TYPE: " << method << llendl;
|
||||
llwarns << "CURL REQ HEADERS: " << headers.asString() << llendl;
|
||||
llwarns << "CURL REQ BODY: " << body_str << llendl;
|
||||
llwarns << "CURL HTTP_STATUS: " << http_status << llendl;
|
||||
llwarns << "CURL ERROR: " << curl_error_buffer << llendl;
|
||||
llwarns << "CURL ERROR BODY: " << http_buffer.asString() << llendl;
|
||||
response["body"] = http_buffer.asString();
|
||||
}
|
||||
else
|
||||
{
|
||||
response["body"] = http_buffer.asLLSD();
|
||||
lldebugs << "CURL response: " << http_buffer.asString() << llendl;
|
||||
}
|
||||
|
||||
if(headers_list)
|
||||
{ // free the header list
|
||||
curl_slist_free_all(headers_list);
|
||||
}
|
||||
|
||||
// * Cleanup
|
||||
curl_easy_cleanup(curlp);
|
||||
return response;
|
||||
}
|
||||
|
||||
@@ -618,8 +600,7 @@ bool LLHTTPClient::hasPump()
|
||||
return theClientPump != NULL;
|
||||
}
|
||||
|
||||
//static
|
||||
LLPumpIO& LLHTTPClient::getPump()
|
||||
LLPumpIO &LLHTTPClient::getPump()
|
||||
{
|
||||
return *theClientPump;
|
||||
}
|
||||
|
||||
@@ -34,10 +34,11 @@
|
||||
#include <string>
|
||||
|
||||
#include <boost/intrusive_ptr.hpp>
|
||||
#include "llurlrequest.h"
|
||||
|
||||
#include "llassettype.h"
|
||||
#include "llcurl.h"
|
||||
#include "lliopipe.h"
|
||||
#include "llurlrequest.h"
|
||||
|
||||
extern const F32 HTTP_REQUEST_EXPIRY_SECS;
|
||||
|
||||
@@ -55,9 +56,6 @@ public:
|
||||
typedef LLCurl::Responder Responder;
|
||||
typedef LLCurl::ResponderPtr ResponderPtr;
|
||||
|
||||
// The default actually already ignores responses.
|
||||
class ResponderIgnore : public Responder { };
|
||||
|
||||
/** @name non-blocking API */
|
||||
//@{
|
||||
static void head(
|
||||
@@ -157,7 +155,7 @@ public:
|
||||
///< Hippo special
|
||||
|
||||
static void setCertVerifyCallback(LLURLRequest::SSLCertVerifyCallback callback);
|
||||
static LLURLRequest::SSLCertVerifyCallback getCertVerifyCallback() { return mCertVerifyCallback; }
|
||||
static LLURLRequest::SSLCertVerifyCallback getCertVerifyCallback() { return mCertVerifyCallback; }
|
||||
|
||||
protected:
|
||||
static LLURLRequest::SSLCertVerifyCallback mCertVerifyCallback;
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
#include "llapr.h"
|
||||
#include "llbuffer.h"
|
||||
#include "llbufferstream.h"
|
||||
#include "llfasttimer.h"
|
||||
#include "llhttpnode.h"
|
||||
#include "lliopipe.h"
|
||||
#include "lliosocket.h"
|
||||
|
||||
@@ -76,14 +76,7 @@ LLIOPipe::~LLIOPipe()
|
||||
}
|
||||
|
||||
//virtual
|
||||
bool LLIOPipe::hasExpiration(void) const
|
||||
{
|
||||
// LLIOPipe::hasNotExpired always returns true.
|
||||
return false;
|
||||
}
|
||||
|
||||
//virtual
|
||||
bool LLIOPipe::hasNotExpired(void) const
|
||||
bool LLIOPipe::isValid()
|
||||
{
|
||||
return true ;
|
||||
}
|
||||
|
||||
@@ -149,7 +149,7 @@ public:
|
||||
// The connection was lost.
|
||||
STATUS_LOST_CONNECTION = -5,
|
||||
|
||||
// The total process time has exceeded the timeout.
|
||||
// The totoal process time has exceeded the timeout.
|
||||
STATUS_EXPIRED = -6,
|
||||
|
||||
// Keep track of the count of codes here.
|
||||
@@ -231,16 +231,7 @@ public:
|
||||
*/
|
||||
virtual ~LLIOPipe();
|
||||
|
||||
/**
|
||||
* @brief External expiration facility.
|
||||
*
|
||||
* If hasExpiration() returns true, then we need to check hasNotExpired()
|
||||
* to see if the LLIOPipe is still valid. In the legacy LL code the
|
||||
* latter was called isValid() and was overloaded for two purposes:
|
||||
* either expiration or failure to initialize.
|
||||
*/
|
||||
virtual bool hasExpiration(void) const;
|
||||
virtual bool hasNotExpired(void) const;
|
||||
virtual bool isValid() ;
|
||||
|
||||
protected:
|
||||
/**
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
#include "llapr.h"
|
||||
|
||||
#include "llbuffer.h"
|
||||
#include "llfasttimer.h"
|
||||
#include "llhost.h"
|
||||
#include "llmemtype.h"
|
||||
#include "llpumpio.h"
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
* OS poll indicates it will not block.
|
||||
*/
|
||||
|
||||
#include "llaprpool.h"
|
||||
#include "lliopipe.h"
|
||||
#include "apr_network_io.h"
|
||||
#include "llchainio.h"
|
||||
|
||||
@@ -27,8 +27,8 @@
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "llfasttimer.h"
|
||||
#include "llioutil.h"
|
||||
#include "llfasttimer.h"
|
||||
|
||||
/**
|
||||
* LLIOFlush
|
||||
|
||||
@@ -50,7 +50,6 @@
|
||||
#include "llstring.h"
|
||||
#include "lluuid.h"
|
||||
#include "net.h"
|
||||
#include "llaprpool.h"
|
||||
|
||||
//
|
||||
// constants
|
||||
@@ -58,7 +57,7 @@
|
||||
const size_t LL_MAX_KNOWN_GOOD_MAIL_SIZE = 4096;
|
||||
|
||||
static bool gMailEnabled = true;
|
||||
static LLAPRPool gMailPool;
|
||||
static apr_pool_t* gMailPool;
|
||||
static apr_sockaddr_t* gSockAddr;
|
||||
static apr_socket_t* gMailSocket;
|
||||
|
||||
@@ -83,7 +82,7 @@ bool connect_smtp()
|
||||
gSockAddr->sa.sin.sin_family,
|
||||
SOCK_STREAM,
|
||||
APR_PROTO_TCP,
|
||||
gMailPool());
|
||||
gMailPool);
|
||||
if(ll_apr_warn_status(status)) return false;
|
||||
status = apr_socket_connect(gMailSocket, gSockAddr);
|
||||
if(ll_apr_warn_status(status))
|
||||
@@ -140,19 +139,19 @@ BOOL LLMail::send(
|
||||
}
|
||||
|
||||
// static
|
||||
void LLMail::init(const std::string& hostname)
|
||||
void LLMail::init(const std::string& hostname, apr_pool_t* pool)
|
||||
{
|
||||
gMailSocket = NULL;
|
||||
if (hostname.empty())
|
||||
if(hostname.empty() || !pool)
|
||||
{
|
||||
gMailPool = NULL;
|
||||
gSockAddr = NULL;
|
||||
gMailPool.destroy();
|
||||
}
|
||||
else
|
||||
{
|
||||
gMailPool.create();
|
||||
gMailPool = pool;
|
||||
|
||||
// Collect all the information into a sockaddr structure. the
|
||||
// collect all the information into a socaddr sturcture. the
|
||||
// documentation is a bit unclear, but I either have to
|
||||
// specify APR_UNSPEC or not specify any flags. I am not sure
|
||||
// which option is better.
|
||||
@@ -162,7 +161,7 @@ void LLMail::init(const std::string& hostname)
|
||||
APR_UNSPEC,
|
||||
25,
|
||||
APR_IPV4_ADDR_OK,
|
||||
gMailPool());
|
||||
gMailPool);
|
||||
ll_apr_warn_status(status);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,13 +27,15 @@
|
||||
#ifndef LL_LLMAIL_H
|
||||
#define LL_LLMAIL_H
|
||||
|
||||
typedef struct apr_pool_t apr_pool_t;
|
||||
|
||||
#include "llsd.h"
|
||||
|
||||
class LLMail
|
||||
{
|
||||
public:
|
||||
// if hostname is NULL, then the host is resolved as 'mail'
|
||||
static void init(const std::string& hostname);
|
||||
static void init(const std::string& hostname, apr_pool_t* pool);
|
||||
|
||||
// Allow all email transmission to be disabled/enabled.
|
||||
static void enable(bool mail_enabled);
|
||||
|
||||
@@ -388,7 +388,7 @@ bool LLMimeParser::Impl::parseHeaders(
|
||||
// not to read past limit when we get() the newline.
|
||||
S32 max_get = llmin((S32)LINE_BUFFER_LENGTH, limit - mScanCount - 1);
|
||||
istr.getline(mBuffer, max_get, '\r');
|
||||
mScanCount += istr.gcount();
|
||||
mScanCount += (S32)istr.gcount();
|
||||
int c = istr.get();
|
||||
if(EOF == c)
|
||||
{
|
||||
@@ -496,7 +496,7 @@ void LLMimeParser::Impl::scanPastSeparator(
|
||||
// past limit when we get() the newline.
|
||||
S32 max_get = llmin((S32)LINE_BUFFER_LENGTH, limit - mScanCount - 1);
|
||||
istr.getline(mBuffer, max_get, '\r');
|
||||
mScanCount += istr.gcount();
|
||||
mScanCount += (S32)istr.gcount();
|
||||
if(istr.gcount() >= LINE_BUFFER_LENGTH - 1)
|
||||
{
|
||||
// that's way too long to be a separator, so ignore it.
|
||||
|
||||
@@ -47,22 +47,23 @@ static apr_status_t tcp_blocking_handshake(LLSocket::ptr_t handle, char * dataou
|
||||
static LLSocket::ptr_t tcp_open_channel(LLHost host); // Open a TCP channel to a given host
|
||||
static void tcp_close_channel(LLSocket::ptr_t* handle_ptr); // Close an open TCP channel
|
||||
|
||||
ProxyShared::ProxyShared(void):
|
||||
mProxyType(LLPROXY_SOCKS),
|
||||
mAuthMethodSelected(METHOD_NOAUTH)
|
||||
{
|
||||
}
|
||||
|
||||
LLProxy::LLProxy():
|
||||
mHTTPProxyEnabled(false)
|
||||
mHTTPProxyEnabled(false),
|
||||
mProxyMutex(),
|
||||
mUDPProxy(),
|
||||
mTCPProxy(),
|
||||
mHTTPProxy(),
|
||||
mProxyType(LLPROXY_SOCKS),
|
||||
mAuthMethodSelected(METHOD_NOAUTH),
|
||||
mSocksUsername(),
|
||||
mSocksPassword()
|
||||
{
|
||||
}
|
||||
|
||||
LLProxy::~LLProxy()
|
||||
{
|
||||
stopSOCKSProxy();
|
||||
Shared_wat shared_w(mShared);
|
||||
disableHTTPProxy(shared_w);
|
||||
disableHTTPProxy();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -77,18 +78,15 @@ S32 LLProxy::proxyHandshake(LLHost proxy)
|
||||
{
|
||||
S32 result;
|
||||
|
||||
Unshared_rat unshared_r(mUnshared);
|
||||
Shared_rat shared_r(mShared);
|
||||
|
||||
/* SOCKS 5 Auth request */
|
||||
socks_auth_request_t socks_auth_request;
|
||||
socks_auth_response_t socks_auth_response;
|
||||
|
||||
socks_auth_request.version = SOCKS_VERSION; // SOCKS version 5
|
||||
socks_auth_request.num_methods = 1; // Sending 1 method.
|
||||
socks_auth_request.methods = getSelectedAuthMethod(shared_r); // Send only the selected method.
|
||||
socks_auth_request.methods = getSelectedAuthMethod(); // Send only the selected method.
|
||||
|
||||
result = tcp_blocking_handshake(unshared_r->mProxyControlChannel,
|
||||
result = tcp_blocking_handshake(mProxyControlChannel,
|
||||
static_cast<char*>(static_cast<void*>(&socks_auth_request)),
|
||||
sizeof(socks_auth_request),
|
||||
static_cast<char*>(static_cast<void*>(&socks_auth_response)),
|
||||
@@ -111,8 +109,8 @@ S32 LLProxy::proxyHandshake(LLHost proxy)
|
||||
if (socks_auth_response.method == METHOD_PASSWORD)
|
||||
{
|
||||
// The server has requested a username/password combination
|
||||
std::string socks_username(getSocksUser(shared_r));
|
||||
std::string socks_password(getSocksPwd(shared_r));
|
||||
std::string socks_username(getSocksUser());
|
||||
std::string socks_password(getSocksPwd());
|
||||
U32 request_size = socks_username.size() + socks_password.size() + 3;
|
||||
char * password_auth = new char[request_size];
|
||||
password_auth[0] = 0x01;
|
||||
@@ -123,7 +121,7 @@ S32 LLProxy::proxyHandshake(LLHost proxy)
|
||||
|
||||
authmethod_password_reply_t password_reply;
|
||||
|
||||
result = tcp_blocking_handshake(unshared_r->mProxyControlChannel,
|
||||
result = tcp_blocking_handshake(mProxyControlChannel,
|
||||
password_auth,
|
||||
request_size,
|
||||
static_cast<char*>(static_cast<void*>(&password_reply)),
|
||||
@@ -159,7 +157,7 @@ S32 LLProxy::proxyHandshake(LLHost proxy)
|
||||
// "If the client is not in possession of the information at the time of the UDP ASSOCIATE,
|
||||
// the client MUST use a port number and address of all zeros. RFC 1928"
|
||||
|
||||
result = tcp_blocking_handshake(unshared_r->mProxyControlChannel,
|
||||
result = tcp_blocking_handshake(mProxyControlChannel,
|
||||
static_cast<char*>(static_cast<void*>(&connect_request)),
|
||||
sizeof(connect_request),
|
||||
static_cast<char*>(static_cast<void*>(&connect_reply)),
|
||||
@@ -178,14 +176,10 @@ S32 LLProxy::proxyHandshake(LLHost proxy)
|
||||
return SOCKS_UDP_FWD_NOT_GRANTED;
|
||||
}
|
||||
|
||||
{
|
||||
// Write access type and read access type are really the same, so unshared_w must be simply a reference.
|
||||
Unshared_wat& unshared_w = unshared_r;
|
||||
unshared_w->mUDPProxy.setPort(ntohs(connect_reply.port)); // reply port is in network byte order
|
||||
unshared_w->mUDPProxy.setAddress(proxy.getAddress());
|
||||
}
|
||||
mUDPProxy.setPort(ntohs(connect_reply.port)); // reply port is in network byte order
|
||||
mUDPProxy.setAddress(proxy.getAddress());
|
||||
// The connection was successful. We now have the UDP port to send requests that need forwarding to.
|
||||
LL_INFOS("Proxy") << "SOCKS 5 UDP proxy connected on " << unshared_r->mUDPProxy << LL_ENDL;
|
||||
LL_INFOS("Proxy") << "SOCKS 5 UDP proxy connected on " << mUDPProxy << LL_ENDL;
|
||||
|
||||
return SOCKS_OK;
|
||||
}
|
||||
@@ -203,11 +197,9 @@ S32 LLProxy::proxyHandshake(LLHost proxy)
|
||||
*/
|
||||
S32 LLProxy::startSOCKSProxy(LLHost host)
|
||||
{
|
||||
Unshared_wat unshared_w(mUnshared);
|
||||
|
||||
if (host.isOk())
|
||||
{
|
||||
unshared_w->mTCPProxy = host;
|
||||
mTCPProxy = host;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -217,13 +209,13 @@ S32 LLProxy::startSOCKSProxy(LLHost host)
|
||||
// Close any running SOCKS connection.
|
||||
stopSOCKSProxy();
|
||||
|
||||
unshared_w->mProxyControlChannel = tcp_open_channel(unshared_w->mTCPProxy);
|
||||
if (!unshared_w->mProxyControlChannel)
|
||||
mProxyControlChannel = tcp_open_channel(mTCPProxy);
|
||||
if (!mProxyControlChannel)
|
||||
{
|
||||
return SOCKS_HOST_CONNECT_FAILED;
|
||||
}
|
||||
|
||||
S32 status = proxyHandshake(unshared_w->mTCPProxy);
|
||||
S32 status = proxyHandshake(mTCPProxy);
|
||||
|
||||
if (status != SOCKS_OK)
|
||||
{
|
||||
@@ -254,16 +246,14 @@ void LLProxy::stopSOCKSProxy()
|
||||
// then we must shut down any HTTP proxy operations. But it is allowable if web
|
||||
// proxy is being used to continue proxying HTTP.
|
||||
|
||||
Shared_rat shared_r(mShared);
|
||||
if (LLPROXY_SOCKS == getHTTPProxyType(shared_r))
|
||||
if (LLPROXY_SOCKS == getHTTPProxyType())
|
||||
{
|
||||
Shared_wat shared_w(shared_r);
|
||||
disableHTTPProxy(shared_w);
|
||||
disableHTTPProxy();
|
||||
}
|
||||
Unshared_wat unshared_w(mUnshared);
|
||||
if (unshared_w->mProxyControlChannel)
|
||||
|
||||
if (mProxyControlChannel)
|
||||
{
|
||||
tcp_close_channel(&unshared_w->mProxyControlChannel);
|
||||
tcp_close_channel(&mProxyControlChannel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,7 +262,9 @@ void LLProxy::stopSOCKSProxy()
|
||||
*/
|
||||
void LLProxy::setAuthNone()
|
||||
{
|
||||
Shared_wat(mShared)->mAuthMethodSelected = METHOD_NOAUTH;
|
||||
LLMutexLock lock(&mProxyMutex);
|
||||
|
||||
mAuthMethodSelected = METHOD_NOAUTH;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -296,10 +288,11 @@ bool LLProxy::setAuthPassword(const std::string &username, const std::string &pa
|
||||
return false;
|
||||
}
|
||||
|
||||
Shared_wat shared_w(mShared);
|
||||
shared_w->mAuthMethodSelected = METHOD_PASSWORD;
|
||||
shared_w->mSocksUsername = username;
|
||||
shared_w->mSocksPassword = password;
|
||||
LLMutexLock lock(&mProxyMutex);
|
||||
|
||||
mAuthMethodSelected = METHOD_PASSWORD;
|
||||
mSocksUsername = username;
|
||||
mSocksPassword = password;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -321,10 +314,12 @@ bool LLProxy::enableHTTPProxy(LLHost httpHost, LLHttpProxyType type)
|
||||
return false;
|
||||
}
|
||||
|
||||
Shared_wat shared_w(mShared);
|
||||
LLMutexLock lock(&mProxyMutex);
|
||||
|
||||
mHTTPProxy = httpHost;
|
||||
mProxyType = type;
|
||||
|
||||
mHTTPProxyEnabled = true;
|
||||
shared_w->mHTTPProxy = httpHost;
|
||||
shared_w->mProxyType = type;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -340,8 +335,9 @@ bool LLProxy::enableHTTPProxy()
|
||||
{
|
||||
bool ok;
|
||||
|
||||
Shared_rat shared_r(mShared);
|
||||
ok = (shared_r->mHTTPProxy.isOk());
|
||||
LLMutexLock lock(&mProxyMutex);
|
||||
|
||||
ok = (mHTTPProxy.isOk());
|
||||
if (ok)
|
||||
{
|
||||
mHTTPProxyEnabled = true;
|
||||
@@ -350,6 +346,54 @@ bool LLProxy::enableHTTPProxy()
|
||||
return ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable the HTTP proxy.
|
||||
*/
|
||||
void LLProxy::disableHTTPProxy()
|
||||
{
|
||||
LLMutexLock lock(&mProxyMutex);
|
||||
|
||||
mHTTPProxyEnabled = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the currently selected HTTP proxy type
|
||||
*/
|
||||
LLHttpProxyType LLProxy::getHTTPProxyType() const
|
||||
{
|
||||
LLMutexLock lock(&mProxyMutex);
|
||||
return mProxyType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the SOCKS 5 password.
|
||||
*/
|
||||
std::string LLProxy::getSocksPwd() const
|
||||
{
|
||||
LLMutexLock lock(&mProxyMutex);
|
||||
return mSocksPassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the SOCKS 5 username.
|
||||
*/
|
||||
std::string LLProxy::getSocksUser() const
|
||||
{
|
||||
LLMutexLock lock(&mProxyMutex);
|
||||
return mSocksUsername;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the currently selected SOCKS 5 authentication method.
|
||||
*
|
||||
* @return Returns either none or password.
|
||||
*/
|
||||
LLSocks5AuthType LLProxy::getSelectedAuthMethod() const
|
||||
{
|
||||
LLMutexLock lock(&mProxyMutex);
|
||||
return mAuthMethodSelected;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stop the LLProxy and make certain that any APR pools and classes are deleted before terminating APR.
|
||||
*
|
||||
@@ -362,6 +406,57 @@ void LLProxy::cleanupClass()
|
||||
deleteSingleton();
|
||||
}
|
||||
|
||||
void LLProxy::applyProxySettings(LLCurlEasyRequest* handle)
|
||||
{
|
||||
applyProxySettings(handle->getEasy());
|
||||
}
|
||||
|
||||
void LLProxy::applyProxySettings(LLCurl::Easy* handle)
|
||||
{
|
||||
applyProxySettings(handle->getCurlHandle());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Apply proxy settings to a CuRL request if an HTTP proxy is enabled.
|
||||
*
|
||||
* This method has been designed to be safe to call from
|
||||
* any thread in the viewer. This allows requests in the
|
||||
* texture fetch thread to be aware of the proxy settings.
|
||||
* When the HTTP proxy is enabled, the proxy mutex will
|
||||
* be locked every time this method is called.
|
||||
*
|
||||
* @param handle A pointer to a valid CURL request, before it has been performed.
|
||||
*/
|
||||
void LLProxy::applyProxySettings(CURL* handle)
|
||||
{
|
||||
// Do a faster unlocked check to see if we are supposed to proxy.
|
||||
if (mHTTPProxyEnabled)
|
||||
{
|
||||
// We think we should proxy, lock the proxy mutex.
|
||||
LLMutexLock lock(&mProxyMutex);
|
||||
// Now test again to verify that the proxy wasn't disabled between the first check and the lock.
|
||||
if (mHTTPProxyEnabled)
|
||||
{
|
||||
LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXY, mHTTPProxy.getIPString().c_str()));
|
||||
LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXYPORT, mHTTPProxy.getPort()));
|
||||
|
||||
if (mProxyType == LLPROXY_SOCKS)
|
||||
{
|
||||
LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5));
|
||||
if (mAuthMethodSelected == METHOD_PASSWORD)
|
||||
{
|
||||
std::string auth_string = mSocksUsername + ":" + mSocksPassword;
|
||||
LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXYUSERPWD, auth_string.c_str()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Send one TCP packet and receive one in return.
|
||||
*
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
#include "llmemory.h"
|
||||
#include "llsingleton.h"
|
||||
#include "llthread.h"
|
||||
#include "aithreadsafe.h"
|
||||
#include <string>
|
||||
|
||||
// SOCKS error codes returned from the StartProxy method
|
||||
@@ -207,92 +206,41 @@ enum LLSocks5AuthType
|
||||
* The implementation of HTTP proxying is handled by libcurl. LLProxy
|
||||
* is responsible for managing the HTTP proxy options and provides a
|
||||
* thread-safe method to apply those options to a curl request
|
||||
* (LLProxy::applyProxySettings()).
|
||||
* (LLProxy::applyProxySettings()). This method is overloaded
|
||||
* to accommodate the various abstraction libcurl layers that exist
|
||||
* throughout the viewer (LLCurlEasyRequest, LLCurl::Easy, and CURL).
|
||||
*
|
||||
* If you are working with LLCurl or LLCurlEasyRequest objects,
|
||||
* the configured proxy settings will be applied in the constructors
|
||||
* of those request handles. If you are working with CURL objects
|
||||
* directly, you will need to pass the handle of the request to
|
||||
* applyProxySettings() before issuing the request.
|
||||
*
|
||||
* To ensure thread safety, all LLProxy members that relate to the HTTP
|
||||
* proxy require the LLProxyMutex to be locked before accessing.
|
||||
*/
|
||||
|
||||
struct ProxyUnshared
|
||||
{
|
||||
/*###########################################################################################
|
||||
MEMBERS READ AND WRITTEN ONLY IN THE MAIN THREAD.
|
||||
###########################################################################################*/
|
||||
|
||||
// UDP proxy address and port
|
||||
LLHost mUDPProxy;
|
||||
|
||||
// TCP proxy control channel address and port
|
||||
LLHost mTCPProxy;
|
||||
|
||||
// socket handle to proxy TCP control channel
|
||||
LLSocket::ptr_t mProxyControlChannel;
|
||||
|
||||
/*###########################################################################################
|
||||
END OF UNSHARED MEMBERS
|
||||
###########################################################################################*/
|
||||
};
|
||||
|
||||
struct ProxyShared
|
||||
{
|
||||
ProxyShared(void);
|
||||
|
||||
/*###########################################################################################
|
||||
MEMBERS WRITTEN IN MAIN THREAD AND READ IN ANY THREAD.
|
||||
###########################################################################################*/
|
||||
|
||||
// HTTP proxy address and port
|
||||
LLHost mHTTPProxy;
|
||||
|
||||
// Currently selected HTTP proxy type. Can be web or SOCKS.
|
||||
LLHttpProxyType mProxyType;
|
||||
|
||||
// SOCKS 5 selected authentication method.
|
||||
LLSocks5AuthType mAuthMethodSelected;
|
||||
|
||||
// SOCKS 5 username
|
||||
std::string mSocksUsername;
|
||||
// SOCKS 5 password
|
||||
std::string mSocksPassword;
|
||||
|
||||
/*###########################################################################################
|
||||
END OF SHARED MEMBERS
|
||||
###########################################################################################*/
|
||||
};
|
||||
|
||||
class LLProxy: public LLSingleton<LLProxy>
|
||||
{
|
||||
LOG_CLASS(LLProxy);
|
||||
|
||||
public:
|
||||
typedef AISTAccessConst<ProxyUnshared> Unshared_crat; // Constant Read Access Type for Unshared (cannot be converted to write access).
|
||||
typedef AISTAccess<ProxyUnshared> Unshared_rat; // Read Access Type for Unshared (same as write access type, since we don't lock at all).
|
||||
typedef AISTAccess<ProxyUnshared> Unshared_wat; // Write Access Type, for Unshared.
|
||||
typedef AIReadAccessConst<ProxyShared> Shared_crat; // Constant Read Access Type for Shared (cannot be converted to write access).
|
||||
typedef AIReadAccess<ProxyShared> Shared_rat; // Read Access Type for Shared.
|
||||
typedef AIWriteAccess<ProxyShared> Shared_wat; // Write Access Type for Shared.
|
||||
|
||||
/*###########################################################################################
|
||||
Public methods that only access variables not shared between threads.
|
||||
METHODS THAT DO NOT LOCK mProxyMutex!
|
||||
###########################################################################################*/
|
||||
// Constructor, cannot have parameters due to LLSingleton parent class. Call from main thread only.
|
||||
LLProxy();
|
||||
|
||||
// Static check for enabled status for UDP packets. Called from main thread only.
|
||||
static bool isSOCKSProxyEnabled(void) { llassert(is_main_thread()); return sUDPProxyEnabled; }
|
||||
// Static check for enabled status for UDP packets. Call from main thread only.
|
||||
static bool isSOCKSProxyEnabled() { return sUDPProxyEnabled; }
|
||||
|
||||
// Get the UDP proxy address and port. Called from main thread only.
|
||||
LLHost getUDPProxy(void) const { return Unshared_crat(mUnshared)->mUDPProxy; }
|
||||
// Get the UDP proxy address and port. Call from main thread only.
|
||||
LLHost getUDPProxy() const { return mUDPProxy; }
|
||||
|
||||
/*###########################################################################################
|
||||
End of methods that only access variables not shared between threads.
|
||||
END OF NON-LOCKING METHODS
|
||||
###########################################################################################*/
|
||||
|
||||
// Return true if there is a good chance that the HTTP proxy is currently enabled.
|
||||
bool HTTPProxyEnabled(void) const { return mHTTPProxyEnabled; }
|
||||
|
||||
/*###########################################################################################
|
||||
Public methods that access variables shared between threads.
|
||||
METHODS THAT LOCK mProxyMutex! DO NOT CALL WHILE mProxyMutex IS LOCKED!
|
||||
###########################################################################################*/
|
||||
// Destructor, closes open connections. Do not call directly, use cleanupClass().
|
||||
~LLProxy();
|
||||
@@ -303,7 +251,9 @@ public:
|
||||
|
||||
// Apply the current proxy settings to a curl request. Doesn't do anything if mHTTPProxyEnabled is false.
|
||||
// Safe to call from any thread.
|
||||
void applyProxySettings(AICurlEasyRequest_wat const& curlEasyRequest_w);
|
||||
void applyProxySettings(CURL* handle);
|
||||
void applyProxySettings(LLCurl::Easy* handle);
|
||||
void applyProxySettings(LLCurlEasyRequest* handle);
|
||||
|
||||
// Start a connection to the SOCKS 5 proxy. Call from main thread only.
|
||||
S32 startSOCKSProxy(LLHost host);
|
||||
@@ -323,37 +273,30 @@ public:
|
||||
bool enableHTTPProxy();
|
||||
|
||||
// Stop proxying HTTP packets. Call from main thread only.
|
||||
// Note that this needs shared_w to be passed because we want the shared members to be locked when this is reset to false.
|
||||
void disableHTTPProxy(Shared_wat const& shared_w) { mHTTPProxyEnabled = false; }
|
||||
void disableHTTPProxy(void) { disableHTTPProxy(Shared_wat(mShared)); }
|
||||
|
||||
// Get the currently selected HTTP proxy address and port
|
||||
LLHost const& getHTTPProxy(Shared_crat const& shared_r) const { return shared_r->mHTTPProxy; }
|
||||
|
||||
// Get the currently selected HTTP proxy type
|
||||
LLHttpProxyType getHTTPProxyType(Shared_crat const& shared_r) const { return shared_r->mProxyType; }
|
||||
|
||||
// Get the currently selected auth method.
|
||||
LLSocks5AuthType getSelectedAuthMethod(Shared_crat const& shared_r) const { return shared_r->mAuthMethodSelected; }
|
||||
|
||||
// SOCKS 5 username and password accessors.
|
||||
std::string getSocksUser(Shared_crat const& shared_r) const { return shared_r->mSocksUsername; }
|
||||
std::string getSocksPwd(Shared_crat const& shared_r) const { return shared_r->mSocksPassword; }
|
||||
void disableHTTPProxy();
|
||||
|
||||
/*###########################################################################################
|
||||
End of methods that access variables shared between threads.
|
||||
END OF LOCKING METHODS
|
||||
###########################################################################################*/
|
||||
|
||||
private:
|
||||
/*###########################################################################################
|
||||
Private methods that access variables shared between threads.
|
||||
METHODS THAT LOCK mProxyMutex! DO NOT CALL WHILE mProxyMutex IS LOCKED!
|
||||
###########################################################################################*/
|
||||
|
||||
// Perform a SOCKS 5 authentication and UDP association with the proxy server.
|
||||
S32 proxyHandshake(LLHost proxy);
|
||||
|
||||
// Get the currently selected auth method.
|
||||
LLSocks5AuthType getSelectedAuthMethod() const;
|
||||
|
||||
// Get the currently selected HTTP proxy type
|
||||
LLHttpProxyType getHTTPProxyType() const;
|
||||
|
||||
std::string getSocksPwd() const;
|
||||
std::string getSocksUser() const;
|
||||
|
||||
/*###########################################################################################
|
||||
End of methods that access variables shared between threads.
|
||||
END OF LOCKING METHODS
|
||||
###########################################################################################*/
|
||||
|
||||
private:
|
||||
@@ -361,16 +304,49 @@ private:
|
||||
// Instead use enableHTTPProxy() and disableHTTPProxy() instead.
|
||||
mutable LLAtomic32<bool> mHTTPProxyEnabled;
|
||||
|
||||
// Mutex to protect shared members in non-main thread calls to applyProxySettings().
|
||||
mutable LLMutex mProxyMutex;
|
||||
|
||||
/*###########################################################################################
|
||||
MEMBERS READ AND WRITTEN ONLY IN THE MAIN THREAD. DO NOT SHARE!
|
||||
###########################################################################################*/
|
||||
|
||||
// Is the UDP proxy enabled?
|
||||
static bool sUDPProxyEnabled;
|
||||
|
||||
AIThreadSafeSingleThreadDC<ProxyUnshared> mUnshared;
|
||||
AIThreadSafeDC<ProxyShared> mShared;
|
||||
// UDP proxy address and port
|
||||
LLHost mUDPProxy;
|
||||
// TCP proxy control channel address and port
|
||||
LLHost mTCPProxy;
|
||||
|
||||
public:
|
||||
// For thread-safe read access. Use the _crat access types with these.
|
||||
AIThreadSafeSingleThreadDC<ProxyUnshared> const& unshared_lockobj(void) const { return mUnshared; }
|
||||
AIThreadSafeDC<ProxyShared> const& shared_lockobj(void) const { return mShared; }
|
||||
// socket handle to proxy TCP control channel
|
||||
LLSocket::ptr_t mProxyControlChannel;
|
||||
|
||||
/*###########################################################################################
|
||||
END OF UNSHARED MEMBERS
|
||||
###########################################################################################*/
|
||||
|
||||
/*###########################################################################################
|
||||
MEMBERS WRITTEN IN MAIN THREAD AND READ IN ANY THREAD. ONLY READ OR WRITE AFTER LOCKING mProxyMutex!
|
||||
###########################################################################################*/
|
||||
|
||||
// HTTP proxy address and port
|
||||
LLHost mHTTPProxy;
|
||||
|
||||
// Currently selected HTTP proxy type. Can be web or socks.
|
||||
LLHttpProxyType mProxyType;
|
||||
|
||||
// SOCKS 5 selected authentication method.
|
||||
LLSocks5AuthType mAuthMethodSelected;
|
||||
|
||||
// SOCKS 5 username
|
||||
std::string mSocksUsername;
|
||||
// SOCKS 5 password
|
||||
std::string mSocksPassword;
|
||||
|
||||
/*###########################################################################################
|
||||
END OF SHARED MEMBERS
|
||||
###########################################################################################*/
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4,25 +4,31 @@
|
||||
* @date 2004-11-21
|
||||
* @brief Implementation of the i/o pump and related functions.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2004&license=viewerlgpl$
|
||||
* $LicenseInfo:firstyear=2004&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2004-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* 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.
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* 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.
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* 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
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
@@ -34,11 +40,12 @@
|
||||
#include "apr_poll.h"
|
||||
|
||||
#include "llapr.h"
|
||||
#include "llfasttimer.h"
|
||||
#include "llmemtype.h"
|
||||
#include "llstl.h"
|
||||
#include "llstat.h"
|
||||
#include "llthread.h"
|
||||
#include "llfasttimer.h"
|
||||
#include <iterator> //VS2010
|
||||
|
||||
// These should not be enabled in production, but they can be
|
||||
// intensely useful during development for finding certain kinds of
|
||||
@@ -184,28 +191,17 @@ LLPumpIO::LLPumpIO(void) :
|
||||
LLPumpIO::~LLPumpIO()
|
||||
{
|
||||
LLMemType m1(LLMemType::MTYPE_IO_PUMP);
|
||||
#if LL_THREADS_APR
|
||||
if (mChainsMutex) apr_thread_mutex_destroy(mChainsMutex);
|
||||
if (mCallbackMutex) apr_thread_mutex_destroy(mCallbackMutex);
|
||||
#endif
|
||||
mChainsMutex = NULL;
|
||||
mCallbackMutex = NULL;
|
||||
if(mPollset)
|
||||
{
|
||||
// lldebugs << "cleaning up pollset" << llendl;
|
||||
apr_pollset_destroy(mPollset);
|
||||
mPollset = NULL;
|
||||
}
|
||||
cleanup();
|
||||
}
|
||||
|
||||
bool LLPumpIO::addChain(chain_t const& chain, F32 timeout)
|
||||
bool LLPumpIO::addChain(const chain_t& chain, F32 timeout)
|
||||
{
|
||||
LLMemType m1(LLMemType::MTYPE_IO_PUMP);
|
||||
if(chain.empty()) return false;
|
||||
|
||||
chain_t::const_iterator it = chain.begin();
|
||||
chain_t::const_iterator const end = chain.end();
|
||||
if (it == end) return false;
|
||||
|
||||
#if LL_THREADS_APR
|
||||
LLScopedLock lock(mChainsMutex);
|
||||
#endif
|
||||
LLChainInfo info;
|
||||
info.setTimeoutSeconds(timeout);
|
||||
info.mData = LLIOPipe::buffer_ptr_t(new LLBufferArray);
|
||||
@@ -216,17 +212,14 @@ bool LLPumpIO::addChain(chain_t const& chain, F32 timeout)
|
||||
#else
|
||||
lldebugs << "LLPumpIO::addChain() " << chain[0] <<llendl;
|
||||
#endif
|
||||
chain_t::const_iterator it = chain.begin();
|
||||
chain_t::const_iterator end = chain.end();
|
||||
for(; it != end; ++it)
|
||||
{
|
||||
info.mHasExpiration = info.mHasExpiration || (*it)->hasExpiration();
|
||||
link.mPipe = (*it);
|
||||
link.mChannels = info.mData->nextChannel();
|
||||
info.mChainLinks.push_back(link);
|
||||
}
|
||||
|
||||
#if LL_THREADS_APR
|
||||
LLScopedLock lock(mChainsMutex);
|
||||
#endif
|
||||
mPendingChains.push_back(info);
|
||||
return true;
|
||||
}
|
||||
@@ -243,10 +236,11 @@ bool LLPumpIO::addChain(
|
||||
// description, we need to have that description matched to a
|
||||
// particular buffer.
|
||||
if(!data) return false;
|
||||
links_t::const_iterator link = links.begin();
|
||||
links_t::const_iterator const end = links.end();
|
||||
if (link == end) return false;
|
||||
if(links.empty()) return false;
|
||||
|
||||
#if LL_THREADS_APR
|
||||
LLScopedLock lock(mChainsMutex);
|
||||
#endif
|
||||
#if LL_DEBUG_PIPE_TYPE_IN_PUMP
|
||||
lldebugs << "LLPumpIO::addChain() " << links[0].mPipe << " '"
|
||||
<< typeid(*(links[0].mPipe)).name() << "'" << llendl;
|
||||
@@ -258,17 +252,6 @@ bool LLPumpIO::addChain(
|
||||
info.mChainLinks = links;
|
||||
info.mData = data;
|
||||
info.mContext = context;
|
||||
for (; link != end; ++link)
|
||||
{
|
||||
if (link->mPipe->hasExpiration())
|
||||
{
|
||||
info.mHasExpiration = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#if LL_THREADS_APR
|
||||
LLScopedLock lock(mChainsMutex);
|
||||
#endif
|
||||
mPendingChains.push_back(info);
|
||||
return true;
|
||||
}
|
||||
@@ -455,15 +438,6 @@ void LLPumpIO::pump()
|
||||
|
||||
static LLFastTimer::DeclareTimer FTM_PUMP_IO("Pump IO");
|
||||
|
||||
LLPumpIO::current_chain_t LLPumpIO::removeRunningChain(LLPumpIO::current_chain_t& run_chain)
|
||||
{
|
||||
std::for_each(
|
||||
(*run_chain).mDescriptors.begin(),
|
||||
(*run_chain).mDescriptors.end(),
|
||||
ll_delete_apr_pollset_fd_client_data());
|
||||
return mRunningChains.erase(run_chain);
|
||||
}
|
||||
|
||||
//timeout is in microseconds
|
||||
void LLPumpIO::pump(const S32& poll_timeout)
|
||||
{
|
||||
@@ -609,16 +583,10 @@ void LLPumpIO::pump(const S32& poll_timeout)
|
||||
// << (*run_chain).mChainLinks[0].mPipe
|
||||
// << " because we reached the end." << llendl;
|
||||
#endif
|
||||
run_chain = removeRunningChain(run_chain);
|
||||
run_chain = mRunningChains.erase(run_chain);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if(isChainExpired(*run_chain))
|
||||
{
|
||||
run_chain = removeRunningChain(run_chain);
|
||||
continue;
|
||||
}
|
||||
|
||||
PUMP_DEBUG;
|
||||
if((*run_chain).mLock)
|
||||
{
|
||||
@@ -726,7 +694,11 @@ void LLPumpIO::pump(const S32& poll_timeout)
|
||||
PUMP_DEBUG;
|
||||
// This chain is done. Clean up any allocated memory and
|
||||
// erase the chain info.
|
||||
run_chain = removeRunningChain(run_chain);
|
||||
std::for_each(
|
||||
(*run_chain).mDescriptors.begin(),
|
||||
(*run_chain).mDescriptors.end(),
|
||||
ll_delete_apr_pollset_fd_client_data());
|
||||
run_chain = mRunningChains.erase(run_chain);
|
||||
|
||||
// *NOTE: may not always need to rebuild the pollset.
|
||||
mRebuildPollset = true;
|
||||
@@ -861,6 +833,22 @@ void LLPumpIO::initialize(void)
|
||||
apr_thread_mutex_create(&mCallbackMutex, APR_THREAD_MUTEX_UNNESTED, mPool());
|
||||
#endif
|
||||
}
|
||||
void LLPumpIO::cleanup()
|
||||
{
|
||||
LLMemType m1(LLMemType::MTYPE_IO_PUMP);
|
||||
#if LL_THREADS_APR
|
||||
if (mChainsMutex) apr_thread_mutex_destroy(mChainsMutex);
|
||||
if (mCallbackMutex) apr_thread_mutex_destroy(mCallbackMutex);
|
||||
#endif
|
||||
mChainsMutex = NULL;
|
||||
mCallbackMutex = NULL;
|
||||
if(mPollset)
|
||||
{
|
||||
// lldebugs << "cleaning up pollset" << llendl;
|
||||
apr_pollset_destroy(mPollset);
|
||||
mPollset = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void LLPumpIO::rebuildPollset()
|
||||
{
|
||||
@@ -1095,30 +1083,10 @@ void LLPumpIO::processChain(LLChainInfo& chain)
|
||||
PUMP_DEBUG;
|
||||
}
|
||||
|
||||
bool LLPumpIO::isChainExpired(LLChainInfo& chain)
|
||||
{
|
||||
if(!chain.mHasExpiration)
|
||||
{
|
||||
return false ;
|
||||
}
|
||||
|
||||
for(links_t::iterator iter = chain.mChainLinks.begin(); iter != chain.mChainLinks.end(); ++iter)
|
||||
{
|
||||
if(!(*iter).mPipe->hasNotExpired())
|
||||
{
|
||||
return true ;
|
||||
}
|
||||
}
|
||||
|
||||
return false ;
|
||||
}
|
||||
|
||||
bool LLPumpIO::handleChainError(
|
||||
LLChainInfo& chain,
|
||||
LLIOPipe::EStatus error)
|
||||
{
|
||||
DoutEntering(dc::notice, "LLPumpIO::handleChainError(" << (void*)&chain << ", " << LLIOPipe::lookupStatusString(error) << ")");
|
||||
|
||||
LLMemType m1(LLMemType::MTYPE_IO_PUMP);
|
||||
links_t::reverse_iterator rit;
|
||||
if(chain.mHead == chain.mChainLinks.end())
|
||||
@@ -1156,9 +1124,6 @@ bool LLPumpIO::handleChainError(
|
||||
#endif
|
||||
keep_going = false;
|
||||
break;
|
||||
case LLIOPipe::STATUS_EXPIRED:
|
||||
keep_going = false;
|
||||
break ;
|
||||
default:
|
||||
if(LLIOPipe::isSuccess(error))
|
||||
{
|
||||
@@ -1181,7 +1146,6 @@ LLPumpIO::LLChainInfo::LLChainInfo() :
|
||||
mInit(false),
|
||||
mLock(0),
|
||||
mEOS(false),
|
||||
mHasExpiration(false),
|
||||
mDescriptorsPool(new LLAPRPool(LLThread::tldata().mRootPool))
|
||||
{
|
||||
LLMemType m1(LLMemType::MTYPE_IO_PUMP);
|
||||
|
||||
@@ -4,25 +4,31 @@
|
||||
* @date 2004-11-19
|
||||
* @brief Declaration of pump class which manages io chains.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2004&license=viewerlgpl$
|
||||
* $LicenseInfo:firstyear=2004&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2004-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* 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.
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* 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.
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* 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
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
@@ -345,13 +351,12 @@ protected:
|
||||
|
||||
// basic member data
|
||||
bool mInit;
|
||||
bool mEOS;
|
||||
bool mHasExpiration;
|
||||
S32 mLock;
|
||||
LLFrameTimer mTimer;
|
||||
links_t::iterator mHead;
|
||||
links_t mChainLinks;
|
||||
LLIOPipe::buffer_ptr_t mData;
|
||||
LLIOPipe::buffer_ptr_t mData;
|
||||
bool mEOS;
|
||||
LLSD mContext;
|
||||
|
||||
// tracking inside the pump
|
||||
@@ -392,8 +397,8 @@ protected:
|
||||
|
||||
protected:
|
||||
void initialize();
|
||||
void cleanup();
|
||||
|
||||
current_chain_t removeRunningChain(current_chain_t& chain) ;
|
||||
/**
|
||||
* @brief Given the internal state of the chains, rebuild the pollset
|
||||
* @see setConditional()
|
||||
@@ -420,9 +425,6 @@ protected:
|
||||
*/
|
||||
bool handleChainError(LLChainInfo& chain, LLIOPipe::EStatus error);
|
||||
|
||||
//if the chain is expired, remove it
|
||||
bool isChainExpired(LLChainInfo& chain) ;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Return number of running chains.
|
||||
|
||||
@@ -88,7 +88,7 @@ bool LLSDMessage::httpListener(const LLSD& request)
|
||||
request,
|
||||
url, "POST", reply, error),
|
||||
LLSD(), // headers
|
||||
timeout);
|
||||
(F32)timeout);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -151,11 +151,11 @@ bool LLSDMessage::ResponderAdapter::listener(const LLSD& payload, bool success)
|
||||
{
|
||||
if (success)
|
||||
{
|
||||
mResponder->pubResult(payload);
|
||||
mResponder->result(payload);
|
||||
}
|
||||
else
|
||||
{
|
||||
mResponder->pubErrorWithContent(payload["status"].asInteger(), payload["reason"], payload["content"]);
|
||||
mResponder->errorWithContent(payload["status"].asInteger(), payload["reason"], payload["content"]);
|
||||
}
|
||||
|
||||
/*---------------- MUST BE LAST STATEMENT BEFORE RETURN ----------------*/
|
||||
|
||||
@@ -317,7 +317,7 @@ void LLSDMessageBuilder::copyFromMessageData(const LLMsgData& data)
|
||||
|
||||
// S64 not supported in LLSD so we just truncate it
|
||||
case MVT_S64:
|
||||
addS32(varname, *(S64*)mvci.getData());
|
||||
addS32(varname, (S32)*(S64*)mvci.getData());
|
||||
break;
|
||||
|
||||
case MVT_F32:
|
||||
|
||||
255
indra/llmessage/llsdrpcclient.cpp
Normal file
255
indra/llmessage/llsdrpcclient.cpp
Normal file
@@ -0,0 +1,255 @@
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
323
indra/llmessage/llsdrpcclient.h
Normal file
323
indra/llmessage/llsdrpcclient.h
Normal file
@@ -0,0 +1,323 @@
|
||||
/**
|
||||
* @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(new LLURLRequest(LLURLRequest::HTTP_POST));
|
||||
if(!http->isValid())
|
||||
{
|
||||
llwarns << "Creating LLURLRequest failed." << llendl ;
|
||||
delete http;
|
||||
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(new LLURLRequest(LLURLRequest::HTTP_POST));
|
||||
if(!http->isValid())
|
||||
{
|
||||
llwarns << "Creating LLURLRequest failed." << llendl ;
|
||||
delete http;
|
||||
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
|
||||
347
indra/llmessage/llsdrpcserver.cpp
Normal file
347
indra/llmessage/llsdrpcserver.cpp
Normal file
@@ -0,0 +1,347 @@
|
||||
/**
|
||||
* @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
|
||||
}
|
||||
360
indra/llmessage/llsdrpcserver.h
Normal file
360
indra/llmessage/llsdrpcserver.h
Normal file
@@ -0,0 +1,360 @@
|
||||
/**
|
||||
* @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
|
||||
@@ -29,33 +29,32 @@
|
||||
#include "linden_common.h"
|
||||
#include "llurlrequest.h"
|
||||
|
||||
#ifdef CWDEBUG
|
||||
#include <libcwd/buf2str.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <openssl/x509_vfy.h>
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#include "llcurl.h"
|
||||
#include "llfasttimer.h"
|
||||
#include "llioutil.h"
|
||||
#include "llmemtype.h"
|
||||
#include "llproxy.h"
|
||||
#include "llpumpio.h"
|
||||
#include "llsd.h"
|
||||
#include "llstring.h"
|
||||
#include "apr_env.h"
|
||||
#include "llapr.h"
|
||||
#include "llscopedvolatileaprpool.h"
|
||||
#include "llfasttimer.h"
|
||||
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");
|
||||
|
||||
|
||||
static size_t headerCallback(char* data, size_t size, size_t nmemb, void* user);
|
||||
static size_t headerCallback(void* data, size_t size, size_t nmemb, void* user);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* class LLURLRequestDetail
|
||||
@@ -66,8 +65,8 @@ public:
|
||||
LLURLRequestDetail();
|
||||
~LLURLRequestDetail();
|
||||
std::string mURL;
|
||||
AICurlEasyRequest mCurlEasyRequest;
|
||||
LLIOPipe::buffer_ptr_t mResponseBuffer;
|
||||
LLCurlEasyRequest* mCurlRequest;
|
||||
LLBufferArray* mResponseBuffer;
|
||||
LLChannelDescriptors mChannels;
|
||||
U8* mLastRead;
|
||||
U32 mBodyLimit;
|
||||
@@ -77,28 +76,31 @@ public:
|
||||
};
|
||||
|
||||
LLURLRequestDetail::LLURLRequestDetail() :
|
||||
mCurlEasyRequest(false),
|
||||
mCurlRequest(NULL),
|
||||
mResponseBuffer(NULL),
|
||||
mLastRead(NULL),
|
||||
mBodyLimit(0),
|
||||
mByteAccumulator(0),
|
||||
mIsBodyLimitSet(false),
|
||||
mSSLVerifyCallback(NULL)
|
||||
mIsBodyLimitSet(false)
|
||||
{
|
||||
LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
|
||||
mCurlRequest = new LLCurlEasyRequest();
|
||||
}
|
||||
|
||||
LLURLRequestDetail::~LLURLRequestDetail()
|
||||
{
|
||||
LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
|
||||
delete mCurlRequest;
|
||||
mResponseBuffer = NULL;
|
||||
mLastRead = NULL;
|
||||
}
|
||||
|
||||
void LLURLRequest::setSSLVerifyCallback(SSLCertVerifyCallback callback, void *param)
|
||||
{
|
||||
LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
|
||||
mDetail->mSSLVerifyCallback = callback;
|
||||
AICurlEasyRequest_wat curlEasyRequest_w(*mDetail->mCurlEasyRequest);
|
||||
curlEasyRequest_w->setSSLCtxCallback(LLURLRequest::_sslCtxCallback, (void *)this);
|
||||
curlEasyRequest_w->setopt(CURLOPT_SSL_VERIFYPEER, true);
|
||||
curlEasyRequest_w->setopt(CURLOPT_SSL_VERIFYHOST, 2);
|
||||
mDetail->mCurlRequest->setSSLCtxCallback(LLURLRequest::_sslCtxCallback, (void *)this);
|
||||
mDetail->mCurlRequest->setopt(CURLOPT_SSL_VERIFYPEER, true);
|
||||
mDetail->mCurlRequest->setopt(CURLOPT_SSL_VERIFYHOST, 2);
|
||||
}
|
||||
|
||||
|
||||
@@ -107,7 +109,7 @@ void LLURLRequest::setSSLVerifyCallback(SSLCertVerifyCallback callback, void *pa
|
||||
// used to configure the context for custom cert validation
|
||||
|
||||
CURLcode LLURLRequest::_sslCtxCallback(CURL * curl, void *sslctx, void *param)
|
||||
{
|
||||
{
|
||||
LLURLRequest *req = (LLURLRequest *)param;
|
||||
if(req == NULL || req->mDetail->mSSLVerifyCallback == NULL)
|
||||
{
|
||||
@@ -121,7 +123,6 @@ CURLcode LLURLRequest::_sslCtxCallback(CURL * curl, void *sslctx, void *param)
|
||||
SSL_CTX_set_cert_verify_callback(ctx, req->mDetail->mSSLVerifyCallback, (void *)req);
|
||||
// the calls are void
|
||||
return CURLE_OK;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -152,7 +153,6 @@ LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action) :
|
||||
mAction(action)
|
||||
{
|
||||
LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
|
||||
// This might throw AICurlNoEasyHandle.
|
||||
initialize();
|
||||
}
|
||||
|
||||
@@ -162,7 +162,6 @@ LLURLRequest::LLURLRequest(
|
||||
mAction(action)
|
||||
{
|
||||
LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
|
||||
// This might throw AICurlNoEasyHandle.
|
||||
initialize();
|
||||
setURL(url);
|
||||
}
|
||||
@@ -170,16 +169,13 @@ LLURLRequest::LLURLRequest(
|
||||
LLURLRequest::~LLURLRequest()
|
||||
{
|
||||
LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
|
||||
{
|
||||
AICurlEasyRequest_wat curl_easy_request_w(*mDetail->mCurlEasyRequest);
|
||||
curl_easy_request_w->revokeCallbacks();
|
||||
curl_easy_request_w->send_events_to(NULL);
|
||||
}
|
||||
delete mDetail;
|
||||
mDetail = NULL ;
|
||||
}
|
||||
|
||||
void LLURLRequest::setURL(const std::string& url)
|
||||
{
|
||||
LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
|
||||
mDetail->mURL = url;
|
||||
}
|
||||
|
||||
@@ -187,12 +183,10 @@ std::string LLURLRequest::getURL() const
|
||||
{
|
||||
return mDetail->mURL;
|
||||
}
|
||||
|
||||
void LLURLRequest::addHeader(const char* header)
|
||||
{
|
||||
LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
|
||||
AICurlEasyRequest_wat curlEasyRequest_w(*mDetail->mCurlEasyRequest);
|
||||
curlEasyRequest_w->addHeader(header);
|
||||
mDetail->mCurlRequest->slist_append(header);
|
||||
}
|
||||
|
||||
void LLURLRequest::setBodyLimit(U32 size)
|
||||
@@ -205,8 +199,7 @@ void LLURLRequest::setCallback(LLURLRequestComplete* callback)
|
||||
{
|
||||
LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
|
||||
mCompletionCallback = callback;
|
||||
AICurlEasyRequest_wat curlEasyRequest_w(*mDetail->mCurlEasyRequest);
|
||||
curlEasyRequest_w->setHeaderCallback(&headerCallback, (void*)callback);
|
||||
mDetail->mCurlRequest->setHeaderCallback(&headerCallback, (void*)callback);
|
||||
}
|
||||
|
||||
// Added to mitigate the effect of libcurl looking
|
||||
@@ -240,41 +233,26 @@ void LLURLRequest::useProxy(bool use_proxy)
|
||||
}
|
||||
}
|
||||
|
||||
lldebugs << "use_proxy = " << (use_proxy?'Y':'N') << ", env_proxy = \"" << env_proxy << "\"" << llendl;
|
||||
LL_DEBUGS("Proxy") << "use_proxy = " << (use_proxy?'Y':'N') << ", env_proxy = " << (!env_proxy.empty() ? env_proxy : "(null)") << LL_ENDL;
|
||||
|
||||
AICurlEasyRequest_wat curlEasyRequest_w(*mDetail->mCurlEasyRequest);
|
||||
curlEasyRequest_w->setoptString(CURLOPT_PROXY, use_proxy ? env_proxy : std::string(""));
|
||||
if (use_proxy && !env_proxy.empty())
|
||||
{
|
||||
mDetail->mCurlRequest->setoptString(CURLOPT_PROXY, env_proxy);
|
||||
}
|
||||
else
|
||||
{
|
||||
mDetail->mCurlRequest->setoptString(CURLOPT_PROXY, "");
|
||||
}
|
||||
}
|
||||
|
||||
void LLURLRequest::useProxy(const std::string &proxy)
|
||||
{
|
||||
AICurlEasyRequest_wat curlEasyRequest_w(*mDetail->mCurlEasyRequest);
|
||||
curlEasyRequest_w->setoptString(CURLOPT_PROXY, proxy);
|
||||
mDetail->mCurlRequest->setoptString(CURLOPT_PROXY, proxy);
|
||||
}
|
||||
|
||||
void LLURLRequest::allowCookies()
|
||||
{
|
||||
AICurlEasyRequest_wat curlEasyRequest_w(*mDetail->mCurlEasyRequest);
|
||||
curlEasyRequest_w->setoptString(CURLOPT_COOKIEFILE, "");
|
||||
}
|
||||
|
||||
//virtual
|
||||
bool LLURLRequest::hasExpiration(void) const
|
||||
{
|
||||
// Currently, this ALWAYS returns false -- because only AICurlEasyRequestStateMachine uses buffered
|
||||
// AICurlEasyRequest objects, and LLURLRequest uses (unbuffered) AICurlEasyRequest directly, which
|
||||
// have no expiration facility.
|
||||
return mDetail->mCurlEasyRequest.isBuffered();
|
||||
}
|
||||
|
||||
//virtual
|
||||
bool LLURLRequest::hasNotExpired(void) const
|
||||
{
|
||||
if (!mDetail->mCurlEasyRequest.isBuffered())
|
||||
return true;
|
||||
AICurlEasyRequest_wat buffered_easy_request_w(*mDetail->mCurlEasyRequest);
|
||||
AICurlResponderBuffer_wat buffer_w(*mDetail->mCurlEasyRequest);
|
||||
return buffer_w->isValid();
|
||||
mDetail->mCurlRequest->setoptString(CURLOPT_COOKIEFILE, "");
|
||||
}
|
||||
|
||||
// virtual
|
||||
@@ -282,27 +260,7 @@ LLIOPipe::EStatus LLURLRequest::handleError(
|
||||
LLIOPipe::EStatus status,
|
||||
LLPumpIO* pump)
|
||||
{
|
||||
DoutEntering(dc::curl, "LLURLRequest::handleError(" << LLIOPipe::lookupStatusString(status) << ", " << (void*)pump << ")");
|
||||
LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
|
||||
|
||||
if (LL_LIKELY(!mDetail->mCurlEasyRequest.isBuffered())) // Currently always true.
|
||||
{
|
||||
// The last reference will be deleted when the pump that this chain belongs to
|
||||
// is removed from the running chains vector, upon returning from this function.
|
||||
// This keeps the CurlEasyRequest object alive until the curl thread cleanly removed it.
|
||||
Dout(dc::curl, "Calling mDetail->mCurlEasyRequest.removeRequest()");
|
||||
mDetail->mCurlEasyRequest.removeRequest();
|
||||
}
|
||||
else if (!hasNotExpired())
|
||||
{
|
||||
// The buffered version has it's own time out handling, and that already expired,
|
||||
// so we can ignore the expiration of this timer (currently never happens).
|
||||
// I left it here because it's what LL did (in the form if (!isValid() ...),
|
||||
// and it would be relevant if this characteristic of mDetail->mCurlEasyRequest
|
||||
// would change. --Aleric
|
||||
return STATUS_EXPIRED ;
|
||||
}
|
||||
|
||||
if(mCompletionCallback && pump)
|
||||
{
|
||||
LLURLRequestComplete* complete = NULL;
|
||||
@@ -317,19 +275,6 @@ LLIOPipe::EStatus LLURLRequest::handleError(
|
||||
return status;
|
||||
}
|
||||
|
||||
void LLURLRequest::added_to_multi_handle(AICurlEasyRequest_wat&)
|
||||
{
|
||||
}
|
||||
|
||||
void LLURLRequest::finished(AICurlEasyRequest_wat&)
|
||||
{
|
||||
}
|
||||
|
||||
void LLURLRequest::removed_from_multi_handle(AICurlEasyRequest_wat&)
|
||||
{
|
||||
mRemoved = true;
|
||||
}
|
||||
|
||||
static LLFastTimer::DeclareTimer FTM_PROCESS_URL_REQUEST("URL Request");
|
||||
|
||||
// virtual
|
||||
@@ -345,8 +290,9 @@ LLIOPipe::EStatus LLURLRequest::process_impl(
|
||||
LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
|
||||
//llinfos << "LLURLRequest::process_impl()" << llendl;
|
||||
if (!buffer) return STATUS_ERROR;
|
||||
|
||||
// we're still waiting or processing, check how many
|
||||
if (!mDetail) return STATUS_ERROR; //Seems to happen on occasion. Need to hunt down why.
|
||||
|
||||
// we're still waiting or prcessing, check how many
|
||||
// bytes we have accumulated.
|
||||
const S32 MIN_ACCUMULATION = 100000;
|
||||
if(pump && (mDetail->mByteAccumulator > MIN_ACCUMULATION))
|
||||
@@ -384,42 +330,47 @@ LLIOPipe::EStatus LLURLRequest::process_impl(
|
||||
|
||||
// *FIX: bit of a hack, but it should work. The configure and
|
||||
// callback method expect this information to be ready.
|
||||
mDetail->mResponseBuffer = buffer;
|
||||
mDetail->mResponseBuffer = buffer.get();
|
||||
mDetail->mChannels = channels;
|
||||
if(!configure())
|
||||
{
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
mRemoved = false;
|
||||
mState = STATE_WAITING_FOR_RESPONSE;
|
||||
mDetail->mCurlEasyRequest.addRequest(); // Add easy handle to multi handle.
|
||||
|
||||
// *FIX: Maybe we should just go to the next state now...
|
||||
return STATUS_BREAK;
|
||||
}
|
||||
case STATE_WAITING_FOR_RESPONSE:
|
||||
case STATE_PROCESSING_RESPONSE:
|
||||
{
|
||||
if (!mRemoved) // Not removed from multi handle yet?
|
||||
{
|
||||
// Easy handle is still being processed.
|
||||
return STATUS_BREAK;
|
||||
}
|
||||
// Curl thread finished with this easy handle.
|
||||
mState = STATE_CURL_FINISHED;
|
||||
}
|
||||
case STATE_CURL_FINISHED:
|
||||
{
|
||||
PUMP_DEBUG;
|
||||
LLIOPipe::EStatus status = STATUS_NO_CONNECTION; // Catch-all failure code.
|
||||
LLIOPipe::EStatus status = STATUS_BREAK;
|
||||
static LLFastTimer::DeclareTimer FTM_URL_PERFORM("Perform");
|
||||
{
|
||||
LLFastTimer t(FTM_URL_PERFORM);
|
||||
mDetail->mCurlRequest->perform();
|
||||
}
|
||||
|
||||
// Left braces in order not to change indentation.
|
||||
while(1)
|
||||
{
|
||||
CURLcode result;
|
||||
|
||||
static LLFastTimer::DeclareTimer FTM_PROCESS_URL_REQUEST_GET_RESULT("Get Result");
|
||||
|
||||
AICurlEasyRequest_wat(*mDetail->mCurlEasyRequest)->getResult(&result);
|
||||
bool newmsg = false;
|
||||
{
|
||||
LLFastTimer t(FTM_PROCESS_URL_REQUEST_GET_RESULT);
|
||||
newmsg = mDetail->mCurlRequest->getResult(&result);
|
||||
}
|
||||
|
||||
if(!newmsg)
|
||||
{
|
||||
// keep processing
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
mState = STATE_HAVE_RESPONSE;
|
||||
context[CONTEXT_REQUEST][CONTEXT_TRANSFERED_BYTES] = mRequestTransferedBytes;
|
||||
context[CONTEXT_RESPONSE][CONTEXT_TRANSFERED_BYTES] = mResponseTransferedBytes;
|
||||
@@ -451,7 +402,6 @@ LLIOPipe::EStatus LLURLRequest::process_impl(
|
||||
}
|
||||
mCompletionCallback = NULL;
|
||||
}
|
||||
status = STATUS_BREAK; // This is what the old code returned. Does it make sense?
|
||||
break;
|
||||
case CURLE_FAILED_INIT:
|
||||
case CURLE_COULDNT_CONNECT:
|
||||
@@ -493,15 +443,10 @@ void LLURLRequest::initialize()
|
||||
{
|
||||
LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
|
||||
mState = STATE_INITIALIZED;
|
||||
// This might throw AICurlNoEasyHandle.
|
||||
mDetail = new LLURLRequestDetail;
|
||||
|
||||
{
|
||||
AICurlEasyRequest_wat curlEasyRequest_w(*mDetail->mCurlEasyRequest);
|
||||
curlEasyRequest_w->setWriteCallback(&downCallback, (void*)this);
|
||||
curlEasyRequest_w->setReadCallback(&upCallback, (void*)this);
|
||||
}
|
||||
|
||||
mDetail->mCurlRequest->setopt(CURLOPT_NOSIGNAL, 1);
|
||||
mDetail->mCurlRequest->setWriteCallback(&downCallback, (void*)this);
|
||||
mDetail->mCurlRequest->setReadCallback(&upCallback, (void*)this);
|
||||
mRequestTransferedBytes = 0;
|
||||
mResponseTransferedBytes = 0;
|
||||
}
|
||||
@@ -516,74 +461,70 @@ bool LLURLRequest::configure()
|
||||
S32 bytes = mDetail->mResponseBuffer->countAfter(
|
||||
mDetail->mChannels.in(),
|
||||
NULL);
|
||||
switch(mAction)
|
||||
{
|
||||
AICurlEasyRequest_wat curlEasyRequest_w(*mDetail->mCurlEasyRequest);
|
||||
switch(mAction)
|
||||
{
|
||||
case HTTP_HEAD:
|
||||
curlEasyRequest_w->setopt(CURLOPT_HEADER, 1);
|
||||
curlEasyRequest_w->setopt(CURLOPT_NOBODY, 1);
|
||||
curlEasyRequest_w->setopt(CURLOPT_FOLLOWLOCATION, 1);
|
||||
rv = true;
|
||||
break;
|
||||
case HTTP_GET:
|
||||
curlEasyRequest_w->setopt(CURLOPT_HTTPGET, 1);
|
||||
curlEasyRequest_w->setopt(CURLOPT_FOLLOWLOCATION, 1);
|
||||
case HTTP_HEAD:
|
||||
mDetail->mCurlRequest->setopt(CURLOPT_HEADER, 1);
|
||||
mDetail->mCurlRequest->setopt(CURLOPT_NOBODY, 1);
|
||||
mDetail->mCurlRequest->setopt(CURLOPT_FOLLOWLOCATION, 1);
|
||||
rv = true;
|
||||
break;
|
||||
case HTTP_GET:
|
||||
mDetail->mCurlRequest->setopt(CURLOPT_HTTPGET, 1);
|
||||
mDetail->mCurlRequest->setopt(CURLOPT_FOLLOWLOCATION, 1);
|
||||
|
||||
// Set Accept-Encoding to allow response compression
|
||||
curlEasyRequest_w->setoptString(CURLOPT_ENCODING, "");
|
||||
rv = true;
|
||||
break;
|
||||
// Set Accept-Encoding to allow response compression
|
||||
mDetail->mCurlRequest->setoptString(CURLOPT_ENCODING, "");
|
||||
rv = true;
|
||||
break;
|
||||
|
||||
case HTTP_PUT:
|
||||
// Disable the expect http 1.1 extension. POST and PUT default
|
||||
// to turning this on, and I am not too sure what it means.
|
||||
addHeader("Expect:");
|
||||
case HTTP_PUT:
|
||||
// Disable the expect http 1.1 extension. POST and PUT default
|
||||
// to turning this on, and I am not too sure what it means.
|
||||
addHeader("Expect:");
|
||||
|
||||
curlEasyRequest_w->setopt(CURLOPT_UPLOAD, 1);
|
||||
curlEasyRequest_w->setopt(CURLOPT_INFILESIZE, bytes);
|
||||
rv = true;
|
||||
break;
|
||||
mDetail->mCurlRequest->setopt(CURLOPT_UPLOAD, 1);
|
||||
mDetail->mCurlRequest->setopt(CURLOPT_INFILESIZE, bytes);
|
||||
rv = true;
|
||||
break;
|
||||
|
||||
case HTTP_POST:
|
||||
// Disable the expect http 1.1 extension. POST and PUT default
|
||||
// to turning this on, and I am not too sure what it means.
|
||||
addHeader("Expect:");
|
||||
case HTTP_POST:
|
||||
// Disable the expect http 1.1 extension. POST and PUT default
|
||||
// to turning this on, and I am not too sure what it means.
|
||||
addHeader("Expect:");
|
||||
|
||||
// Disable the content type http header.
|
||||
// *FIX: what should it be?
|
||||
addHeader("Content-Type:");
|
||||
// Disable the content type http header.
|
||||
// *FIX: what should it be?
|
||||
addHeader("Content-Type:");
|
||||
|
||||
// Set the handle for an http post
|
||||
curlEasyRequest_w->setPost(NULL, bytes);
|
||||
// Set the handle for an http post
|
||||
mDetail->mCurlRequest->setPost(NULL, bytes);
|
||||
|
||||
// Set Accept-Encoding to allow response compression
|
||||
curlEasyRequest_w->setoptString(CURLOPT_ENCODING, "");
|
||||
rv = true;
|
||||
break;
|
||||
// Set Accept-Encoding to allow response compression
|
||||
mDetail->mCurlRequest->setoptString(CURLOPT_ENCODING, "");
|
||||
rv = true;
|
||||
break;
|
||||
|
||||
case HTTP_DELETE:
|
||||
// Set the handle for an http post
|
||||
curlEasyRequest_w->setoptString(CURLOPT_CUSTOMREQUEST, "DELETE");
|
||||
rv = true;
|
||||
break;
|
||||
case HTTP_DELETE:
|
||||
// Set the handle for an http post
|
||||
mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "DELETE");
|
||||
rv = true;
|
||||
break;
|
||||
|
||||
case HTTP_MOVE:
|
||||
// Set the handle for an http post
|
||||
curlEasyRequest_w->setoptString(CURLOPT_CUSTOMREQUEST, "MOVE");
|
||||
// *NOTE: should we check for the Destination header?
|
||||
rv = true;
|
||||
break;
|
||||
case HTTP_MOVE:
|
||||
// Set the handle for an http post
|
||||
mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "MOVE");
|
||||
// *NOTE: should we check for the Destination header?
|
||||
rv = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
llwarns << "Unhandled URLRequest action: " << mAction << llendl;
|
||||
break;
|
||||
}
|
||||
if(rv)
|
||||
{
|
||||
curlEasyRequest_w->finalizeRequest(mDetail->mURL);
|
||||
curlEasyRequest_w->send_events_to(this);
|
||||
}
|
||||
default:
|
||||
llwarns << "Unhandled URLRequest action: " << mAction << llendl;
|
||||
break;
|
||||
}
|
||||
if(rv)
|
||||
{
|
||||
mDetail->mCurlRequest->sendRequest(mDetail->mURL);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
@@ -647,8 +588,9 @@ size_t LLURLRequest::upCallback(
|
||||
return bytes;
|
||||
}
|
||||
|
||||
static size_t headerCallback(char* header_line, size_t size, size_t nmemb, void* user)
|
||||
static size_t headerCallback(void* data, size_t size, size_t nmemb, void* user)
|
||||
{
|
||||
const char* header_line = (const char*)data;
|
||||
size_t header_len = size * nmemb;
|
||||
LLURLRequestComplete* complete = (LLURLRequestComplete*)user;
|
||||
|
||||
@@ -714,6 +656,42 @@ 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
|
||||
*/
|
||||
|
||||
@@ -40,8 +40,8 @@
|
||||
#include "llerror.h"
|
||||
#include "llcurl.h"
|
||||
|
||||
|
||||
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;
|
||||
|
||||
@@ -65,7 +65,7 @@ typedef struct x509_store_ctx_st X509_STORE_CTX;
|
||||
* worth the time and effort to eventually port this to a raw client
|
||||
* socket.
|
||||
*/
|
||||
class LLURLRequest : public LLIOPipe, protected AICurlEasyHandleEvents
|
||||
class LLURLRequest : public LLIOPipe
|
||||
{
|
||||
LOG_CLASS(LLURLRequest);
|
||||
public:
|
||||
@@ -144,7 +144,6 @@ public:
|
||||
*/
|
||||
void setSSLVerifyCallback(SSLCertVerifyCallback callback, void * param);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return at most size bytes of body.
|
||||
*
|
||||
@@ -189,15 +188,11 @@ public:
|
||||
*/
|
||||
void allowCookies();
|
||||
|
||||
/*virtual*/ bool hasExpiration(void) const;
|
||||
/*virtual*/ bool hasNotExpired(void) const;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Give this pipe a chance to handle a generated error
|
||||
*/
|
||||
virtual EStatus handleError(EStatus status, LLPumpIO* pump);
|
||||
|
||||
|
||||
protected:
|
||||
/**
|
||||
@@ -217,25 +212,16 @@ protected:
|
||||
STATE_INITIALIZED,
|
||||
STATE_WAITING_FOR_RESPONSE,
|
||||
STATE_PROCESSING_RESPONSE,
|
||||
STATE_CURL_FINISHED,
|
||||
STATE_HAVE_RESPONSE,
|
||||
};
|
||||
EState mState;
|
||||
ERequestAction mAction;
|
||||
LLURLRequestDetail* mDetail;
|
||||
LLIOPipe::ptr_t mCompletionCallback;
|
||||
S32 mRequestTransferedBytes;
|
||||
S32 mResponseTransferedBytes;
|
||||
S32 mRequestTransferedBytes;
|
||||
S32 mResponseTransferedBytes;
|
||||
|
||||
static CURLcode _sslCtxCallback(CURL * curl, void *sslctx, void *param);
|
||||
|
||||
// mRemoved is used instead of changing mState directly, because I'm not convinced the latter is atomic.
|
||||
// Set to false before adding curl request and then only tested.
|
||||
// Reset in removed_from_multi_handle (by another thread), this is thread-safe.
|
||||
bool mRemoved;
|
||||
/*virtual*/ void added_to_multi_handle(AICurlEasyRequest_wat&);
|
||||
/*virtual*/ void finished(AICurlEasyRequest_wat&);
|
||||
/*virtual*/ void removed_from_multi_handle(AICurlEasyRequest_wat&);
|
||||
|
||||
private:
|
||||
/**
|
||||
@@ -275,6 +261,42 @@ 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
|
||||
@@ -347,4 +369,11 @@ protected:
|
||||
EStatus mRequestStatus;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* External constants
|
||||
*/
|
||||
extern const std::string CONTEXT_DEST_URI_SD_LABEL;
|
||||
|
||||
#endif // LL_LLURLREQUEST_H
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
#include "message.h"
|
||||
#include "lltimer.h"
|
||||
#include "llextendedstatus.h"
|
||||
|
||||
const S32 LL_XFER_LARGE_PAYLOAD = 7680;
|
||||
|
||||
|
||||
@@ -97,10 +97,8 @@ std::string get_shared_secret();
|
||||
class LLMessagePollInfo
|
||||
{
|
||||
public:
|
||||
LLMessagePollInfo(void) : mPool(LLThread::tldata().mRootPool) { }
|
||||
apr_socket_t *mAPRSocketp;
|
||||
apr_pollfd_t mPollFD;
|
||||
LLAPRPool mPool;
|
||||
};
|
||||
|
||||
namespace
|
||||
@@ -289,13 +287,15 @@ LLMessageSystem::LLMessageSystem(const std::string& filename, U32 port,
|
||||
}
|
||||
// LL_DEBUGS("Messaging") << << "*** port: " << mPort << llendl;
|
||||
|
||||
mPollInfop = new LLMessagePollInfo;
|
||||
|
||||
//
|
||||
// Create the data structure that we can poll on
|
||||
//
|
||||
apr_socket_t *aprSocketp = NULL;
|
||||
apr_os_sock_put(&aprSocketp, (apr_os_sock_t*)&mSocket, mPollInfop->mPool());
|
||||
apr_os_sock_put(&aprSocketp, (apr_os_sock_t*)&mSocket, LLAPRRootPool::get()());
|
||||
|
||||
mPollInfop = new LLMessagePollInfo;
|
||||
mPollInfop->mAPRSocketp = aprSocketp;
|
||||
mPollInfop->mPollFD.p = mPollInfop->mPool();
|
||||
mPollInfop->mPollFD.p = LLAPRRootPool::get()();
|
||||
mPollInfop->mPollFD.desc_type = APR_POLL_SOCKET;
|
||||
mPollInfop->mPollFD.reqevents = APR_POLLIN;
|
||||
mPollInfop->mPollFD.rtnevents = 0;
|
||||
@@ -3142,7 +3142,7 @@ bool LLMessageSystem::generateDigestForWindowAndUUIDs(char* digest, const S32 wi
|
||||
LL_ERRS("Messaging") << "Trying to generate complex digest on a machine without a shared secret!" << llendl;
|
||||
}
|
||||
|
||||
U32 now = time(NULL);
|
||||
U32 now = (U32)time(NULL);
|
||||
|
||||
now /= window;
|
||||
|
||||
@@ -3162,7 +3162,7 @@ bool LLMessageSystem::isMatchingDigestForWindowAndUUIDs(const char* digest, cons
|
||||
}
|
||||
|
||||
char our_digest[MD5HEX_STR_SIZE]; /* Flawfinder: ignore */
|
||||
U32 now = time(NULL);
|
||||
U32 now = (U32)time(NULL);
|
||||
|
||||
now /= window;
|
||||
|
||||
@@ -3208,7 +3208,7 @@ bool LLMessageSystem::generateDigestForWindow(char* digest, const S32 window) co
|
||||
LL_ERRS("Messaging") << "Trying to generate simple digest on a machine without a shared secret!" << llendl;
|
||||
}
|
||||
|
||||
U32 now = time(NULL);
|
||||
U32 now = (U32)time(NULL);
|
||||
|
||||
now /= window;
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ include_directories(
|
||||
|
||||
set(llprimitive_SOURCE_FILES
|
||||
llmaterialtable.cpp
|
||||
llmediaentry.cpp
|
||||
llmodel.cpp
|
||||
llprimitive.cpp
|
||||
llprimtexturelist.cpp
|
||||
|
||||
@@ -137,6 +137,7 @@ void LLMaterialTable::initTableTransNames(std::map<std::string, std::string> nam
|
||||
infop->mName = namemap[name];
|
||||
}
|
||||
}
|
||||
|
||||
void LLMaterialTable::initBasicTable()
|
||||
{
|
||||
// *TODO: Translate
|
||||
|
||||
596
indra/llprimitive/llmediaentry.cpp
Normal file
596
indra/llprimitive/llmediaentry.cpp
Normal file
@@ -0,0 +1,596 @@
|
||||
/**
|
||||
* @file llmediaentry.cpp
|
||||
* @brief This is a single instance of media data related to the face of a prim
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&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 "llmediaentry.h"
|
||||
#include "lllslconstants.h"
|
||||
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
// LLSD key defines
|
||||
// DO NOT REORDER OR REMOVE THESE!
|
||||
|
||||
// Some LLSD keys. Do not change!
|
||||
#define MEDIA_ALT_IMAGE_ENABLE_KEY_STR "alt_image_enable"
|
||||
#define MEDIA_CONTROLS_KEY_STR "controls"
|
||||
#define MEDIA_CURRENT_URL_KEY_STR "current_url"
|
||||
#define MEDIA_HOME_URL_KEY_STR "home_url"
|
||||
#define MEDIA_AUTO_LOOP_KEY_STR "auto_loop"
|
||||
#define MEDIA_AUTO_PLAY_KEY_STR "auto_play"
|
||||
#define MEDIA_AUTO_SCALE_KEY_STR "auto_scale"
|
||||
#define MEDIA_AUTO_ZOOM_KEY_STR "auto_zoom"
|
||||
#define MEDIA_FIRST_CLICK_INTERACT_KEY_STR "first_click_interact"
|
||||
#define MEDIA_WIDTH_PIXELS_KEY_STR "width_pixels"
|
||||
#define MEDIA_HEIGHT_PIXELS_KEY_STR "height_pixels"
|
||||
|
||||
// "security" fields
|
||||
#define MEDIA_WHITELIST_ENABLE_KEY_STR "whitelist_enable"
|
||||
#define MEDIA_WHITELIST_KEY_STR "whitelist"
|
||||
|
||||
// "permissions" fields
|
||||
#define MEDIA_PERMS_INTERACT_KEY_STR "perms_interact"
|
||||
#define MEDIA_PERMS_CONTROL_KEY_STR "perms_control"
|
||||
|
||||
// "general" fields
|
||||
const char* LLMediaEntry::ALT_IMAGE_ENABLE_KEY = MEDIA_ALT_IMAGE_ENABLE_KEY_STR;
|
||||
const char* LLMediaEntry::CONTROLS_KEY = MEDIA_CONTROLS_KEY_STR;
|
||||
const char* LLMediaEntry::CURRENT_URL_KEY = MEDIA_CURRENT_URL_KEY_STR;
|
||||
const char* LLMediaEntry::HOME_URL_KEY = MEDIA_HOME_URL_KEY_STR;
|
||||
const char* LLMediaEntry::AUTO_LOOP_KEY = MEDIA_AUTO_LOOP_KEY_STR;
|
||||
const char* LLMediaEntry::AUTO_PLAY_KEY = MEDIA_AUTO_PLAY_KEY_STR;
|
||||
const char* LLMediaEntry::AUTO_SCALE_KEY = MEDIA_AUTO_SCALE_KEY_STR;
|
||||
const char* LLMediaEntry::AUTO_ZOOM_KEY = MEDIA_AUTO_ZOOM_KEY_STR;
|
||||
const char* LLMediaEntry::FIRST_CLICK_INTERACT_KEY = MEDIA_FIRST_CLICK_INTERACT_KEY_STR;
|
||||
const char* LLMediaEntry::WIDTH_PIXELS_KEY = MEDIA_WIDTH_PIXELS_KEY_STR;
|
||||
const char* LLMediaEntry::HEIGHT_PIXELS_KEY = MEDIA_HEIGHT_PIXELS_KEY_STR;
|
||||
|
||||
// "security" fields
|
||||
const char* LLMediaEntry::WHITELIST_ENABLE_KEY = MEDIA_WHITELIST_ENABLE_KEY_STR;
|
||||
const char* LLMediaEntry::WHITELIST_KEY = MEDIA_WHITELIST_KEY_STR;
|
||||
|
||||
// "permissions" fields
|
||||
const char* LLMediaEntry::PERMS_INTERACT_KEY = MEDIA_PERMS_INTERACT_KEY_STR;
|
||||
const char* LLMediaEntry::PERMS_CONTROL_KEY = MEDIA_PERMS_CONTROL_KEY_STR;
|
||||
|
||||
#define DEFAULT_URL_PREFIX "http://"
|
||||
|
||||
// Constructor(s)
|
||||
LLMediaEntry::LLMediaEntry() :
|
||||
mAltImageEnable(false),
|
||||
mControls(STANDARD),
|
||||
mCurrentURL(""),
|
||||
mHomeURL(""),
|
||||
mAutoLoop(false),
|
||||
mAutoPlay(false),
|
||||
mAutoScale(false),
|
||||
mAutoZoom(false),
|
||||
mFirstClickInteract(false),
|
||||
mWidthPixels(0),
|
||||
mHeightPixels(0),
|
||||
mWhiteListEnable(false),
|
||||
// mWhiteList
|
||||
mPermsInteract(PERM_ALL),
|
||||
mPermsControl(PERM_ALL),
|
||||
mMediaIDp(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
LLMediaEntry::LLMediaEntry(const LLMediaEntry &rhs) :
|
||||
mMediaIDp(NULL)
|
||||
{
|
||||
// "general" fields
|
||||
mAltImageEnable = rhs.mAltImageEnable;
|
||||
mControls = rhs.mControls;
|
||||
mCurrentURL = rhs.mCurrentURL;
|
||||
mHomeURL = rhs.mHomeURL;
|
||||
mAutoLoop = rhs.mAutoLoop;
|
||||
mAutoPlay = rhs.mAutoPlay;
|
||||
mAutoScale = rhs.mAutoScale;
|
||||
mAutoZoom = rhs.mAutoZoom;
|
||||
mFirstClickInteract = rhs.mFirstClickInteract;
|
||||
mWidthPixels = rhs.mWidthPixels;
|
||||
mHeightPixels = rhs.mHeightPixels;
|
||||
|
||||
// "security" fields
|
||||
mWhiteListEnable = rhs.mWhiteListEnable;
|
||||
mWhiteList = rhs.mWhiteList;
|
||||
|
||||
// "permissions" fields
|
||||
mPermsInteract = rhs.mPermsInteract;
|
||||
mPermsControl = rhs.mPermsControl;
|
||||
}
|
||||
|
||||
LLMediaEntry::~LLMediaEntry()
|
||||
{
|
||||
if (NULL != mMediaIDp)
|
||||
{
|
||||
delete mMediaIDp;
|
||||
}
|
||||
}
|
||||
|
||||
LLSD LLMediaEntry::asLLSD() const
|
||||
{
|
||||
LLSD sd;
|
||||
asLLSD(sd);
|
||||
return sd;
|
||||
}
|
||||
|
||||
//
|
||||
// LLSD functions
|
||||
//
|
||||
void LLMediaEntry::asLLSD(LLSD& sd) const
|
||||
{
|
||||
// "general" fields
|
||||
sd[ALT_IMAGE_ENABLE_KEY] = mAltImageEnable;
|
||||
sd[CONTROLS_KEY] = (LLSD::Integer)mControls;
|
||||
sd[CURRENT_URL_KEY] = mCurrentURL;
|
||||
sd[HOME_URL_KEY] = mHomeURL;
|
||||
sd[AUTO_LOOP_KEY] = mAutoLoop;
|
||||
sd[AUTO_PLAY_KEY] = mAutoPlay;
|
||||
sd[AUTO_SCALE_KEY] = mAutoScale;
|
||||
sd[AUTO_ZOOM_KEY] = mAutoZoom;
|
||||
sd[FIRST_CLICK_INTERACT_KEY] = mFirstClickInteract;
|
||||
sd[WIDTH_PIXELS_KEY] = mWidthPixels;
|
||||
sd[HEIGHT_PIXELS_KEY] = mHeightPixels;
|
||||
|
||||
// "security" fields
|
||||
sd[WHITELIST_ENABLE_KEY] = mWhiteListEnable;
|
||||
sd.erase(WHITELIST_KEY);
|
||||
for (U32 i=0; i<mWhiteList.size(); i++)
|
||||
{
|
||||
sd[WHITELIST_KEY].append(mWhiteList[i]);
|
||||
}
|
||||
|
||||
// "permissions" fields
|
||||
sd[PERMS_INTERACT_KEY] = mPermsInteract;
|
||||
sd[PERMS_CONTROL_KEY] = mPermsControl;
|
||||
}
|
||||
|
||||
// static
|
||||
bool LLMediaEntry::checkLLSD(const LLSD& sd)
|
||||
{
|
||||
if (sd.isUndefined()) return true;
|
||||
LLMediaEntry temp;
|
||||
return temp.fromLLSDInternal(sd, true);
|
||||
}
|
||||
|
||||
void LLMediaEntry::fromLLSD(const LLSD& sd)
|
||||
{
|
||||
(void)fromLLSDInternal(sd, true);
|
||||
}
|
||||
|
||||
void LLMediaEntry::mergeFromLLSD(const LLSD& sd)
|
||||
{
|
||||
(void)fromLLSDInternal(sd, false);
|
||||
}
|
||||
|
||||
// *NOTE: returns true if NO failures to set occurred, false otherwise.
|
||||
// However, be aware that if a failure to set does occur, it does
|
||||
// not stop setting fields from the LLSD!
|
||||
bool LLMediaEntry::fromLLSDInternal(const LLSD& sd, bool overwrite)
|
||||
{
|
||||
// *HACK: we sort of cheat here and assume that status is a
|
||||
// bit field. We "or" into status and instead of returning
|
||||
// it, we return whether it finishes off as LSL_STATUS_OK or not.
|
||||
U32 status = LSL_STATUS_OK;
|
||||
|
||||
// "general" fields
|
||||
if ( overwrite || sd.has(ALT_IMAGE_ENABLE_KEY) )
|
||||
{
|
||||
status |= setAltImageEnable( sd[ALT_IMAGE_ENABLE_KEY] );
|
||||
}
|
||||
if ( overwrite || sd.has(CONTROLS_KEY) )
|
||||
{
|
||||
status |= setControls( (MediaControls)(LLSD::Integer)sd[CONTROLS_KEY] );
|
||||
}
|
||||
if ( overwrite || sd.has(CURRENT_URL_KEY) )
|
||||
{
|
||||
// Don't check whitelist
|
||||
status |= setCurrentURLInternal( sd[CURRENT_URL_KEY], false );
|
||||
}
|
||||
if ( overwrite || sd.has(HOME_URL_KEY) )
|
||||
{
|
||||
status |= setHomeURL( sd[HOME_URL_KEY] );
|
||||
}
|
||||
if ( overwrite || sd.has(AUTO_LOOP_KEY) )
|
||||
{
|
||||
status |= setAutoLoop( sd[AUTO_LOOP_KEY] );
|
||||
}
|
||||
if ( overwrite || sd.has(AUTO_PLAY_KEY) )
|
||||
{
|
||||
status |= setAutoPlay( sd[AUTO_PLAY_KEY] );
|
||||
}
|
||||
if ( overwrite || sd.has(AUTO_SCALE_KEY) )
|
||||
{
|
||||
status |= setAutoScale( sd[AUTO_SCALE_KEY] );
|
||||
}
|
||||
if ( overwrite || sd.has(AUTO_ZOOM_KEY) )
|
||||
{
|
||||
status |= setAutoZoom( sd[AUTO_ZOOM_KEY] );
|
||||
}
|
||||
if ( overwrite || sd.has(FIRST_CLICK_INTERACT_KEY) )
|
||||
{
|
||||
status |= setFirstClickInteract( sd[FIRST_CLICK_INTERACT_KEY] );
|
||||
}
|
||||
if ( overwrite || sd.has(WIDTH_PIXELS_KEY) )
|
||||
{
|
||||
status |= setWidthPixels( (LLSD::Integer)sd[WIDTH_PIXELS_KEY] );
|
||||
}
|
||||
if ( overwrite || sd.has(HEIGHT_PIXELS_KEY) )
|
||||
{
|
||||
status |= setHeightPixels( (LLSD::Integer)sd[HEIGHT_PIXELS_KEY] );
|
||||
}
|
||||
|
||||
// "security" fields
|
||||
if ( overwrite || sd.has(WHITELIST_ENABLE_KEY) )
|
||||
{
|
||||
status |= setWhiteListEnable( sd[WHITELIST_ENABLE_KEY] );
|
||||
}
|
||||
if ( overwrite || sd.has(WHITELIST_KEY) )
|
||||
{
|
||||
status |= setWhiteList( sd[WHITELIST_KEY] );
|
||||
}
|
||||
|
||||
// "permissions" fields
|
||||
if ( overwrite || sd.has(PERMS_INTERACT_KEY) )
|
||||
{
|
||||
status |= setPermsInteract( 0xff & (LLSD::Integer)sd[PERMS_INTERACT_KEY] );
|
||||
}
|
||||
if ( overwrite || sd.has(PERMS_CONTROL_KEY) )
|
||||
{
|
||||
status |= setPermsControl( 0xff & (LLSD::Integer)sd[PERMS_CONTROL_KEY] );
|
||||
}
|
||||
|
||||
return LSL_STATUS_OK == status;
|
||||
}
|
||||
|
||||
LLMediaEntry& LLMediaEntry::operator=(const LLMediaEntry &rhs)
|
||||
{
|
||||
if (this != &rhs)
|
||||
{
|
||||
// "general" fields
|
||||
mAltImageEnable = rhs.mAltImageEnable;
|
||||
mControls = rhs.mControls;
|
||||
mCurrentURL = rhs.mCurrentURL;
|
||||
mHomeURL = rhs.mHomeURL;
|
||||
mAutoLoop = rhs.mAutoLoop;
|
||||
mAutoPlay = rhs.mAutoPlay;
|
||||
mAutoScale = rhs.mAutoScale;
|
||||
mAutoZoom = rhs.mAutoZoom;
|
||||
mFirstClickInteract = rhs.mFirstClickInteract;
|
||||
mWidthPixels = rhs.mWidthPixels;
|
||||
mHeightPixels = rhs.mHeightPixels;
|
||||
|
||||
// "security" fields
|
||||
mWhiteListEnable = rhs.mWhiteListEnable;
|
||||
mWhiteList = rhs.mWhiteList;
|
||||
|
||||
// "permissions" fields
|
||||
mPermsInteract = rhs.mPermsInteract;
|
||||
mPermsControl = rhs.mPermsControl;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool LLMediaEntry::operator==(const LLMediaEntry &rhs) const
|
||||
{
|
||||
return (
|
||||
// "general" fields
|
||||
mAltImageEnable == rhs.mAltImageEnable &&
|
||||
mControls == rhs.mControls &&
|
||||
mCurrentURL == rhs.mCurrentURL &&
|
||||
mHomeURL == rhs.mHomeURL &&
|
||||
mAutoLoop == rhs.mAutoLoop &&
|
||||
mAutoPlay == rhs.mAutoPlay &&
|
||||
mAutoScale == rhs.mAutoScale &&
|
||||
mAutoZoom == rhs.mAutoZoom &&
|
||||
mFirstClickInteract == rhs.mFirstClickInteract &&
|
||||
mWidthPixels == rhs.mWidthPixels &&
|
||||
mHeightPixels == rhs.mHeightPixels &&
|
||||
|
||||
// "security" fields
|
||||
mWhiteListEnable == rhs.mWhiteListEnable &&
|
||||
mWhiteList == rhs.mWhiteList &&
|
||||
|
||||
// "permissions" fields
|
||||
mPermsInteract == rhs.mPermsInteract &&
|
||||
mPermsControl == rhs.mPermsControl
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
bool LLMediaEntry::operator!=(const LLMediaEntry &rhs) const
|
||||
{
|
||||
return (
|
||||
// "general" fields
|
||||
mAltImageEnable != rhs.mAltImageEnable ||
|
||||
mControls != rhs.mControls ||
|
||||
mCurrentURL != rhs.mCurrentURL ||
|
||||
mHomeURL != rhs.mHomeURL ||
|
||||
mAutoLoop != rhs.mAutoLoop ||
|
||||
mAutoPlay != rhs.mAutoPlay ||
|
||||
mAutoScale != rhs.mAutoScale ||
|
||||
mAutoZoom != rhs.mAutoZoom ||
|
||||
mFirstClickInteract != rhs.mFirstClickInteract ||
|
||||
mWidthPixels != rhs.mWidthPixels ||
|
||||
mHeightPixels != rhs.mHeightPixels ||
|
||||
|
||||
// "security" fields
|
||||
mWhiteListEnable != rhs.mWhiteListEnable ||
|
||||
mWhiteList != rhs.mWhiteList ||
|
||||
|
||||
// "permissions" fields
|
||||
mPermsInteract != rhs.mPermsInteract ||
|
||||
mPermsControl != rhs.mPermsControl
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
U32 LLMediaEntry::setWhiteList( const std::vector<std::string> &whitelist )
|
||||
{
|
||||
// *NOTE: This code is VERY similar to the setWhitelist below.
|
||||
// IF YOU CHANGE THIS IMPLEMENTATION, BE SURE TO CHANGE THE OTHER!
|
||||
U32 size = 0;
|
||||
U32 count = 0;
|
||||
// First count to make sure the size constraint is not violated
|
||||
std::vector<std::string>::const_iterator iter = whitelist.begin();
|
||||
std::vector<std::string>::const_iterator end = whitelist.end();
|
||||
for ( ; iter < end; ++iter)
|
||||
{
|
||||
const std::string &entry = (*iter);
|
||||
size += entry.length() + 1; // Include one for \0
|
||||
count ++;
|
||||
if (size > MAX_WHITELIST_SIZE || count > MAX_WHITELIST_COUNT)
|
||||
{
|
||||
return LSL_STATUS_BOUNDS_ERROR;
|
||||
}
|
||||
}
|
||||
// Next clear the vector
|
||||
mWhiteList.clear();
|
||||
// Then re-iterate and copy entries
|
||||
iter = whitelist.begin();
|
||||
for ( ; iter < end; ++iter)
|
||||
{
|
||||
const std::string &entry = (*iter);
|
||||
mWhiteList.push_back(entry);
|
||||
}
|
||||
return LSL_STATUS_OK;
|
||||
}
|
||||
|
||||
U32 LLMediaEntry::setWhiteList( const LLSD &whitelist )
|
||||
{
|
||||
// If whitelist is undef, the whitelist is cleared
|
||||
if (whitelist.isUndefined())
|
||||
{
|
||||
mWhiteList.clear();
|
||||
return LSL_STATUS_OK;
|
||||
}
|
||||
|
||||
// However, if the whitelist is an empty array, erase it.
|
||||
if (whitelist.isArray())
|
||||
{
|
||||
// *NOTE: This code is VERY similar to the setWhitelist above.
|
||||
// IF YOU CHANGE THIS IMPLEMENTATION, BE SURE TO CHANGE THE OTHER!
|
||||
U32 size = 0;
|
||||
U32 count = 0;
|
||||
// First check to make sure the size and count constraints are not violated
|
||||
LLSD::array_const_iterator iter = whitelist.beginArray();
|
||||
LLSD::array_const_iterator end = whitelist.endArray();
|
||||
for ( ; iter < end; ++iter)
|
||||
{
|
||||
const std::string &entry = (*iter).asString();
|
||||
size += entry.length() + 1; // Include one for \0
|
||||
count ++;
|
||||
if (size > MAX_WHITELIST_SIZE || count > MAX_WHITELIST_COUNT)
|
||||
{
|
||||
return LSL_STATUS_BOUNDS_ERROR;
|
||||
}
|
||||
}
|
||||
// Next clear the vector
|
||||
mWhiteList.clear();
|
||||
// Then re-iterate and copy entries
|
||||
iter = whitelist.beginArray();
|
||||
for ( ; iter < end; ++iter)
|
||||
{
|
||||
const std::string &entry = (*iter).asString();
|
||||
mWhiteList.push_back(entry);
|
||||
}
|
||||
return LSL_STATUS_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return LSL_STATUS_MALFORMED_PARAMS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void prefix_with(std::string &str, const char *chars, const char *prefix)
|
||||
{
|
||||
// Given string 'str', prefix all instances of any character in 'chars'
|
||||
// with 'prefix'
|
||||
size_t found = str.find_first_of(chars);
|
||||
size_t prefix_len = strlen(prefix);
|
||||
while (found != std::string::npos)
|
||||
{
|
||||
str.insert(found, prefix, prefix_len);
|
||||
found = str.find_first_of(chars, found+prefix_len+1);
|
||||
}
|
||||
}
|
||||
|
||||
static bool pattern_match(const std::string &candidate_str, const std::string &pattern)
|
||||
{
|
||||
// If the pattern is empty, it matches
|
||||
if (pattern.empty()) return true;
|
||||
|
||||
// 'pattern' is a glob pattern, we only accept '*' chars
|
||||
// copy it
|
||||
std::string expression = pattern;
|
||||
|
||||
// Escape perl's regexp chars with a backslash, except all "*" chars
|
||||
prefix_with(expression, ".[{()\\+?|^$", "\\");
|
||||
prefix_with(expression, "*", ".");
|
||||
|
||||
// case-insensitive matching:
|
||||
boost::regex regexp(expression, boost::regex::perl|boost::regex::icase);
|
||||
return boost::regex_match(candidate_str, regexp);
|
||||
}
|
||||
|
||||
bool LLMediaEntry::checkCandidateUrl(const std::string& url) const
|
||||
{
|
||||
if (getWhiteListEnable())
|
||||
{
|
||||
return checkUrlAgainstWhitelist(url, getWhiteList());
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
bool LLMediaEntry::checkUrlAgainstWhitelist(const std::string& url,
|
||||
const std::vector<std::string> &whitelist)
|
||||
{
|
||||
bool passes = true;
|
||||
// *NOTE: no entries? Don't check
|
||||
if (whitelist.size() > 0)
|
||||
{
|
||||
passes = false;
|
||||
|
||||
// Case insensitive: the reason why we toUpper both this and the
|
||||
// filter
|
||||
std::string candidate_url = url;
|
||||
// Use lluri to see if there is a path part in the candidate URL. No path? Assume "/"
|
||||
LLURI candidate_uri(candidate_url);
|
||||
std::vector<std::string>::const_iterator iter = whitelist.begin();
|
||||
std::vector<std::string>::const_iterator end = whitelist.end();
|
||||
for ( ; iter < end; ++iter )
|
||||
{
|
||||
std::string filter = *iter;
|
||||
|
||||
LLURI filter_uri(filter);
|
||||
bool scheme_passes = pattern_match( candidate_uri.scheme(), filter_uri.scheme() );
|
||||
if (filter_uri.scheme().empty())
|
||||
{
|
||||
filter_uri = LLURI(DEFAULT_URL_PREFIX + filter);
|
||||
}
|
||||
bool authority_passes = pattern_match( candidate_uri.authority(), filter_uri.authority() );
|
||||
bool path_passes = pattern_match( candidate_uri.escapedPath(), filter_uri.escapedPath() );
|
||||
|
||||
if (scheme_passes && authority_passes && path_passes)
|
||||
{
|
||||
passes = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return passes;
|
||||
}
|
||||
|
||||
U32 LLMediaEntry::setStringFieldWithLimit( std::string &field, const std::string &value, U32 limit )
|
||||
{
|
||||
if ( value.length() > limit )
|
||||
{
|
||||
return LSL_STATUS_BOUNDS_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
field = value;
|
||||
return LSL_STATUS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
U32 LLMediaEntry::setControls(LLMediaEntry::MediaControls controls)
|
||||
{
|
||||
if (controls == STANDARD ||
|
||||
controls == MINI)
|
||||
{
|
||||
mControls = controls;
|
||||
return LSL_STATUS_OK;
|
||||
}
|
||||
return LSL_STATUS_BOUNDS_ERROR;
|
||||
}
|
||||
|
||||
U32 LLMediaEntry::setPermsInteract( U8 val )
|
||||
{
|
||||
mPermsInteract = val & PERM_MASK;
|
||||
return LSL_STATUS_OK;
|
||||
}
|
||||
|
||||
U32 LLMediaEntry::setPermsControl( U8 val )
|
||||
{
|
||||
mPermsControl = val & PERM_MASK;
|
||||
return LSL_STATUS_OK;
|
||||
}
|
||||
|
||||
U32 LLMediaEntry::setCurrentURL(const std::string& current_url)
|
||||
{
|
||||
return setCurrentURLInternal( current_url, true );
|
||||
}
|
||||
|
||||
U32 LLMediaEntry::setCurrentURLInternal(const std::string& current_url, bool check_whitelist)
|
||||
{
|
||||
if ( ! check_whitelist || checkCandidateUrl(current_url))
|
||||
{
|
||||
return setStringFieldWithLimit( mCurrentURL, current_url, MAX_URL_LENGTH );
|
||||
}
|
||||
else
|
||||
{
|
||||
return LSL_STATUS_WHITELIST_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
U32 LLMediaEntry::setHomeURL(const std::string& home_url)
|
||||
{
|
||||
return setStringFieldWithLimit( mHomeURL, home_url, MAX_URL_LENGTH );
|
||||
}
|
||||
|
||||
U32 LLMediaEntry::setWidthPixels(U16 width)
|
||||
{
|
||||
if (width > MAX_WIDTH_PIXELS) return LSL_STATUS_BOUNDS_ERROR;
|
||||
mWidthPixels = width;
|
||||
return LSL_STATUS_OK;
|
||||
}
|
||||
|
||||
U32 LLMediaEntry::setHeightPixels(U16 height)
|
||||
{
|
||||
if (height > MAX_HEIGHT_PIXELS) return LSL_STATUS_BOUNDS_ERROR;
|
||||
mHeightPixels = height;
|
||||
return LSL_STATUS_OK;
|
||||
}
|
||||
|
||||
const LLUUID &LLMediaEntry::getMediaID() const
|
||||
{
|
||||
// Lazily generate media ID
|
||||
if (NULL == mMediaIDp)
|
||||
{
|
||||
mMediaIDp = new LLUUID();
|
||||
mMediaIDp->generate();
|
||||
}
|
||||
return *mMediaIDp;
|
||||
}
|
||||
|
||||
@@ -83,7 +83,6 @@ LLModel::~LLModel()
|
||||
bool get_dom_sources(const domInputLocalOffset_Array& inputs, S32& pos_offset, S32& tc_offset, S32& norm_offset, S32 &idx_stride,
|
||||
domSource* &pos_source, domSource* &tc_source, domSource* &norm_source)
|
||||
{
|
||||
|
||||
idx_stride = 0;
|
||||
|
||||
for (U32 j = 0; j < inputs.getCount(); ++j)
|
||||
@@ -209,7 +208,6 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa
|
||||
n[idx[i+norm_offset]*3+1],
|
||||
n[idx[i+norm_offset]*3+2]));
|
||||
}
|
||||
|
||||
|
||||
BOOL found = FALSE;
|
||||
|
||||
@@ -276,7 +274,6 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa
|
||||
face = LLVolumeFace();
|
||||
point_map.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!verts.empty())
|
||||
@@ -509,7 +506,7 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac
|
||||
{
|
||||
material = std::string(poly->getMaterial());
|
||||
}
|
||||
|
||||
|
||||
materials.push_back(material);
|
||||
face_list.push_back(face);
|
||||
face_list.rbegin()->fillFromLegacyData(verts, indices);
|
||||
@@ -539,7 +536,6 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac
|
||||
|
||||
const domInputLocalOffset_Array& inputs = poly->getInput_array();
|
||||
|
||||
|
||||
S32 v_offset = -1;
|
||||
S32 n_offset = -1;
|
||||
S32 t_offset = -1;
|
||||
@@ -651,8 +647,7 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac
|
||||
vert.mTexCoord.setVec(t->get(t_idx),
|
||||
t->get(t_idx+1));
|
||||
}
|
||||
|
||||
|
||||
|
||||
verts.push_back(vert);
|
||||
}
|
||||
}
|
||||
@@ -1467,7 +1462,6 @@ LLSD LLModel::writeModel(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LLVector2 tc_range = max_tc - min_tc;
|
||||
|
||||
for (U32 j = 0; j < (U32)face.mNumVertices; ++j)
|
||||
@@ -1983,6 +1977,7 @@ bool LLModel::matchMaterialOrder(LLModel* ref, int& refFaceCnt, int& modelFaceCn
|
||||
|
||||
//build a map of material slot names to face indexes
|
||||
bool reorder = false;
|
||||
|
||||
std::set<std::string> base_mat;
|
||||
std::set<std::string> cur_mat;
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ include(LLRender)
|
||||
include(LLWindow)
|
||||
include(LLVFS)
|
||||
include(LLXML)
|
||||
include(LLXUIXML)
|
||||
|
||||
include_directories(
|
||||
${LLCOMMON_INCLUDE_DIRS}
|
||||
@@ -24,7 +23,6 @@ include_directories(
|
||||
${LLWINDOW_INCLUDE_DIRS}
|
||||
${LLVFS_INCLUDE_DIRS}
|
||||
${LLXML_INCLUDE_DIRS}
|
||||
${LLXUIXML_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
set(llui_SOURCE_FILES
|
||||
@@ -73,6 +71,7 @@ set(llui_SOURCE_FILES
|
||||
lltextparser.cpp
|
||||
lltrans.cpp
|
||||
llui.cpp
|
||||
lluicolor.cpp
|
||||
lluictrl.cpp
|
||||
lluictrlfactory.cpp
|
||||
lluiimage.cpp
|
||||
@@ -142,6 +141,7 @@ set(llui_HEADER_FILES
|
||||
lluictrl.h
|
||||
lluifwd.h
|
||||
llui.h
|
||||
lluicolor.h
|
||||
lluiimage.h
|
||||
lluistring.h
|
||||
lluixmltags.h
|
||||
@@ -165,7 +165,6 @@ target_link_libraries(llui
|
||||
llwindow
|
||||
llimage
|
||||
llvfs # ugh, just for LLDir
|
||||
llxuixml
|
||||
llxml
|
||||
llcommon # must be after llimage, llwindow, llrender
|
||||
llmath
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
# -*- cmake -*-
|
||||
|
||||
project(llxuixml)
|
||||
|
||||
include(00-Common)
|
||||
include(LLCommon)
|
||||
include(LLMath)
|
||||
include(LLXML)
|
||||
|
||||
include_directories(
|
||||
${LLCOMMON_INCLUDE_DIRS}
|
||||
${LLMATH_INCLUDE_DIRS}
|
||||
${LLXML_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
set(llxuixml_SOURCE_FILES
|
||||
llinitparam.cpp
|
||||
lluicolor.cpp
|
||||
)
|
||||
|
||||
set(llxuixml_HEADER_FILES
|
||||
CMakeLists.txt
|
||||
|
||||
llinitparam.h
|
||||
lluicolor.h
|
||||
)
|
||||
|
||||
set_source_files_properties(${llxuixml_HEADER_FILES}
|
||||
PROPERTIES HEADER_FILE_ONLY TRUE)
|
||||
|
||||
list(APPEND llxuixml_SOURCE_FILES ${llxuixml_HEADER_FILES})
|
||||
|
||||
add_library (llxuixml ${llxuixml_SOURCE_FILES})
|
||||
# Libraries on which this library depends, needed for Linux builds
|
||||
# Sort by high-level to low-level
|
||||
target_link_libraries(llxuixml
|
||||
llxml
|
||||
llcommon
|
||||
llmath
|
||||
)
|
||||
@@ -37,7 +37,6 @@ include(LLUI)
|
||||
include(LLVFS)
|
||||
include(LLWindow)
|
||||
include(LLXML)
|
||||
include(LLXUIXML)
|
||||
include(LScript)
|
||||
include(Linking)
|
||||
include(NDOF)
|
||||
@@ -72,7 +71,6 @@ include_directories(
|
||||
${LLVFS_INCLUDE_DIRS}
|
||||
${LLWINDOW_INCLUDE_DIRS}
|
||||
${LLXML_INCLUDE_DIRS}
|
||||
${LLXUIXML_INCLUDE_DIRS}
|
||||
${LSCRIPT_INCLUDE_DIRS}
|
||||
${LSCRIPT_INCLUDE_DIRS}/lscript_compile
|
||||
)
|
||||
@@ -98,11 +96,7 @@ set(viewer_SOURCE_FILES
|
||||
ascentprefschat.cpp
|
||||
ascentprefssys.cpp
|
||||
ascentprefsvan.cpp
|
||||
#dhparam.cpp
|
||||
#dsaparam.cpp
|
||||
emeraldboobutils.cpp
|
||||
dofloaterhex.cpp
|
||||
dohexeditor.cpp
|
||||
floatersculptpreview.cpp
|
||||
hbfloatergrouptitles.cpp
|
||||
hgfloatertexteditor.cpp
|
||||
@@ -115,6 +109,7 @@ set(viewer_SOURCE_FILES
|
||||
jcfloaterareasearch.cpp
|
||||
chatbar_as_cmdline.cpp
|
||||
qtoolalign.cpp
|
||||
NACLantispam.cpp
|
||||
llaccountingcostmanager.cpp
|
||||
llagent.cpp
|
||||
llagentaccess.cpp
|
||||
@@ -152,7 +147,6 @@ set(viewer_SOURCE_FILES
|
||||
llconfirmationmanager.cpp
|
||||
llconsole.cpp
|
||||
llcontainerview.cpp
|
||||
llcurlrequest.cpp
|
||||
llcurrencyuimanager.cpp
|
||||
llcylinder.cpp
|
||||
lldebugmessagebox.cpp
|
||||
@@ -527,7 +521,6 @@ set(viewer_SOURCE_FILES
|
||||
llvopartgroup.cpp
|
||||
llvosky.cpp
|
||||
llvosurfacepatch.cpp
|
||||
llvotextbubble.cpp
|
||||
llvotree.cpp
|
||||
llvovolume.cpp
|
||||
llvowater.cpp
|
||||
@@ -575,6 +568,7 @@ set(viewer_HEADER_FILES
|
||||
CMakeLists.txt
|
||||
ViewerInstall.cmake
|
||||
|
||||
NACLantispam.h
|
||||
sgmemstat.h
|
||||
sgversion.h
|
||||
llviewerobjectbackup.h
|
||||
@@ -594,8 +588,6 @@ set(viewer_HEADER_FILES
|
||||
ascentprefssys.h
|
||||
ascentprefsvan.h
|
||||
emeraldboobutils.h
|
||||
dofloaterhex.h
|
||||
dohexeditor.h
|
||||
floatersculptpreview.h
|
||||
hbfloatergrouptitles.h
|
||||
hgfloatertexteditor.h
|
||||
@@ -648,7 +640,6 @@ set(viewer_HEADER_FILES
|
||||
llconfirmationmanager.h
|
||||
llconsole.h
|
||||
llcontainerview.h
|
||||
llcurlrequest.h
|
||||
llcurrencyuimanager.h
|
||||
llcylinder.h
|
||||
lldebugmessagebox.h
|
||||
@@ -1028,7 +1019,6 @@ set(viewer_HEADER_FILES
|
||||
llvopartgroup.h
|
||||
llvosky.h
|
||||
llvosurfacepatch.h
|
||||
llvotextbubble.h
|
||||
llvotree.h
|
||||
llvotreenew.h
|
||||
llvovolume.h
|
||||
@@ -1550,7 +1540,6 @@ target_link_libraries(${VIEWER_BINARY_NAME}
|
||||
${LLVFS_LIBRARIES}
|
||||
${LLWINDOW_LIBRARIES}
|
||||
${LLXML_LIBRARIES}
|
||||
${LLXUIXML_LIBRARIES}
|
||||
${LSCRIPT_LIBRARIES}
|
||||
${LLMATH_LIBRARIES}
|
||||
${LLCOMMON_LIBRARIES}
|
||||
|
||||
406
indra/newview/NACLantispam.cpp
Normal file
406
indra/newview/NACLantispam.cpp
Normal file
@@ -0,0 +1,406 @@
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
#include "NACLantispam.h"
|
||||
#include "llviewercontrol.h"
|
||||
#include "llnotificationsutil.h"
|
||||
#include "llviewerobjectlist.h"
|
||||
#include "llagent.h"
|
||||
#include <time.h>
|
||||
|
||||
U32 NACLAntiSpamRegistry::globalAmount;
|
||||
U32 NACLAntiSpamRegistry::globalTime;
|
||||
bool NACLAntiSpamRegistry::bGlobalQueue;
|
||||
NACLAntiSpamQueue* NACLAntiSpamRegistry::queues[NACLAntiSpamRegistry::QUEUE_MAX] = {0};
|
||||
std::tr1::unordered_map<std::string,NACLAntiSpamQueueEntry*> NACLAntiSpamRegistry::globalEntries;
|
||||
std::tr1::unordered_map<std::string,NACLAntiSpamQueueEntry*>::iterator NACLAntiSpamRegistry::it2;
|
||||
|
||||
const std::string COLLISION_SOUNDS[] ={"dce5fdd4-afe4-4ea1-822f-dd52cac46b08","51011582-fbca-4580-ae9e-1a5593f094ec","68d62208-e257-4d0c-bbe2-20c9ea9760bb","75872e8c-bc39-451b-9b0b-042d7ba36cba","6a45ba0b-5775-4ea8-8513-26008a17f873","992a6d1b-8c77-40e0-9495-4098ce539694","2de4da5a-faf8-46be-bac6-c4d74f1e5767","6e3fb0f7-6d9c-42ca-b86b-1122ff562d7d","14209133-4961-4acc-9649-53fc38ee1667","bc4a4348-cfcc-4e5e-908e-8a52a8915fe6","9e5c1297-6eed-40c0-825a-d9bcd86e3193","e534761c-1894-4b61-b20c-658a6fb68157","8761f73f-6cf9-4186-8aaa-0948ed002db1","874a26fd-142f-4173-8c5b-890cd846c74d","0e24a717-b97e-4b77-9c94-b59a5a88b2da","75cf3ade-9a5b-4c4d-bb35-f9799bda7fb2","153c8bf7-fb89-4d89-b263-47e58b1b4774","55c3e0ce-275a-46fa-82ff-e0465f5e8703","24babf58-7156-4841-9a3f-761bdbb8e237","aca261d8-e145-4610-9e20-9eff990f2c12","0642fba6-5dcf-4d62-8e7b-94dbb529d117","25a863e8-dc42-4e8a-a357-e76422ace9b5","9538f37c-456e-4047-81be-6435045608d4","8c0f84c3-9afd-4396-b5f5-9bca2c911c20","be582e5d-b123-41a2-a150-454c39e961c8","c70141d4-ba06-41ea-bcbc-35ea81cb8335","7d1826f4-24c4-4aac-8c2e-eff45df37783","063c97d3-033a-4e9b-98d8-05c8074922cb","00000000-0000-0000-0000-000000000120"};
|
||||
const int COLLISION_SOUNDS_SIZE=29;
|
||||
|
||||
// NaClAntiSpamQueueEntry
|
||||
|
||||
NACLAntiSpamQueueEntry::NACLAntiSpamQueueEntry()
|
||||
{
|
||||
entryTime=0;
|
||||
entryAmount=0;
|
||||
blocked=false;
|
||||
}
|
||||
void NACLAntiSpamQueueEntry::clearEntry()
|
||||
{
|
||||
entryTime=0;
|
||||
entryAmount=0;
|
||||
blocked=false;
|
||||
}
|
||||
U32 NACLAntiSpamQueueEntry::getEntryAmount()
|
||||
{
|
||||
return entryAmount;
|
||||
}
|
||||
U32 NACLAntiSpamQueueEntry::getEntryTime()
|
||||
{
|
||||
return entryTime;
|
||||
}
|
||||
void NACLAntiSpamQueueEntry::updateEntryAmount()
|
||||
{
|
||||
entryAmount++;
|
||||
}
|
||||
void NACLAntiSpamQueueEntry::updateEntryTime()
|
||||
{
|
||||
entryTime=time(0);
|
||||
}
|
||||
void NACLAntiSpamQueueEntry::setBlocked()
|
||||
{
|
||||
blocked=true;
|
||||
}
|
||||
bool NACLAntiSpamQueueEntry::getBlocked()
|
||||
{
|
||||
return blocked;
|
||||
}
|
||||
|
||||
// NaClAntiSpamQueue
|
||||
|
||||
NACLAntiSpamQueue::NACLAntiSpamQueue(U32 time, U32 amount)
|
||||
{
|
||||
queueTime=time;
|
||||
queueAmount=amount;
|
||||
}
|
||||
void NACLAntiSpamQueue::setAmount(U32 amount)
|
||||
{
|
||||
queueAmount=amount;
|
||||
}
|
||||
void NACLAntiSpamQueue::setTime(U32 time)
|
||||
{
|
||||
queueTime=time;
|
||||
}
|
||||
void NACLAntiSpamQueue::clearEntries()
|
||||
{
|
||||
for(it = entries.begin(); it != entries.end(); it++)
|
||||
{
|
||||
it->second->clearEntry();
|
||||
}
|
||||
}
|
||||
void NACLAntiSpamQueue::purgeEntries()
|
||||
{
|
||||
for(it = entries.begin(); it != entries.end(); it++)
|
||||
{
|
||||
delete it->second;
|
||||
}
|
||||
entries.clear();
|
||||
}
|
||||
void NACLAntiSpamQueue::blockEntry(LLUUID& source)
|
||||
{
|
||||
it=entries.find(source.asString());
|
||||
if(it == entries.end())
|
||||
{
|
||||
entries[source.asString()]=new NACLAntiSpamQueueEntry();
|
||||
}
|
||||
entries[source.asString()]->setBlocked();
|
||||
}
|
||||
int NACLAntiSpamQueue::checkEntry(LLUUID& name, U32 multiplier)
|
||||
{
|
||||
it=entries.find(name.asString());
|
||||
if(it != entries.end())
|
||||
{
|
||||
if(it->second->getBlocked()) return 2;
|
||||
U32 eTime=it->second->getEntryTime();
|
||||
U32 currentTime=time(0);
|
||||
if((currentTime-eTime) <= queueTime)
|
||||
{
|
||||
it->second->updateEntryAmount();
|
||||
U32 eAmount=it->second->getEntryAmount();
|
||||
if(eAmount > (queueAmount*multiplier))
|
||||
{
|
||||
it->second->setBlocked();
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
it->second->clearEntry();
|
||||
it->second->updateEntryAmount();
|
||||
it->second->updateEntryTime();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
entries[name.asString()]=new NACLAntiSpamQueueEntry();
|
||||
entries[name.asString()]->updateEntryAmount();
|
||||
entries[name.asString()]->updateEntryTime();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// NaClAntiSpamRegistry
|
||||
|
||||
static const char* QUEUE_NAME[NACLAntiSpamRegistry::QUEUE_MAX] = {
|
||||
"Chat",
|
||||
"Inventory",
|
||||
"Instant Message",
|
||||
"Calling Card",
|
||||
"Sound",
|
||||
"Sound Preload",
|
||||
"Script Dialog",
|
||||
"Teleport"};
|
||||
|
||||
NACLAntiSpamRegistry::NACLAntiSpamRegistry(U32 time, U32 amount)
|
||||
{
|
||||
globalTime=time;
|
||||
globalAmount=amount;
|
||||
static LLCachedControl<bool> _NACL_AntiSpamGlobalQueue(gSavedSettings,"_NACL_AntiSpamGlobalQueue");
|
||||
bGlobalQueue=_NACL_AntiSpamGlobalQueue;
|
||||
for(int queue = 0; queue < QUEUE_MAX; ++queue)
|
||||
{
|
||||
queues[queue] = new NACLAntiSpamQueue(time,amount);
|
||||
}
|
||||
}
|
||||
const char* NACLAntiSpamRegistry::getQueueName(U32 queue_id)
|
||||
{
|
||||
if(queue_id >= QUEUE_MAX)
|
||||
return "Unknown";
|
||||
return QUEUE_NAME[queue_id];
|
||||
}
|
||||
void NACLAntiSpamRegistry::registerQueues(U32 time, U32 amount)
|
||||
{
|
||||
globalTime=time;
|
||||
globalAmount=amount;
|
||||
static LLCachedControl<bool> _NACL_AntiSpamGlobalQueue(gSavedSettings,"_NACL_AntiSpamGlobalQueue");
|
||||
bGlobalQueue=_NACL_AntiSpamGlobalQueue;
|
||||
for(int queue = 0; queue < QUEUE_MAX; ++queue)
|
||||
{
|
||||
queues[queue] = new NACLAntiSpamQueue(time,amount);
|
||||
}
|
||||
}
|
||||
void NACLAntiSpamRegistry::registerQueue(U32 name, U32 time, U32 amount)
|
||||
{
|
||||
/*
|
||||
it=queues.find(name);
|
||||
if(it == queues.end())
|
||||
{
|
||||
queues[name]=new NACLAntiSpamQueue(time,amount);
|
||||
}
|
||||
*/
|
||||
}
|
||||
void NACLAntiSpamRegistry::setRegisteredQueueTime(U32 name, U32 time)
|
||||
{
|
||||
if(name >= QUEUE_MAX || queues[name] == 0)
|
||||
{
|
||||
LL_ERRS("AntiSpam") << "CODE BUG: Attempting to use a antispam queue that was not created or was outside of the reasonable range of queues. Queue: " << getQueueName(name) << llendl;
|
||||
return;
|
||||
}
|
||||
|
||||
queues[name]->setTime(time);
|
||||
}
|
||||
void NACLAntiSpamRegistry::setRegisteredQueueAmount(U32 name, U32 amount)
|
||||
{
|
||||
if(name >= QUEUE_MAX || queues[name] == 0)
|
||||
{
|
||||
LL_ERRS("AntiSpam") << "CODE BUG: Attempting to use a antispam queue that was not created or was outside of the reasonable range of queues. Queue: " << getQueueName(name) << llendl;
|
||||
return;
|
||||
}
|
||||
|
||||
queues[name]->setAmount(amount);
|
||||
}
|
||||
void NACLAntiSpamRegistry::setAllQueueTimes(U32 time)
|
||||
{
|
||||
globalTime=time;
|
||||
for(int queue = 0; queue < QUEUE_MAX; ++queue)
|
||||
queues[queue]->setTime(time);
|
||||
}
|
||||
void NACLAntiSpamRegistry::setAllQueueAmounts(U32 amount)
|
||||
{
|
||||
globalAmount=amount;
|
||||
for(int queue = 0; queue < QUEUE_MAX; ++queue)
|
||||
{
|
||||
if(queue == QUEUE_SOUND || queue == QUEUE_SOUND_PRELOAD)
|
||||
queues[queue]->setAmount(amount*5);
|
||||
else
|
||||
queues[queue]->setAmount(amount);
|
||||
}
|
||||
}
|
||||
void NACLAntiSpamRegistry::clearRegisteredQueue(U32 name)
|
||||
{
|
||||
if(name >= QUEUE_MAX || queues[name] == 0)
|
||||
{
|
||||
LL_ERRS("AntiSpam") << "CODE BUG: Attempting to use a antispam queue that was not created or was outside of the reasonable range of queues. Queue: " << getQueueName(name) << llendl;
|
||||
return;
|
||||
}
|
||||
|
||||
queues[name]->clearEntries();
|
||||
}
|
||||
void NACLAntiSpamRegistry::purgeRegisteredQueue(U32 name)
|
||||
{
|
||||
if(name >= QUEUE_MAX || queues[name] == 0)
|
||||
{
|
||||
LL_ERRS("AntiSpam") << "CODE BUG: Attempting to use a antispam queue that was not created or was outside of the reasonable range of queues. Queue: " << getQueueName(name) << llendl;
|
||||
return;
|
||||
}
|
||||
|
||||
queues[name]->purgeEntries();
|
||||
}
|
||||
void NACLAntiSpamRegistry::blockOnQueue(U32 name, LLUUID& source)
|
||||
{
|
||||
if(bGlobalQueue)
|
||||
{
|
||||
NACLAntiSpamRegistry::blockGlobalEntry(source);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(name >= QUEUE_MAX || queues[name] == 0)
|
||||
{
|
||||
LL_ERRS("AntiSpam") << "CODE BUG: Attempting to use a antispam queue that was not created or was outside of the reasonable range of queues. Queue: " << getQueueName(name) << llendl;
|
||||
return;
|
||||
}
|
||||
queues[name]->blockEntry(source);
|
||||
}
|
||||
}
|
||||
void NACLAntiSpamRegistry::blockGlobalEntry(LLUUID& source)
|
||||
{
|
||||
it2=globalEntries.find(source.asString());
|
||||
if(it2 == globalEntries.end())
|
||||
{
|
||||
globalEntries[source.asString()]=new NACLAntiSpamQueueEntry();
|
||||
}
|
||||
globalEntries[source.asString()]->setBlocked();
|
||||
}
|
||||
bool NACLAntiSpamRegistry::checkQueue(U32 name, LLUUID& source, U32 multiplier, bool silent)
|
||||
{
|
||||
if(source.isNull()) return false;
|
||||
if(gAgent.getID() == source) return false;
|
||||
LLViewerObject *obj=gObjectList.findObject(source);
|
||||
if(obj)
|
||||
if(obj->permYouOwner()) return false;
|
||||
|
||||
int result;
|
||||
if(bGlobalQueue)
|
||||
{
|
||||
result=NACLAntiSpamRegistry::checkGlobalEntry(source,multiplier);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(name >= QUEUE_MAX || queues[name] == 0)
|
||||
{
|
||||
LL_ERRS("AntiSpam") << "CODE BUG: Attempting to use a antispam queue that was not created or was outside of the reasonable range of queues. Queue: " << getQueueName(name) << llendl;
|
||||
return false;
|
||||
}
|
||||
result=queues[name]->checkEntry(source,multiplier);
|
||||
}
|
||||
if(result==0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if(result==2)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!silent)
|
||||
{
|
||||
LLSD args;
|
||||
args["MESSAGE"] = std::string(getQueueName(name))+": Blocked object "+source.asString();
|
||||
LLNotificationsUtil::add("SystemMessageTip", args);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Global queue stoof
|
||||
void NACLAntiSpamRegistry::setGlobalQueue(bool value)
|
||||
{
|
||||
NACLAntiSpamRegistry::purgeAllQueues();
|
||||
bGlobalQueue=value;
|
||||
}
|
||||
void NACLAntiSpamRegistry::setGlobalAmount(U32 amount)
|
||||
{
|
||||
globalAmount=amount;
|
||||
}
|
||||
void NACLAntiSpamRegistry::setGlobalTime(U32 time)
|
||||
{
|
||||
globalTime=time;
|
||||
}
|
||||
void NACLAntiSpamRegistry::clearAllQueues()
|
||||
{
|
||||
if(bGlobalQueue)
|
||||
NACLAntiSpamRegistry::clearGlobalEntries();
|
||||
else
|
||||
for(int queue = 0; queue < QUEUE_MAX; ++queue)
|
||||
{
|
||||
queues[queue]->clearEntries();
|
||||
}
|
||||
}
|
||||
void NACLAntiSpamRegistry::purgeAllQueues()
|
||||
{
|
||||
if(bGlobalQueue)
|
||||
NACLAntiSpamRegistry::purgeGlobalEntries();
|
||||
else
|
||||
for(int queue = 0; queue < QUEUE_MAX; ++queue)
|
||||
{
|
||||
queues[queue]->purgeEntries();
|
||||
}
|
||||
}
|
||||
int NACLAntiSpamRegistry::checkGlobalEntry(LLUUID& name, U32 multiplier)
|
||||
{
|
||||
it2=globalEntries.find(name.asString());
|
||||
if(it2 != globalEntries.end())
|
||||
{
|
||||
if(it2->second->getBlocked()) return 2;
|
||||
U32 eTime=it2->second->getEntryTime();
|
||||
U32 currentTime=time(0);
|
||||
if((currentTime-eTime) <= globalTime)
|
||||
{
|
||||
it2->second->updateEntryAmount();
|
||||
U32 eAmount=it2->second->getEntryAmount();
|
||||
if(eAmount > (globalAmount*multiplier))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
it2->second->clearEntry();
|
||||
it2->second->updateEntryAmount();
|
||||
it2->second->updateEntryTime();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
globalEntries[name.asString()]=new NACLAntiSpamQueueEntry();
|
||||
globalEntries[name.asString()]->updateEntryAmount();
|
||||
globalEntries[name.asString()]->updateEntryTime();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
void NACLAntiSpamRegistry::clearGlobalEntries()
|
||||
{
|
||||
for(it2 = globalEntries.begin(); it2 != globalEntries.end(); it2++)
|
||||
{
|
||||
it2->second->clearEntry();
|
||||
}
|
||||
}
|
||||
void NACLAntiSpamRegistry::purgeGlobalEntries()
|
||||
{
|
||||
for(it2 = globalEntries.begin(); it2 != globalEntries.end(); it2++)
|
||||
{
|
||||
delete it2->second;
|
||||
it2->second = 0;
|
||||
}
|
||||
globalEntries.clear();
|
||||
}
|
||||
bool NACLAntiSpamRegistry::handleNaclAntiSpamGlobalQueueChanged(const LLSD& newvalue)
|
||||
{
|
||||
setGlobalQueue(newvalue.asBoolean());
|
||||
return true;
|
||||
}
|
||||
bool NACLAntiSpamRegistry::handleNaclAntiSpamTimeChanged(const LLSD& newvalue)
|
||||
{
|
||||
setAllQueueTimes(newvalue.asInteger());
|
||||
return true;
|
||||
}
|
||||
bool NACLAntiSpamRegistry::handleNaclAntiSpamAmountChanged(const LLSD& newvalue)
|
||||
{
|
||||
setAllQueueAmounts(newvalue.asInteger());
|
||||
return true;
|
||||
}
|
||||
|
||||
93
indra/newview/NACLantispam.h
Normal file
93
indra/newview/NACLantispam.h
Normal file
@@ -0,0 +1,93 @@
|
||||
#ifndef NACLANTISPAM_H
|
||||
#define NACLANTISPAM_H
|
||||
#include <boost/tr1/unordered_map.hpp>
|
||||
#include "stdtypes.h"
|
||||
#include "lluuid.h"
|
||||
class NACLAntiSpamQueueEntry
|
||||
{
|
||||
friend class NACLAntiSpamQueue;
|
||||
friend class NACLAntiSpamRegistry;
|
||||
protected:
|
||||
NACLAntiSpamQueueEntry();
|
||||
void clearEntry();
|
||||
U32 getEntryAmount();
|
||||
U32 getEntryTime();
|
||||
void updateEntryAmount();
|
||||
void updateEntryTime();
|
||||
bool getBlocked();
|
||||
void setBlocked();
|
||||
private:
|
||||
U32 entryAmount;
|
||||
U32 entryTime;
|
||||
bool blocked;
|
||||
};
|
||||
class NACLAntiSpamQueue
|
||||
{
|
||||
friend class NACLAntiSpamRegistry;
|
||||
protected:
|
||||
NACLAntiSpamQueue(U32 time, U32 amount);
|
||||
void setAmount(U32 amount);
|
||||
void setTime(U32 time);
|
||||
void clearEntries();
|
||||
void purgeEntries();
|
||||
void blockEntry(LLUUID& source);
|
||||
int checkEntry(LLUUID& source, U32 multiplier);
|
||||
private:
|
||||
std::tr1::unordered_map<std::string,NACLAntiSpamQueueEntry*> entries;
|
||||
std::tr1::unordered_map<std::string,NACLAntiSpamQueueEntry*>::iterator it;
|
||||
U32 queueAmount;
|
||||
U32 queueTime;
|
||||
};
|
||||
class NACLAntiSpamRegistry
|
||||
{
|
||||
public:
|
||||
NACLAntiSpamRegistry(U32 time=2, U32 amount=10);
|
||||
static void registerQueues(U32 time=2, U32 amount=10);
|
||||
static void registerQueue(U32 name, U32 time, U32 amount);
|
||||
static void setRegisteredQueueTime(U32 name, U32 time);
|
||||
static void setRegisteredQueueAmount(U32 name,U32 amount);
|
||||
static void setAllQueueTimes(U32 amount);
|
||||
static void setAllQueueAmounts(U32 time);
|
||||
static bool checkQueue(U32 name, LLUUID& source, U32 multiplier=1, bool silent=false);
|
||||
static bool handleNaclAntiSpamGlobalQueueChanged(const LLSD& newvalue);
|
||||
static bool handleNaclAntiSpamTimeChanged(const LLSD& newvalue);
|
||||
static bool handleNaclAntiSpamAmountChanged(const LLSD& newvalue);
|
||||
static void clearRegisteredQueue(U32 name);
|
||||
static void purgeRegisteredQueue(U32 name);
|
||||
static void clearAllQueues();
|
||||
static void purgeAllQueues();
|
||||
static void setGlobalQueue(bool value);
|
||||
static void setGlobalAmount(U32 amount);
|
||||
static void setGlobalTime(U32 time);
|
||||
static void blockOnQueue(U32 name,LLUUID& owner_id);
|
||||
enum {
|
||||
QUEUE_CHAT,
|
||||
QUEUE_INVENTORY,
|
||||
QUEUE_IM,
|
||||
QUEUE_CALLING_CARD,
|
||||
QUEUE_SOUND,
|
||||
QUEUE_SOUND_PRELOAD,
|
||||
QUEUE_SCRIPT_DIALOG,
|
||||
QUEUE_TELEPORT,
|
||||
QUEUE_MAX
|
||||
};
|
||||
private:
|
||||
static const char* getQueueName(U32 queue_id);
|
||||
static NACLAntiSpamQueue* queues[QUEUE_MAX];
|
||||
static std::tr1::unordered_map<std::string,NACLAntiSpamQueueEntry*> globalEntries;
|
||||
static std::tr1::unordered_map<std::string,NACLAntiSpamQueueEntry*>::iterator it2;
|
||||
static U32 globalTime;
|
||||
static U32 globalAmount;
|
||||
static bool bGlobalQueue;
|
||||
|
||||
static int checkGlobalEntry(LLUUID& source, U32 multiplier);
|
||||
static void clearGlobalEntries();
|
||||
static void purgeGlobalEntries();
|
||||
static void blockGlobalEntry(LLUUID& source);
|
||||
};
|
||||
|
||||
|
||||
extern const std::string COLLISION_SOUNDS[];
|
||||
extern const int COLLISION_SOUNDS_SIZE;
|
||||
|
||||
#endif //NACLANTISPAM_H
|
||||
@@ -8,7 +8,6 @@
|
||||
<string>settings_sh.xml</string>
|
||||
<string>settings_rlv.xml</string>
|
||||
</array>
|
||||
|
||||
<key>SianaRenderDeferredInvisiprim</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -894,6 +893,83 @@
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>_NACL_Antispam</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>When true, all dialogs will be blocked, resets on restart.</string>
|
||||
<key>Persist</key>
|
||||
<integer>0</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>_NACL_AntiSpamGlobalQueue</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string> </string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>_NACL_AntiSpamTime</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string> </string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>U32</string>
|
||||
<key>Value</key>
|
||||
<integer>2</integer>
|
||||
</map>
|
||||
<key>_NACL_AntiSpamAmount</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string> </string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>U32</string>
|
||||
<key>Value</key>
|
||||
<integer>10</integer>
|
||||
</map>
|
||||
<key>_NACL_AntiSpamSoundMulti</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string> </string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>U32</string>
|
||||
<key>Value</key>
|
||||
<integer>4</integer>
|
||||
</map>
|
||||
<key>_NACL_AntiSpamNewlines</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>How many newlines a message can have before it's considered spam.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>U32</string>
|
||||
<key>Value</key>
|
||||
<integer>30</integer>
|
||||
</map>
|
||||
<key>_NACL_AntiSpamSoundPreloadMulti</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string> </string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>U32</string>
|
||||
<key>Value</key>
|
||||
<integer>4</integer>
|
||||
</map>
|
||||
<!-- Vanilla SL settings that are now optionally Account-Specific -->
|
||||
<key>AgentChatColor</key>
|
||||
@@ -1725,6 +1801,17 @@
|
||||
<key>Value</key>
|
||||
<real>1.0</real>
|
||||
</map>
|
||||
<key>AudioLevelUnderwaterRolloff</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Controls the distance-based dropoff of audio volume when camera is submerged (fraction or multiple of default audio rolloff)</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>F32</string>
|
||||
<key>Value</key>
|
||||
<real>4.0</real>
|
||||
</map>
|
||||
<key>AudioLevelSFX</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -1796,7 +1883,7 @@
|
||||
<key>Comment</key>
|
||||
<string>Enable texture auditting.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<integer>0</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
@@ -4006,6 +4093,17 @@
|
||||
<key>Value</key>
|
||||
<real>120.0</real>
|
||||
</map>
|
||||
<key>CurlUseMultipleThreads</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Use background threads for executing curl_multi_perform (requires restart)</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>Cursor3D</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -15086,3 +15184,4 @@
|
||||
</map>
|
||||
</map>
|
||||
</llsd>
|
||||
|
||||
|
||||
@@ -141,94 +141,6 @@
|
||||
<real>1.0</real>
|
||||
</map>
|
||||
|
||||
<key>SGBlockGeneralSpam</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Enable automatic general spam blocking</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>SGBlockCardSpam</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Enable automatic calling card spam blocking</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>SGBlockChatSpam</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Enable automatic chat spam blocking</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>SGBlockDialogSpam</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Enable automatic dialog spam blocking</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>SGSpamTime</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Time of Evalulating spam. (Default: 1.000)</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>F32</string>
|
||||
<key>Value</key>
|
||||
<real>1.0</real>
|
||||
</map>
|
||||
<key>SGSpamCount</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Number of items spammed per time period in SGSpamTime. (Default: 4)</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>U32</string>
|
||||
<key>Value</key>
|
||||
<real>4</real>
|
||||
</map>
|
||||
<key>SGChatSpamTime</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Time of Evalulating spam. (Default: 1.000)</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>F32</string>
|
||||
<key>Value</key>
|
||||
<real>1.0</real>
|
||||
</map>
|
||||
<key>SGChatSpamCount</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Number of items spammed per time set in SGSpamTime. (Default: 10)</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>U32</string>
|
||||
<key>Value</key>
|
||||
<real>10.0</real>
|
||||
</map>
|
||||
<key>ShyotlUseLegacyTextureBatching</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "llradiogroup.h"
|
||||
#include "lluictrlfactory.h"
|
||||
#include "llviewercontrol.h"
|
||||
#include "NACLantispam.h"
|
||||
#include "lgghunspell_wrapper.h"
|
||||
|
||||
#include "llstartup.h"
|
||||
@@ -78,7 +79,8 @@ LLPrefsAscentChat::LLPrefsAscentChat()
|
||||
addChild(mObjectDropTarget);
|
||||
}
|
||||
|
||||
if (LLStartUp::getStartupState() == STATE_STARTED)
|
||||
bool started = LLStartUp::getStartupState() == STATE_STARTED;
|
||||
if (started)
|
||||
{
|
||||
LLUUID itemid = (LLUUID)gSavedPerAccountSettings.getString("AscentInstantMessageResponseItemData");
|
||||
LLViewerInventoryItem* item = gInventory.getItem(itemid);
|
||||
@@ -91,6 +93,9 @@ LLPrefsAscentChat::LLPrefsAscentChat()
|
||||
|
||||
childSetCommitCallback("im_response", onCommitAutoResponse, this);
|
||||
|
||||
childSetEnabled("reset_antispam", started);
|
||||
childSetCommitCallback("reset_antispam", onCommitResetAS, this);
|
||||
|
||||
childSetCommitCallback("KeywordsOn", onCommitKeywords, this);
|
||||
childSetCommitCallback("KeywordsList", onCommitKeywords, this);
|
||||
childSetCommitCallback("KeywordsSound", onCommitKeywords, this);
|
||||
@@ -218,7 +223,7 @@ void LLPrefsAscentChat::onCommitTimeDate(LLUICtrl* ctrl, void* userdata)
|
||||
//static
|
||||
void LLPrefsAscentChat::onCommitAutoResponse(LLUICtrl* ctrl, void* user_data)
|
||||
{
|
||||
LLPrefsAscentChat* self = (LLPrefsAscentChat*)user_data;
|
||||
LLPrefsAscentChat* self = (LLPrefsAscentChat*)user_data;
|
||||
|
||||
gSavedPerAccountSettings.setBOOL("AscentInstantMessageResponseAnyone", self->childGetValue("AscentInstantMessageResponseAnyone"));
|
||||
gSavedPerAccountSettings.setBOOL("AscentInstantMessageResponseFriends", self->childGetValue("AscentInstantMessageResponseFriends"));
|
||||
@@ -237,6 +242,12 @@ void LLPrefsAscentChat::SinguIMResponseItemDrop(LLViewerInventoryItem* item)
|
||||
sInst->childSetValue("im_give_disp_rect_txt","Currently set to: "+item->getName());
|
||||
}
|
||||
|
||||
//static
|
||||
void LLPrefsAscentChat::onCommitResetAS(LLUICtrl*, void*)
|
||||
{
|
||||
NACLAntiSpamRegistry::purgeAllQueues();
|
||||
}
|
||||
|
||||
//static
|
||||
void LLPrefsAscentChat::onCommitKeywords(LLUICtrl* ctrl, void* user_data)
|
||||
{
|
||||
@@ -316,13 +327,13 @@ void LLPrefsAscentChat::refreshValues()
|
||||
mIMResponseText = gSavedPerAccountSettings.getString("AscentInstantMessageResponse");
|
||||
|
||||
//Spam --------------------------------------------------------------------------------
|
||||
mBlockChatSpam = gSavedSettings.getBOOL("SGBlockChatSpam");
|
||||
mChatSpamCount = gSavedSettings.getU32("SGChatSpamCount");
|
||||
mChatSpamTime = gSavedSettings.getF32("SGChatSpamTime");
|
||||
mBlockDialogSpam = gSavedSettings.getBOOL("SGBlockDialogSpam");
|
||||
mBlockCardSpam = gSavedSettings.getBOOL("SGBlockCardSpam");
|
||||
mSpamCount = gSavedSettings.getU32("SGSpamCount");
|
||||
mSpamTime = gSavedSettings.getF32("SGSpamTime");
|
||||
mGlobalQueue = gSavedSettings.getBOOL("_NACL_AntiSpamGlobalQueue");
|
||||
mChatSpamCount = gSavedSettings.getU32("_NACL_AntiSpamAmount");
|
||||
mChatSpamTime = gSavedSettings.getU32("_NACL_AntiSpamTime");
|
||||
mBlockDialogSpam = gSavedSettings.getBOOL("_NACL_Antispam");
|
||||
mSoundMulti = gSavedSettings.getU32("_NACL_AntiSpamSoundMulti");
|
||||
mNewLines = gSavedSettings.getU32("_NACL_AntiSpamNewlines");
|
||||
mPreloadMulti = gSavedSettings.getU32("_NACL_AntiSpamSoundPreloadMulti");
|
||||
|
||||
//Text Options ------------------------------------------------------------------------
|
||||
mSpellDisplay = gSavedSettings.getBOOL("SpellDisplay");
|
||||
@@ -503,13 +514,13 @@ void LLPrefsAscentChat::cancel()
|
||||
gSavedPerAccountSettings.setString("AscentInstantMessageResponse", mIMResponseText);
|
||||
|
||||
//Spam --------------------------------------------------------------------------------
|
||||
gSavedSettings.setBOOL("SGBlockChatSpam", mBlockChatSpam);
|
||||
gSavedSettings.setU32("SGChatSpamCount", mChatSpamCount);
|
||||
gSavedSettings.setF32("SGChatSpamTime", mChatSpamTime);
|
||||
gSavedSettings.setBOOL("SGBlockDialogSpam", mBlockDialogSpam);
|
||||
gSavedSettings.setBOOL("SGBlockCardSpam", mBlockCardSpam);
|
||||
gSavedSettings.setU32("SGSpamCount", mSpamCount);
|
||||
gSavedSettings.setF32("SGSpamTime", mSpamTime);
|
||||
gSavedSettings.setBOOL("_NACL_AntiSpamGlobalQueue", mGlobalQueue);
|
||||
gSavedSettings.setU32("_NACL_AntiSpamAmount", mChatSpamCount);
|
||||
gSavedSettings.setU32("_NACL_AntiSpamTime", mChatSpamTime);
|
||||
gSavedSettings.setBOOL("_NACL_Antispam", mBlockDialogSpam);
|
||||
gSavedSettings.setU32("_NACL_AntiSpamSoundMulti", mSoundMulti);
|
||||
gSavedSettings.setU32("_NACL_AntiSpamNewlines", mNewLines);
|
||||
gSavedSettings.setU32("_NACL_AntiSpamSoundPreloadMulti", mPreloadMulti);
|
||||
|
||||
//Text Options ------------------------------------------------------------------------
|
||||
gSavedSettings.setBOOL("SpellDisplay", mSpellDisplay);
|
||||
|
||||
@@ -56,6 +56,7 @@ protected:
|
||||
static void onSpellBaseComboBoxCommit(LLUICtrl* ctrl, void* userdata);
|
||||
static void onCommitTimeDate(LLUICtrl* ctrl, void *userdata);
|
||||
static void onCommitAutoResponse(LLUICtrl* ctrl, void* user_data);
|
||||
static void onCommitResetAS(LLUICtrl*,void*);
|
||||
static void onCommitKeywords(LLUICtrl* ctrl, void* user_data);
|
||||
|
||||
//Chat/IM -----------------------------------------------------------------------------
|
||||
@@ -84,13 +85,13 @@ protected:
|
||||
std::string mIMResponseText;
|
||||
|
||||
//Spam --------------------------------------------------------------------------------
|
||||
BOOL mBlockChatSpam;
|
||||
BOOL mGlobalQueue;
|
||||
U32 mChatSpamCount;
|
||||
F32 mChatSpamTime;
|
||||
U32 mChatSpamTime;
|
||||
BOOL mBlockDialogSpam;
|
||||
BOOL mBlockCardSpam;
|
||||
U32 mSpamCount;
|
||||
F32 mSpamTime;
|
||||
BOOL mSoundMulti;
|
||||
U32 mNewLines;
|
||||
U32 mPreloadMulti;
|
||||
|
||||
//Text Options ------------------------------------------------------------------------
|
||||
BOOL mSpellDisplay;
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
/* Generated using openssl */
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
#include <openssl/dh.h>
|
||||
|
||||
DH *get_dh2048()
|
||||
{
|
||||
static unsigned char dh2048_p[]={
|
||||
0xAC,0x31,0xAA,0xFD,0x76,0x1B,0x47,0x24,0x99,0x6D,0xF8,0xD5,
|
||||
0x5B,0x4B,0xD1,0x7E,0xF9,0x1A,0x41,0xF6,0x29,0xCC,0xA9,0x02,
|
||||
0x6B,0xED,0xFD,0xC9,0x37,0xCE,0xF6,0x11,0x78,0x6F,0x37,0x38,
|
||||
0x7D,0x49,0x3F,0x78,0x36,0x83,0x0A,0x6F,0xBA,0x6F,0x74,0xD9,
|
||||
0xB1,0xC1,0xC4,0x5A,0x7D,0x84,0x26,0x56,0x8B,0x53,0xF4,0xFE,
|
||||
0xD1,0x34,0xF1,0xE0,0x08,0x65,0xA6,0xFD,0xDB,0x5D,0xAC,0x14,
|
||||
0xCD,0xC9,0x7E,0x79,0xE9,0x3B,0xAF,0x92,0xC7,0x4D,0x91,0x15,
|
||||
0x0B,0x1E,0x2F,0x0A,0x56,0x4E,0x0D,0x3A,0x4D,0x9E,0xB0,0xB5,
|
||||
0xFC,0x0D,0xB1,0x55,0x40,0xC6,0x30,0x99,0xCD,0xE8,0x7E,0x72,
|
||||
0x08,0x93,0x9C,0x7F,0x55,0x23,0x27,0x09,0xF4,0x50,0xF2,0x96,
|
||||
0xB5,0x30,0x35,0x6A,0x99,0x4C,0xD6,0x85,0x72,0x8D,0x9C,0x19,
|
||||
0x70,0x9A,0x77,0x52,0xE8,0x33,0x03,0x7A,0x00,0xDA,0xFE,0xD7,
|
||||
0x98,0xD0,0x7B,0x26,0xBA,0xD7,0xFF,0xD1,0x49,0x61,0x27,0x3E,
|
||||
0xFC,0x12,0x81,0xC9,0xB0,0xAF,0x34,0x14,0x97,0x66,0xFB,0xEF,
|
||||
0xD3,0xFE,0xC9,0x01,0x25,0xEC,0xF4,0xE8,0xA8,0xD8,0x21,0x45,
|
||||
0x20,0x6F,0xFC,0xA8,0xB3,0xCE,0xCF,0x0D,0xA1,0x14,0xCC,0x38,
|
||||
0x81,0x74,0x6A,0x5E,0x36,0x09,0x1D,0xBE,0x4C,0x08,0x52,0x5E,
|
||||
0xC2,0x5F,0xA4,0x48,0x3A,0x71,0x85,0xF2,0x97,0x32,0xEC,0x3B,
|
||||
0xFB,0x1B,0x9A,0x8A,0x4B,0x20,0x32,0xFE,0x6A,0x94,0x4C,0x02,
|
||||
0xB2,0xD7,0xC3,0x1B,0xF8,0x90,0x54,0x76,0x70,0x49,0x81,0x86,
|
||||
0x30,0x12,0xD2,0x91,0xF0,0xFD,0x1B,0x53,0x2E,0x60,0x13,0x78,
|
||||
0x8B,0x3F,0x1B,0x13,
|
||||
};
|
||||
static unsigned char dh2048_g[]={
|
||||
0x05,
|
||||
};
|
||||
DH *dh;
|
||||
|
||||
if ((dh=DH_new()) == NULL) return(NULL);
|
||||
dh->p=BN_bin2bn(dh2048_p,sizeof(dh2048_p),NULL);
|
||||
dh->g=BN_bin2bn(dh2048_g,sizeof(dh2048_g),NULL);
|
||||
if ((dh->p == NULL) || (dh->g == NULL))
|
||||
{ DH_free(dh); return(NULL); }
|
||||
return(dh);
|
||||
}
|
||||
@@ -1,503 +0,0 @@
|
||||
/**
|
||||
* @file dofloaterhex.h
|
||||
* @brief Hex Editor Floater made by Day
|
||||
* @author Day Oh
|
||||
*
|
||||
* $LicenseInfo:firstyear=2009&license=WTFPLV2$
|
||||
*
|
||||
*/
|
||||
|
||||
// <edit>
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "dofloaterhex.h"
|
||||
#include "lluictrlfactory.h"
|
||||
#include "llinventorybackup.h" // for downloading
|
||||
#include "llviewercontrol.h" // gSavedSettings
|
||||
#include "llviewerwindow.h" // alertXML
|
||||
#include "llagent.h" // gAgent getID
|
||||
#include "llviewermenufile.h"
|
||||
#include "llviewerregion.h" // getCapability
|
||||
#include "llassetuploadresponders.h" // LLUpdateAgentInventoryResponder
|
||||
#include "llinventorymodel.h" // gInventory.updateItem
|
||||
#include "llappviewer.h" // System Folders
|
||||
#include "llfloaterperms.h" //get default perms
|
||||
#include "llnotificationsutil.h"
|
||||
|
||||
std::list<DOFloaterHex*> DOFloaterHex::sInstances;
|
||||
S32 DOFloaterHex::sUploadAmount = 10;
|
||||
|
||||
DOFloaterHex::DOFloaterHex(LLUUID item_id, BOOL vfs, LLAssetType::EType asset_type)
|
||||
: LLFloater()
|
||||
{
|
||||
sInstances.push_back(this);
|
||||
|
||||
mVFS = vfs;
|
||||
|
||||
//we are editing an asset directly from the VFS
|
||||
if(vfs)
|
||||
{
|
||||
mAssetId = item_id;
|
||||
mAssetType = asset_type;
|
||||
|
||||
//we are editing an inventory item
|
||||
} else {
|
||||
mItem = (LLInventoryItem*)gInventory.getItem(item_id);
|
||||
mAssetId = mItem->getAssetUUID();
|
||||
mAssetType = mItem->getType();
|
||||
}
|
||||
LLUICtrlFactory::getInstance()->buildFloater(this, "floater_hex.xml");
|
||||
}
|
||||
|
||||
//this bit should be rewritten entirely
|
||||
void DOFloaterHex::show(LLUUID item_id, BOOL vfs, LLAssetType::EType asset_type)
|
||||
{
|
||||
if(!vfs)
|
||||
{
|
||||
LLInventoryItem* item = (LLInventoryItem*)gInventory.getItem(item_id);
|
||||
if(item)
|
||||
{
|
||||
S32 left, top;
|
||||
gFloaterView->getNewFloaterPosition(&left, &top);
|
||||
LLRect rect = gSavedSettings.getRect("FloaterHexRect");
|
||||
rect.translate(left - rect.mLeft, top - rect.mTop);
|
||||
|
||||
DOFloaterHex* floaterp = new DOFloaterHex(item_id);
|
||||
floaterp->setRect(rect);
|
||||
|
||||
gFloaterView->adjustToFitScreen(floaterp, FALSE);
|
||||
}
|
||||
} else if (item_id.notNull() && asset_type != LLAssetType::AT_NONE) {
|
||||
S32 left, top;
|
||||
gFloaterView->getNewFloaterPosition(&left, &top);
|
||||
LLRect rect = gSavedSettings.getRect("FloaterHexRect");
|
||||
rect.translate(left - rect.mLeft, top - rect.mTop);
|
||||
DOFloaterHex* floaterp = new DOFloaterHex(item_id, true, asset_type);
|
||||
floaterp->setRect(rect);
|
||||
|
||||
llinfos << "Asset ID: " << item_id.asString() << llendl;
|
||||
|
||||
gFloaterView->adjustToFitScreen(floaterp, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
DOFloaterHex::~DOFloaterHex()
|
||||
{
|
||||
sInstances.remove(this);
|
||||
}
|
||||
|
||||
void DOFloaterHex::close(bool app_quitting)
|
||||
{
|
||||
LLFloater::close(app_quitting);
|
||||
}
|
||||
|
||||
BOOL DOFloaterHex::postBuild(void)
|
||||
{
|
||||
DOHexEditor* editor = getChild<DOHexEditor>("hex");
|
||||
mEditor = editor;
|
||||
#ifndef COLUMN_SPAN
|
||||
// Set number of columns
|
||||
U8 columns = U8(gSavedSettings.getU32("HexEditorColumns"));
|
||||
editor->setColumns(columns);
|
||||
// Reflect clamped U8ness in settings
|
||||
gSavedSettings.setU32("HexEditorColumns", U32(columns));
|
||||
#endif
|
||||
handleSizing();
|
||||
|
||||
childSetEnabled("upload_btn", false);
|
||||
childSetLabelArg("upload_btn", "[UPLOAD]", std::string("Upload"));
|
||||
childSetAction("upload_btn", onClickUpload, this);
|
||||
childSetEnabled("save_btn", false);
|
||||
childSetAction("save_btn", onClickSave, this);
|
||||
|
||||
if(!mVFS && mItem)
|
||||
{
|
||||
std::string title = "Hex editor: " + mItem->getName();
|
||||
const char* asset_type_name = LLAssetType::lookup(mItem->getType());
|
||||
if(asset_type_name)
|
||||
{
|
||||
title.append(" (" + std::string(asset_type_name) + ")");
|
||||
}
|
||||
setTitle(title);
|
||||
}
|
||||
if(!mVFS)
|
||||
{
|
||||
// Load the asset
|
||||
editor->setVisible(FALSE);
|
||||
childSetText("status_text", std::string("Loading..."));
|
||||
LLInventoryBackup::download(mItem, this, imageCallback, assetCallback);
|
||||
}
|
||||
else if (mVFS) //the asset already exists in the VFS, we don't need to fetch it
|
||||
//and we don't want to associate it with an item
|
||||
{
|
||||
setTitle(mAssetId.asString());
|
||||
readVFile();
|
||||
} else {
|
||||
this->close(false);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// static
|
||||
void DOFloaterHex::imageCallback(BOOL success,
|
||||
LLViewerFetchedTexture *src_vi,
|
||||
LLImageRaw* src,
|
||||
LLImageRaw* aux_src,
|
||||
S32 discard_level,
|
||||
BOOL final,
|
||||
void* userdata)
|
||||
{
|
||||
|
||||
if(final)
|
||||
{
|
||||
LLInventoryBackup::callbackdata* data = static_cast<LLInventoryBackup::callbackdata*>(userdata);
|
||||
DOFloaterHex* floater = (DOFloaterHex*)(data->floater);
|
||||
if(!floater) return;
|
||||
if(std::find(sInstances.begin(), sInstances.end(), floater) == sInstances.end()) return; // no more crash
|
||||
//LLInventoryItem* item = data->item;
|
||||
|
||||
if(!success)
|
||||
{
|
||||
floater->childSetText("status_text", std::string("Unable to download asset."));
|
||||
return;
|
||||
}
|
||||
|
||||
U8* src_data = src->getData();
|
||||
S32 size = src->getDataSize();
|
||||
std::vector<U8> new_data;
|
||||
for(S32 i = 0; i < size; i++)
|
||||
new_data.push_back(src_data[i]);
|
||||
|
||||
floater->mEditor->setValue(new_data);
|
||||
floater->mEditor->setVisible(TRUE);
|
||||
floater->childSetText("status_text", std::string("Note: Image data shown isn't the actual asset data, yet"));
|
||||
|
||||
floater->childSetEnabled("save_btn", false);
|
||||
floater->childSetEnabled("upload_btn", true);
|
||||
floater->childSetLabelArg("upload_btn", "[UPLOAD]", std::string("Upload (L$10)"));
|
||||
}
|
||||
else
|
||||
{
|
||||
src_vi->setBoostLevel(LLViewerTexture::BOOST_UI);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void DOFloaterHex::assetCallback(LLVFS *vfs,
|
||||
const LLUUID& asset_uuid,
|
||||
LLAssetType::EType type,
|
||||
void* user_data, S32 status, LLExtStat ext_status)
|
||||
{
|
||||
|
||||
LLInventoryBackup::callbackdata* data = static_cast<LLInventoryBackup::callbackdata*>(user_data);
|
||||
DOFloaterHex* floater = (DOFloaterHex*)(data->floater);
|
||||
if(!floater) return;
|
||||
if(std::find(sInstances.begin(), sInstances.end(), floater) == sInstances.end()) return; // no more crash
|
||||
LLInventoryItem* item = data->item;
|
||||
|
||||
if(status != 0 && item->getType() != LLAssetType::AT_NOTECARD)
|
||||
{
|
||||
floater->childSetText("status_text", std::string("Unable to download asset."));
|
||||
return;
|
||||
}
|
||||
|
||||
// Todo: this doesn't work for static vfs shit
|
||||
LLVFile file(vfs, asset_uuid, type, LLVFile::READ);
|
||||
S32 size = file.getSize();
|
||||
|
||||
char* buffer = new char[size];
|
||||
if (buffer == NULL)
|
||||
{
|
||||
llerrs << "Memory Allocation Failed" << llendl;
|
||||
return;
|
||||
}
|
||||
|
||||
file.read((U8*)buffer, size);
|
||||
|
||||
std::vector<U8> new_data;
|
||||
for(S32 i = 0; i < size; i++)
|
||||
new_data.push_back(buffer[i]);
|
||||
|
||||
delete[] buffer;
|
||||
|
||||
floater->mEditor->setValue(new_data);
|
||||
floater->mEditor->setVisible(TRUE);
|
||||
floater->childSetText("status_text", std::string(""));
|
||||
|
||||
floater->childSetEnabled("upload_btn", true);
|
||||
floater->childSetEnabled("save_btn", false);
|
||||
if(item->getPermissions().allowModifyBy(gAgent.getID()))
|
||||
{
|
||||
switch(item->getType())
|
||||
{
|
||||
case LLAssetType::AT_TEXTURE:
|
||||
case LLAssetType::AT_ANIMATION:
|
||||
case LLAssetType::AT_SOUND:
|
||||
floater->childSetLabelArg("upload_btn", "[UPLOAD]", std::string("Upload (L$10)"));
|
||||
break;
|
||||
case LLAssetType::AT_LANDMARK:
|
||||
case LLAssetType::AT_CALLINGCARD:
|
||||
floater->childSetEnabled("upload_btn", false);
|
||||
floater->childSetEnabled("save_btn", false);
|
||||
break;
|
||||
default:
|
||||
floater->childSetEnabled("save_btn", true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(item->getType())
|
||||
{
|
||||
case LLAssetType::AT_TEXTURE:
|
||||
case LLAssetType::AT_ANIMATION:
|
||||
case LLAssetType::AT_SOUND:
|
||||
floater->childSetLabelArg("upload_btn", "[UPLOAD]", std::string("Upload (L$10)"));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Never enable save if it's a pretend item
|
||||
if(gInventory.isObjectDescendentOf(item->getUUID(), gSystemFolderRoot))
|
||||
{
|
||||
floater->childSetEnabled("save_btn", false);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void DOFloaterHex::onClickUpload(void* user_data)
|
||||
{
|
||||
|
||||
DOFloaterHex* floater = (DOFloaterHex*)user_data;
|
||||
LLInventoryItem* item = floater->mItem;
|
||||
|
||||
LLTransactionID transaction_id;
|
||||
transaction_id.generate();
|
||||
LLUUID fake_asset_id = transaction_id.makeAssetID(gAgent.getSecureSessionID());
|
||||
|
||||
std::vector<U8> value = floater->mEditor->getValue();
|
||||
int size = value.size();
|
||||
U8* buffer = new U8[size];
|
||||
for(int i = 0; i < size; i++)
|
||||
buffer[i] = value[i];
|
||||
value.clear();
|
||||
|
||||
LLVFile file(gVFS, fake_asset_id, item->getType(), LLVFile::APPEND);
|
||||
file.setMaxSize(size);
|
||||
if (!file.write(buffer, size))
|
||||
{
|
||||
LLSD args;
|
||||
args["ERROR_MESSAGE"] = "Couldn't write data to file";
|
||||
LLNotificationsUtil::add("ErrorMessage", args);
|
||||
return;
|
||||
}
|
||||
delete[] buffer;
|
||||
|
||||
LLAssetStorage::LLStoreAssetCallback callback = NULL;
|
||||
void *fake_user_data = NULL;
|
||||
|
||||
if(item->getType() != LLAssetType::AT_GESTURE && item->getType() != LLAssetType::AT_LSL_TEXT
|
||||
&& item->getType() != LLAssetType::AT_NOTECARD)
|
||||
{
|
||||
upload_new_resource(transaction_id,
|
||||
item->getType(),
|
||||
item->getName(),
|
||||
item->getDescription(),
|
||||
0,
|
||||
LLFolderType::assetTypeToFolderType(item->getType()),
|
||||
item->getInventoryType(),
|
||||
LLFloaterPerms::getNextOwnerPerms(), LLFloaterPerms::getGroupPerms(), LLFloaterPerms::getEveryonePerms(),
|
||||
item->getName(),
|
||||
callback,
|
||||
sUploadAmount,
|
||||
fake_user_data);
|
||||
}
|
||||
else // gestures and scripts, create an item first
|
||||
{ // AND notecards
|
||||
//if(item->getType() == LLAssetType::AT_NOTECARD) gDontOpenNextNotecard = true;
|
||||
create_inventory_item( gAgent.getID(),
|
||||
gAgent.getSessionID(),
|
||||
item->getParentUUID(), //gInventory.findCategoryUUIDForType(item->getType()),
|
||||
LLTransactionID::tnull,
|
||||
item->getName(),
|
||||
fake_asset_id.asString(),
|
||||
item->getType(),
|
||||
item->getInventoryType(),
|
||||
(LLWearableType::EType)item->getFlags(),
|
||||
PERM_ITEM_UNRESTRICTED,
|
||||
new NewResourceItemCallback);
|
||||
}
|
||||
}
|
||||
|
||||
struct LLSaveInfo
|
||||
{
|
||||
LLSaveInfo(DOFloaterHex* floater, LLTransactionID transaction_id)
|
||||
: mFloater(floater), mTransactionID(transaction_id)
|
||||
{
|
||||
}
|
||||
|
||||
DOFloaterHex* mFloater;
|
||||
LLTransactionID mTransactionID;
|
||||
};
|
||||
|
||||
// static
|
||||
void DOFloaterHex::onClickSave(void* user_data)
|
||||
{
|
||||
DOFloaterHex* floater = (DOFloaterHex*)user_data;
|
||||
LLInventoryItem* item = floater->mItem;
|
||||
|
||||
LLTransactionID transaction_id;
|
||||
transaction_id.generate();
|
||||
LLUUID fake_asset_id = transaction_id.makeAssetID(gAgent.getSecureSessionID());
|
||||
|
||||
std::vector<U8> value = floater->mEditor->getValue();
|
||||
int size = value.size();
|
||||
U8* buffer = new U8[size];
|
||||
for(int i = 0; i < size; i++)
|
||||
buffer[i] = value[i];
|
||||
value.clear();
|
||||
|
||||
LLVFile file(gVFS, fake_asset_id, item->getType(), LLVFile::APPEND);
|
||||
file.setMaxSize(size);
|
||||
if (!file.write(buffer, size))
|
||||
{
|
||||
LLSD args;
|
||||
args["ERROR_MESSAGE"] = "Couldn't write data to file";
|
||||
LLNotificationsUtil::add("ErrorMessage", args);
|
||||
return;
|
||||
}
|
||||
delete[] buffer;
|
||||
|
||||
|
||||
bool caps = false;
|
||||
std::string url;
|
||||
LLSD body;
|
||||
body["item_id"] = item->getUUID();
|
||||
|
||||
switch(item->getType())
|
||||
{
|
||||
case LLAssetType::AT_GESTURE:
|
||||
url = gAgent.getRegion()->getCapability("UpdateGestureAgentInventory");
|
||||
caps = true;
|
||||
break;
|
||||
case LLAssetType::AT_LSL_TEXT:
|
||||
url = gAgent.getRegion()->getCapability("UpdateScriptAgent");
|
||||
body["target"] = "mono";
|
||||
caps = true;
|
||||
break;
|
||||
case LLAssetType::AT_NOTECARD:
|
||||
url = gAgent.getRegion()->getCapability("UpdateNotecardAgentInventory");
|
||||
caps = true;
|
||||
break;
|
||||
default: // wearables & notecards, Oct 12 2009
|
||||
// ONLY WEARABLES, Oct 15 2009
|
||||
floater->childSetText("status_text", std::string("Saving..."));
|
||||
LLSaveInfo* info = new LLSaveInfo(floater, transaction_id);
|
||||
gAssetStorage->storeAssetData(transaction_id, item->getType(), onSaveComplete, info);
|
||||
caps = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if(caps)
|
||||
{
|
||||
LLHTTPClient::post(url, body,
|
||||
new LLUpdateAgentInventoryResponder(body, fake_asset_id, item->getType()));
|
||||
}
|
||||
}
|
||||
|
||||
void DOFloaterHex::onSaveComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status)
|
||||
{
|
||||
LLSaveInfo* info = (LLSaveInfo*)user_data;
|
||||
DOFloaterHex* floater = info->mFloater;
|
||||
if(std::find(sInstances.begin(), sInstances.end(), floater) == sInstances.end()) return; // no more crash
|
||||
LLInventoryItem* item = floater->mItem;
|
||||
|
||||
floater->childSetText("status_text", std::string(""));
|
||||
|
||||
if(item && (status == 0))
|
||||
{
|
||||
LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
|
||||
new_item->setDescription(item->getDescription());
|
||||
new_item->setTransactionID(info->mTransactionID);
|
||||
new_item->setAssetUUID(asset_uuid);
|
||||
new_item->updateServer(FALSE);
|
||||
gInventory.updateItem(new_item);
|
||||
gInventory.notifyObservers();
|
||||
}
|
||||
else
|
||||
{
|
||||
LLSD args;
|
||||
args["ERROR_MESSAGE"] = llformat("Upload failed with status %d, also %d", status, ext_status);
|
||||
LLNotificationsUtil::add("ErrorMessage", args);
|
||||
}
|
||||
}
|
||||
|
||||
void DOFloaterHex::onCommitColumnCount(LLUICtrl *control, void *user_data)
|
||||
{
|
||||
if(control && user_data)
|
||||
{
|
||||
DOFloaterHex *instance = (DOFloaterHex *)user_data;
|
||||
U8 columns = llclamp<U8>((U8)llfloor(control->getValue().asReal()), 0x00, 0xFF);
|
||||
instance->mEditor->setColumns(columns);
|
||||
gSavedSettings.setU32("HexEditorColumns", (U32)instance->mEditor->getColumns());
|
||||
instance->handleSizing();
|
||||
}
|
||||
}
|
||||
|
||||
void DOFloaterHex::handleSizing()
|
||||
{
|
||||
// Reshape a little based on columns
|
||||
S32 min_width = S32(mEditor->getSuggestedWidth(MIN_COLS)) + 20;
|
||||
setResizeLimits(min_width, getMinHeight());
|
||||
if(getRect().getWidth() < min_width)
|
||||
{
|
||||
//LLRect rect = getRect();
|
||||
//rect.setOriginAndSize(rect.mLeft, rect.mBottom, min_width, rect.getHeight());
|
||||
//setRect(rect);
|
||||
|
||||
reshape(min_width, getRect().getHeight(), FALSE);
|
||||
mEditor->reshape(mEditor->getRect().getWidth(), mEditor->getRect().getHeight(), TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
void DOFloaterHex::readVFile()
|
||||
{
|
||||
if(!mVFS) return;
|
||||
// quick cut paste job
|
||||
// Todo: this doesn't work for static vfs shit
|
||||
LLVFile file(gVFS, mAssetId, mAssetType, LLVFile::READ);
|
||||
if(file.getVFSThread())
|
||||
{
|
||||
S32 size = file.getSize();
|
||||
|
||||
char* buffer = new char[size];
|
||||
if (buffer == NULL)
|
||||
{
|
||||
llerrs << "Memory Allocation Failed" << llendl;
|
||||
return;
|
||||
}
|
||||
|
||||
file.read((U8*)buffer, size);
|
||||
|
||||
std::vector<U8> new_data;
|
||||
for(S32 i = 0; i < size; i++)
|
||||
new_data.push_back(buffer[i]);
|
||||
|
||||
delete[] buffer;
|
||||
|
||||
mEditor->setValue(new_data);
|
||||
mEditor->setVisible(TRUE);
|
||||
|
||||
}
|
||||
|
||||
childSetText("status_text", std::string("Editing VFile"));
|
||||
|
||||
childSetEnabled("upload_btn", false);
|
||||
childSetEnabled("save_btn", false);
|
||||
}
|
||||
|
||||
// </edit>
|
||||
@@ -1,51 +0,0 @@
|
||||
// <edit>
|
||||
|
||||
|
||||
#ifndef LL_LLFLOATERHEX_H
|
||||
#define LL_LLFLOATERHEX_H
|
||||
|
||||
#include "llfloater.h"
|
||||
#include "dohexeditor.h"
|
||||
#include "llinventory.h"
|
||||
#include "llviewertexture.h"
|
||||
#include "llassettype.h"
|
||||
|
||||
class DOFloaterHex
|
||||
: public LLFloater
|
||||
{
|
||||
public:
|
||||
DOFloaterHex(LLUUID item_id, BOOL vfs=false, LLAssetType::EType asset_type = LLAssetType::AT_NONE);
|
||||
static void show(LLUUID item_id, BOOL vfs=false, LLAssetType::EType asset_type = LLAssetType::AT_NONE);
|
||||
BOOL postBuild(void);
|
||||
void close(bool app_quitting);
|
||||
static void imageCallback(BOOL success,
|
||||
LLViewerFetchedTexture *src_vi,
|
||||
LLImageRaw* src,
|
||||
LLImageRaw* aux_src,
|
||||
S32 discard_level,
|
||||
BOOL final,
|
||||
void* userdata);
|
||||
static void assetCallback(LLVFS *vfs,
|
||||
const LLUUID& asset_uuid,
|
||||
LLAssetType::EType type,
|
||||
void* user_data, S32 status, LLExtStat ext_status);
|
||||
static void onClickSave(void* user_data);
|
||||
static void onClickUpload(void* user_data);
|
||||
static void onSaveComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status);
|
||||
static void onCommitColumnCount(LLUICtrl *control, void *user_data);
|
||||
void handleSizing();
|
||||
void readVFile();
|
||||
LLInventoryItem* mItem;
|
||||
LLUUID mAssetId;
|
||||
LLAssetType::EType mAssetType;
|
||||
BOOL mVFS;
|
||||
DOHexEditor* mEditor;
|
||||
static std::list<DOFloaterHex*> sInstances;
|
||||
private:
|
||||
virtual ~DOFloaterHex();
|
||||
protected:
|
||||
static S32 sUploadAmount;
|
||||
};
|
||||
|
||||
#endif
|
||||
// </edit>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user