Compare commits

..

29 Commits

Author SHA1 Message Date
Siana Gearz
68ad5411c9 Shyotl's old llcurl 2012-08-07 13:13:45 +02:00
Siana Gearz
6ed9a62501 Disable texture auditing at start-up 2012-07-28 16:56:19 +02:00
Siana Gearz
89be317a00 Fix measurement tool 2012-07-23 14:18:45 +02:00
Siana Gearz
1ad4597d7a Fix alpha flicker when Show Updates is enabled 2012-07-23 12:00:33 +02:00
Siana Gearz
c65b659538 Dirty potential mesh crash fix 2012-07-23 10:50:05 +02:00
Siana Gearz
3c23163a29 Less intrusive notifications, by Tazy Scientist 2012-07-23 09:54:00 +02:00
Siana Gearz
c3900ee4f3 Merge branch 'AltCompilers' of git://github.com/LightDrake/SingularityViewer
Conflicts:
	indra/newview/llvieweraudio.cpp
2012-07-23 09:03:17 +02:00
Siana Gearz
9c5da9e42c Build fixes VC10 2012-07-23 08:13:13 +02:00
Drake Arconis
efa970c6a5 Uhm..
This fixes a build issue temp till can rebuild QT...*sigh*
2012-07-22 23:41:09 -04:00
Siana Gearz
179f04739d Merge commit 'c7bdaf66329b018159c834d75fcc3d807b188ccb' 2012-07-23 05:10:56 +02:00
Siana Gearz
b2f513caae Safer settings, EOL fix 2012-07-23 04:02:20 +02:00
Siana Gearz
9c1e74b0c0 Merge branch 'master' of git://github.com/Shyotl/SingularityViewer
Conflicts:
	indra/llaudio/llstreamingaudio_fmodex.cpp
	indra/newview/skins/default/xui/en-us/panel_preferences_graphics1.xml
2012-07-23 03:04:33 +02:00
Siana Gearz
e53af58d4a Merge branch 'master' of git://github.com/AlericInglewood/SingularityViewer 2012-07-22 23:31:19 +02:00
Siana Gearz
d9cb2ce6c7 Looks like a bit of edit crash fix got missed, thx Drake 2012-07-22 23:30:41 +02:00
Siana Gearz
a967f2b037 Updated 'Show Updates' 2012-07-22 22:36:40 +02:00
Siana Gearz
db5a7578c9 Crash fix copy texture params 2012-07-22 21:44:41 +02:00
Siana Gearz
15086833a3 Random stab in the dark coming right up! 2012-07-22 11:26:36 +02:00
Drake Arconis
72a9b6b7fe Corrected issues
Corrected issue noted in media_plugin_webkit by Aleric.
Grr.
2012-07-21 03:23:02 -04:00
Drake Arconis
0d3fab40e5 Further header cleanup and a few updates
Updated llstring to current linden
Further linden_common cleanup
Header cleanup
Raised banlines to 5000 as per linden server change
Included missing llmediaentry.cpp file
Minor whitespace changes here and there
2012-07-21 03:01:42 -04:00
Shyotl
4e4d554ea4 Silence the diagnostic llinfos spam when listening to a stream. 2012-07-20 12:11:30 -05:00
Lirusaito
c7bdaf6632 Merge branch 'AltCompilers' of https://github.com/LightDrake/SingularityViewer 2012-07-20 10:50:40 -04:00
Lirusaito
92c7792e95 Merge branch 'master' of git://github.com/Shyotl/SingularityViewer
Conflicts:
	indra/newview/skins/default/xui/en-us/panel_preferences_graphics1.xml - Resolved to the eye's pleasure.
2012-07-20 10:41:25 -04:00
Drake Arconis
1e81966b89 Clean up and updates
Cleaned up header bloatyness in linden_common
Moved around things to be in line with Linden Lab
Updated llinitparam and imported its new dependencies
Removed dohexeditor and related files
Removed unused legacy files

             /\_..._/\
             |/ \_/ \|
             | o.-.o |
             \ ( O ) /
             /'--U--'\
             |  .:.  | /\
             | /:;:\ |` /
   Drake     | |:;:| |-'
  Arconis   /  |'-'|  \
            `""`   `""`
2012-07-20 08:13:07 -04:00
Shyotl
b785b9d219 Added 'Transparent Water' checkbox to graphics panel, as we actually have space for it now. 2012-07-20 05:15:47 -05:00
Shyotl
85da7163a7 Changing the rolloff settings now immediately apply (with fmodex). Also added AudioLevelUnderwaterRolloff now that the underwater rolloff 3d setting doesnt immediately get clobbered. Also, divvied up sound channels into channelgroups if using the fmod profiler, so it actually has useful info to show now. 2012-07-20 04:00:02 -05:00
Lirusaito
f3f8bee83b Remove old spam stuffs, Clean up new spam stuffs to compile, UI new spam stuffs. 2012-07-19 23:40:07 -04:00
Drake Arconis
7843f51110 Merge remote-tracking branch 'singu/master' into AltCompilers 2012-07-19 17:51:18 -04:00
Drake Arconis
8bfdc98ef4 Improvements!
Fixed Boost library to not throw warnings
Changed PNG cmake slightly
Updated 32lib package for correct locations
Cleaned up flags a bit for linux64
2012-07-19 17:44:19 -04:00
Ruby
6673c89791 Add Antispam code from NaCl (Chalice Yao)
Amended by: Lirusaito <inusaito@gmail.com>
2012-07-19 16:36:39 -04:00
165 changed files with 7935 additions and 8880 deletions

View File

@@ -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)

View File

@@ -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)

View File

@@ -1,7 +1,7 @@
# -*- cmake -*-
include(Prebuilt)
set(CURL_FIND_QUIETLY OFF)
set(CURL_FIND_QUIETLY ON)
set(CURL_FIND_REQUIRED ON)
if (STANDALONE)

View File

@@ -1,7 +0,0 @@
# -*- cmake -*-
set(LLXUIXML_INCLUDE_DIRS
${LIBS_OPEN_DIR}/llxuixml
)
set(LLXUIXML_LIBRARIES llxuixml)

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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()]);
}

View File

@@ -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];
};

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -38,7 +38,6 @@
#include "llcharacter.h"
#include "llstring.h"
#include "llfasttimer.h"
#define SKEL_HEADER "Linden Skeleton 1.0"

View File

@@ -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) );

View File

@@ -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)

View File

@@ -93,6 +93,7 @@ class LLVisualParam
{
public:
typedef boost::function<LLVisualParam*(S32)> visual_param_mapper;
LLVisualParam();
virtual ~LLVisualParam();

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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)

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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)
{

View 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) */

View File

@@ -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

View File

@@ -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 )
{

View File

@@ -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);

View File

@@ -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;

View File

@@ -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

View 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) */

View File

@@ -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;

View File

@@ -34,7 +34,6 @@
#include <iostream>
#include <set>
#include <vector>
#include "stdtypes.h"
#include "llpreprocessor.h"

View File

@@ -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");

View File

@@ -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

View File

@@ -32,7 +32,7 @@
#ifndef LL_LLPNGWRAPPER_H
#define LL_LLPNGWRAPPER_H
#include "png.h"
#include "libpng15/png.h"
#include "llimage.h"
class LLPngWrapper

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;
};

View File

@@ -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.

View File

@@ -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;

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)
{

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -29,7 +29,6 @@
#include "lldispatcher.h"
#include <algorithm>
#include <iterator>
#include "llstl.h"
#include "message.h"

View File

@@ -80,7 +80,6 @@
#include "llbuffer.h"
#include "llbufferstream.h"
#include "llfasttimer.h"
#include "llmemorystream.h"
#include "llsd.h"
#include "llsdserialize.h"

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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"

View File

@@ -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 ;
}

View File

@@ -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:
/**

View File

@@ -32,7 +32,6 @@
#include "llapr.h"
#include "llbuffer.h"
#include "llfasttimer.h"
#include "llhost.h"
#include "llmemtype.h"
#include "llpumpio.h"

View File

@@ -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"

View File

@@ -27,8 +27,8 @@
*/
#include "linden_common.h"
#include "llfasttimer.h"
#include "llioutil.h"
#include "llfasttimer.h"
/**
* LLIOFlush

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -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.

View File

@@ -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.
*

View File

@@ -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

View File

@@ -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);

View File

@@ -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.

View File

@@ -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 ----------------*/

View File

@@ -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:

View 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;
}

View 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

View 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
}

View 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

View File

@@ -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
*/

View File

@@ -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

View File

@@ -29,6 +29,7 @@
#include "message.h"
#include "lltimer.h"
#include "llextendedstatus.h"
const S32 LL_XFER_LARGE_PAYLOAD = 7680;

View File

@@ -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;

View File

@@ -17,6 +17,7 @@ include_directories(
set(llprimitive_SOURCE_FILES
llmaterialtable.cpp
llmediaentry.cpp
llmodel.cpp
llprimitive.cpp
llprimtexturelist.cpp

View File

@@ -137,6 +137,7 @@ void LLMaterialTable::initTableTransNames(std::map<std::string, std::string> nam
infop->mName = namemap[name];
}
}
void LLMaterialTable::initBasicTable()
{
// *TODO: Translate

View 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;
}

View File

@@ -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;

View File

@@ -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

View File

@@ -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
)

View File

@@ -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}

View 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;
}

View 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

View File

@@ -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>

View File

@@ -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>

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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>

View File

@@ -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