Apertura del repositorio

This commit is contained in:
2025-05-24 18:09:39 -03:00
parent 76e6359dad
commit d883ddd0d0
35253 changed files with 2891973 additions and 2 deletions
+226
View File
@@ -0,0 +1,226 @@
# -*- cmake -*-
project(llmessage)
include(00-Common)
include(LLAddBuildTest)
include(LLCommon)
include(LLCoreHttp)
include(LLAddBuildTest)
include(Python)
include(Tut)
include(Python)
set(llmessage_SOURCE_FILES
fscorehttputil.cpp
llassetstorage.cpp
llavatarname.cpp
llavatarnamecache.cpp
llblowfishcipher.cpp
llbuffer.cpp
llbufferstream.cpp
llcachename.cpp
llchainio.cpp
llcircuit.cpp
llclassifiedflags.cpp
llcoproceduremanager.cpp
llcorehttputil.cpp
lldatapacker.cpp
lldispatcher.cpp
llexperiencecache.cpp
llgenericstreamingmessage.cpp
llhost.cpp
llhttpnode.cpp
llhttpsdhandler.cpp
llinstantmessage.cpp
lliobuffer.cpp
lliohttpserver.cpp
lliopipe.cpp
lliosocket.cpp
llioutil.cpp
llmail.cpp
llmessagebuilder.cpp
llmessageconfig.cpp
llmessagereader.cpp
llmessagetemplate.cpp
llmessagetemplateparser.cpp
llmessagethrottle.cpp
llnamevalue.cpp
llnullcipher.cpp
llpacketack.cpp
llpacketbuffer.cpp
llpacketring.cpp
llpartdata.cpp
llproxy.cpp
llpumpio.cpp
llsdappservices.cpp
llsdhttpserver.cpp
llsdmessagebuilder.cpp
llsdmessagereader.cpp
llservicebuilder.cpp
llservice.cpp
llstoredmessage.cpp
lltemplatemessagebuilder.cpp
lltemplatemessagedispatcher.cpp
lltemplatemessagereader.cpp
llthrottle.cpp
lltransfermanager.cpp
lltransfersourceasset.cpp
lltransfersourcefile.cpp
lltransfertargetfile.cpp
lltransfertargetvfile.cpp
lltrustedmessageservice.cpp
lluseroperation.cpp
llxfer.cpp
llxfer_file.cpp
llxfermanager.cpp
llxfer_mem.cpp
llxfer_vfile.cpp
llxorcipher.cpp
machine.cpp
message.cpp
message_prehash.cpp
message_string_table.cpp
net.cpp
partsyspacket.cpp
patch_code.cpp
patch_dct.cpp
patch_idct.cpp
sound_ids.cpp
)
set(llmessage_HEADER_FILES
CMakeLists.txt
fscorehttputil.h
llassetstorage.h
llavatarname.h
llavatarnamecache.h
llblowfishcipher.h
llbuffer.h
llbufferstream.h
llcachename.h
llchainio.h
llcipher.h
llcircuit.h
llclassifiedflags.h
llcoproceduremanager.h
llcorehttputil.h
lldatapacker.h
lldbstrings.h
lldispatcher.h
lleventflags.h
llexperiencecache.h
llextendedstatus.h
llfollowcamparams.h
llgenericstreamingmessage.h
llhost.h
llhttpnode.h
llhttpnodeadapter.h
llhttpsdhandler.h
llinstantmessage.h
llinvite.h
lliobuffer.h
lliohttpserver.h
lliopipe.h
lliosocket.h
llioutil.h
llloginflags.h
llmail.h
llmessagebuilder.h
llmessageconfig.h
llmessagereader.h
llmessagetemplate.h
llmessagetemplateparser.h
llmessagethrottle.h
llmsgvariabletype.h
llnamevalue.h
llnullcipher.h
llpacketack.h
llpacketbuffer.h
llpacketring.h
llpartdata.h
llpumpio.h
llproxy.h
llqueryflags.h
llregionflags.h
llregionhandle.h
llsdappservices.h
llsdhttpserver.h
llsdmessagebuilder.h
llsdmessagereader.h
llservice.h
llservicebuilder.h
llstoredmessage.h
lltaskname.h
llteleportflags.h
lltemplatemessagebuilder.h
lltemplatemessagedispatcher.h
lltemplatemessagereader.h
llthrottle.h
lltransfermanager.h
lltransfersourceasset.h
lltransfersourcefile.h
lltransfertargetfile.h
lltransfertargetvfile.h
lltrustedmessageservice.h
lluseroperation.h
llvehicleparams.h
llxfer.h
llxfermanager.h
llxfer_file.h
llxfer_mem.h
llxfer_vfile.h
llxorcipher.h
machine.h
mean_collision_data.h
message.h
message_prehash.h
net.h
partsyspacket.h
patch_code.h
patch_dct.h
sound_ids.h
)
list(APPEND llmessage_SOURCE_FILES ${llmessage_HEADER_FILES})
add_library (llmessage ${llmessage_SOURCE_FILES})
target_link_libraries(
llmessage
llcommon
llfilesystem
llmath
llcorehttp
llxml #<FS:Ansariel> For accessing settings
)
target_include_directories( llmessage INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
# tests
if (LL_TESTS)
SET(llmessage_TEST_SOURCE_FILES
llcoproceduremanager.cpp
llnamevalue.cpp
lltrustedmessageservice.cpp
lltemplatemessagedispatcher.cpp
)
set_property( SOURCE ${llmessage_TEST_SOURCE_FILES} PROPERTY LL_TEST_ADDITIONAL_LIBRARIES llmath llcorehttp)
LL_ADD_PROJECT_UNIT_TESTS(llmessage "${llmessage_TEST_SOURCE_FILES}")
# set(TEST_DEBUG on)
set(test_libs
llfilesystem
llmath
llcorehttp
llmessage
llcommon
)
#LL_ADD_INTEGRATION_TEST(llavatarnamecache "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(llhost "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(llpartdata "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(llxfer_file "" "${test_libs}")
endif (LL_TESTS)
+153
View File
@@ -0,0 +1,153 @@
/**
* @file fscorehttputil.h
* @brief Core HTTP utility classes.
*
* $LicenseInfo:firstyear=2015&license=viewerlgpl$
* Phoenix Firestorm Viewer Source Code
* Copyright (c) 2015 Nicky Dasmijn
*
* 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
*
* The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA
* http://www.firestormviewer.org
* $/LicenseInfo$
*/
#include "fscorehttputil.h"
namespace FSCoreHttpUtil
{
void trivialPostCoroRaw(std::string url, LLCore::HttpRequest::policy_t policyId, LLCore::BufferArray::ptr_t postData, LLCore::HttpHeaders::ptr_t aHeader, LLCore::HttpOptions::ptr_t options, completionCallback_t success, completionCallback_t failure)
{
LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("genericPostCoroRaw", policyId));
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
if (!options)
{
options.reset(new LLCore::HttpOptions);
options->setWantHeaders(true);
}
LL_INFOS("HttpCoroutineAdapter", "genericPostCoroRaw") << "Generic POST for " << url << LL_ENDL;
LLSD result = httpAdapter->postRawAndSuspend(httpRequest, url, postData, options, aHeader );
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
if (!status)
{
// If a failure routine is provided do it.
if (failure)
{
failure(httpResults);
}
}
else
{
// If a success routine is provided do it.
if (success)
{
success(result);
}
}
}
void callbackHttpPostRaw(const std::string &url, std::string postData, completionCallback_t success, completionCallback_t failure, LLCore::HttpHeaders::ptr_t aHeader, LLCore::HttpOptions::ptr_t options)
{
LLCore::BufferArray::ptr_t postDataBuffer( new LLCore::BufferArray() );
postDataBuffer->append( postData.c_str(), postData.size() );
LLCoros::instance().launch("HttpCoroutineAdapter::genericPostCoroRaw",
boost::bind(trivialPostCoroRaw, url, LLCore::HttpRequest::DEFAULT_POLICY_ID, postDataBuffer, aHeader, options, success, failure));
}
void trivialGetCoroRaw(std::string url, LLCore::HttpRequest::policy_t policyId, LLCore::HttpHeaders::ptr_t aHeader, LLCore::HttpOptions::ptr_t options, completionCallback_t success, completionCallback_t failure)
{
LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("genericGetCoro", policyId));
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
if (!options)
{
options.reset(new LLCore::HttpOptions);
options->setWantHeaders(true);
}
LL_INFOS("HttpCoroutineAdapter", "genericGetCoroRaw") << "Generic GET for " << url << LL_ENDL;
LLSD result = httpAdapter->getRawAndSuspend(httpRequest, url, options, aHeader);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
if (!status)
{
if (failure)
{
failure(httpResults);
}
}
else
{
if (success)
{
success(result);
}
}
}
void callbackHttpGetRaw(const std::string &url, completionCallback_t success, completionCallback_t failure, LLCore::HttpHeaders::ptr_t aHeader, LLCore::HttpOptions::ptr_t options)
{
LLCoros::instance().launch("HttpCoroutineAdapter::genericGetCoroRaw",
boost::bind(trivialGetCoroRaw, url, LLCore::HttpRequest::DEFAULT_POLICY_ID, aHeader, options, success, failure));
}
void trivialGetCoro(std::string url, time_t last_modified, completionCallback_t success, completionCallback_t failure)
{
LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("trivialGetCoro", LLCore::HttpRequest::DEFAULT_POLICY_ID));
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
httpOpts->setWantHeaders(true);
httpOpts->setLastModified((long)last_modified);
LLSD result = httpAdapter->getAndSuspend(httpRequest, url, httpOpts);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
if (!status)
{
if (failure)
{
failure(httpResults);
}
}
else
{
if (success)
{
success(result);
}
}
}
void callbackHttpGet(const std::string &url, const time_t& last_modified, completionCallback_t success, completionCallback_t failure)
{
LLCoros::instance().launch("HttpCoroutineAdapter::genericGetCoro", boost::bind(&trivialGetCoro, url, last_modified, success, failure));
}
}
+49
View File
@@ -0,0 +1,49 @@
/**
* @file fscorehttputil.h
* @brief Core HTTP utility classes.
*
* $LicenseInfo:firstyear=2015&license=viewerlgpl$
* Phoenix Firestorm Viewer Source Code
* Copyright (c) 2015 Nicky Dasmijn
*
* 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
*
* The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA
* http://www.firestormviewer.org
* $/LicenseInfo$
*/
#ifndef FS_COREHTTPUTIL_H
#define FS_COREHTTPUTIL_H
#include "llcorehttputil.h"
namespace FSCoreHttpUtil
{
typedef boost::function<void(const LLSD &)> completionCallback_t;
void callbackHttpPostRaw(const std::string &url, std::string postData, completionCallback_t success = NULL, completionCallback_t failure = NULL,
LLCore::HttpHeaders::ptr_t aHeader = LLCore::HttpHeaders::ptr_t(), LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t());
void callbackHttpGetRaw(const std::string &url, completionCallback_t success = NULL, completionCallback_t failure = NULL,
LLCore::HttpHeaders::ptr_t aHeader = LLCore::HttpHeaders::ptr_t(), LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t());
void callbackHttpGet(const std::string &url, const time_t& last_modified, completionCallback_t success, completionCallback_t failure);
void trivialGetCoroRaw(std::string url, LLCore::HttpRequest::policy_t policyId, LLCore::HttpHeaders::ptr_t aHeader, LLCore::HttpOptions::ptr_t options, completionCallback_t success, completionCallback_t failure);
void trivialPostCoroRaw(std::string url, LLCore::HttpRequest::policy_t policyId, LLCore::BufferArray::ptr_t postData, LLCore::HttpHeaders::ptr_t aHeader, LLCore::HttpOptions::ptr_t options,
completionCallback_t success, completionCallback_t failure);
void trivialGetCoro(std::string url, time_t last_modified, completionCallback_t success, completionCallback_t failure);
}
#endif // FS_COREHTTPUTIL_H
File diff suppressed because it is too large Load Diff
+432
View File
@@ -0,0 +1,432 @@
/**
* @file llassetstorage.h
* @brief definition of LLAssetStorage class which allows simple
* up/downloads of uuid,type asets
*
* $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$
*/
#ifndef LL_LLASSETSTORAGE_H
#define LL_LLASSETSTORAGE_H
#include <string>
#include <functional>
#include "lluuid.h"
#include "lltimer.h"
#include "llnamevalue.h"
#include "llhost.h"
#include "lltransfermanager.h" // For LLTSCode enum
#include "llassettype.h"
#include "llstring.h"
#include "llextendedstatus.h"
#include "llxfer.h"
// Forward declarations
class LLMessageSystem;
class LLXferManager;
class LLAssetStorage;
class LLSD;
// anything that takes longer than this to download will abort.
// HTTP Uploads also timeout if they take longer than this.
const F32Minutes LL_ASSET_STORAGE_TIMEOUT(5);
// Specific error codes
const int LL_ERR_ASSET_REQUEST_FAILED = -1;
//const int LL_ERR_ASSET_REQUEST_INVALID = -2;
const int LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE = -3;
const int LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE = -4;
const int LL_ERR_INSUFFICIENT_PERMISSIONS = -5;
const int LL_ERR_PRICE_MISMATCH = -23018;
// *TODO: these typedefs are passed into the cache via a legacy C function pointer
// future project would be to convert these to C++ callables (std::function<>) so that
// we can use bind and remove the userData parameter.
//
typedef std::function<void(const LLUUID &asset_id, LLAssetType::EType asset_type, void *user_data, S32 status, LLExtStat ext_status)> LLGetAssetCallback;
typedef std::function<void(const LLUUID &asset_id, void *user_data, S32 status, LLExtStat ext_status)> LLStoreAssetCallback;
class LLAssetInfo
{
protected:
std::string mDescription;
std::string mName;
public:
LLUUID mUuid;
LLTransactionID mTransactionID;
LLUUID mCreatorID;
LLAssetType::EType mType;
LLAssetInfo( void );
LLAssetInfo( const LLUUID& object_id, const LLUUID& creator_id,
LLAssetType::EType type, const char* name, const char* desc );
LLAssetInfo( const LLNameValue& nv );
const std::string& getName( void ) const { return mName; }
const std::string& getDescription( void ) const { return mDescription; }
void setName( const std::string& name );
void setDescription( const std::string& desc );
// Assets (aka potential inventory items) can be applied to an
// object in the world. We'll store that as a string name value
// pair where the name encodes part of asset info, and the value
// the rest. LLAssetInfo objects will be responsible for parsing
// the meaning out froman LLNameValue object. See the inventory
// design docs for details.
void setFromNameValue( const LLNameValue& nv );
};
class LLBaseDownloadRequest
{
public:
LLBaseDownloadRequest(const LLUUID &uuid, const LLAssetType::EType at);
virtual ~LLBaseDownloadRequest();
LLUUID getUUID() const { return mUUID; }
LLAssetType::EType getType() const { return mType; }
void setUUID(const LLUUID& id) { mUUID = id; }
void setType(LLAssetType::EType type) { mType = type; }
virtual LLBaseDownloadRequest* getCopy();
protected:
LLUUID mUUID;
LLAssetType::EType mType;
public:
LLGetAssetCallback mDownCallback;
void *mUserData;
LLHost mHost;
bool mIsTemp;
F64Seconds mTime; // Message system time
bool mIsPriority;
bool mDataSentInFirstPacket;
bool mDataIsInCache;
};
class LLAssetRequest : public LLBaseDownloadRequest
{
public:
LLAssetRequest(const LLUUID &uuid, const LLAssetType::EType at);
virtual ~LLAssetRequest();
void setTimeout(F64Seconds timeout) { mTimeout = timeout; }
virtual LLBaseDownloadRequest* getCopy();
LLStoreAssetCallback mUpCallback;
// void (*mUpCallback)(const LLUUID&, void *, S32, LLExtStat);
void (*mInfoCallback)(LLAssetInfo *, void *, S32);
bool mIsLocal;
bool mIsUserWaiting; // We don't want to try forever if a user is waiting for a result.
F64Seconds mTimeout; // Amount of time before timing out.
LLUUID mRequestingAgentID; // Only valid for uploads from an agent
F64 mBytesFetched;
virtual LLSD getTerseDetails() const;
virtual LLSD getFullDetails() const;
};
template <class T>
struct ll_asset_request_equal : public std::equal_to<T>
{
bool operator()(const T& x, const T& y) const
{
return ( x->getType() == y->getType()
&& x->getUUID() == y->getUUID() );
}
};
class LLInvItemRequest : public LLBaseDownloadRequest
{
public:
LLInvItemRequest(const LLUUID &uuid, const LLAssetType::EType at);
virtual ~LLInvItemRequest();
virtual LLBaseDownloadRequest* getCopy();
};
class LLEstateAssetRequest : public LLBaseDownloadRequest
{
public:
LLEstateAssetRequest(const LLUUID &uuid, const LLAssetType::EType at, EstateAssetType et);
virtual ~LLEstateAssetRequest();
LLAssetType::EType getAType() const { return mType; }
virtual LLBaseDownloadRequest* getCopy();
protected:
EstateAssetType mEstateAssetType;
};
// Map of known bad assets
typedef std::map<LLUUID,U64,lluuid_less> toxic_asset_map_t;
class LLAssetStorage
{
public:
typedef ::LLStoreAssetCallback LLStoreAssetCallback;
typedef ::LLGetAssetCallback LLGetAssetCallback;
enum ERequestType
{
RT_INVALID = -1,
RT_DOWNLOAD = 0,
RT_UPLOAD = 1,
RT_LOCALUPLOAD = 2,
RT_COUNT = 3
};
protected:
bool mShutDown;
LLHost mUpstreamHost;
LLMessageSystem *mMessageSys;
LLXferManager *mXferManager;
typedef std::list<LLAssetRequest*> request_list_t;
request_list_t mPendingDownloads;
request_list_t mPendingUploads;
request_list_t mPendingLocalUploads;
// Map of toxic assets - these caused problems when recently rezzed, so avoid them
toxic_asset_map_t mToxicAssetMap; // Objects in this list are known to cause problems and are not loaded
public:
LLAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, const LLHost &upstream_host);
LLAssetStorage(LLMessageSystem *msg, LLXferManager *xfer);
virtual ~LLAssetStorage();
void setUpstream(const LLHost &upstream_host);
bool hasLocalAsset(const LLUUID &uuid, LLAssetType::EType type);
// public interface methods
// note that your callback may get called BEFORE the function returns
void getAssetData(const LLUUID uuid, LLAssetType::EType atype, LLGetAssetCallback cb, void *user_data, bool is_priority = false);
/*
* TransactionID version
* Viewer needs the store_local
*/
virtual void storeAssetData(
const LLTransactionID& tid,
LLAssetType::EType atype,
LLStoreAssetCallback callback,
void* user_data,
bool temp_file = false,
bool is_priority = false,
bool store_local = false,
bool user_waiting= false,
F64Seconds timeout=LL_ASSET_STORAGE_TIMEOUT) = 0;
virtual void logAssetStorageInfo() = 0;
virtual void checkForTimeouts();
void getEstateAsset(const LLHost &object_sim, const LLUUID &agent_id, const LLUUID &session_id,
const LLUUID &asset_id, LLAssetType::EType atype, EstateAssetType etype,
LLGetAssetCallback callback, void *user_data, bool is_priority);
void getInvItemAsset(const LLHost &object_sim,
const LLUUID &agent_id, const LLUUID &session_id,
const LLUUID &owner_id, const LLUUID &task_id, const LLUUID &item_id,
const LLUUID &asset_id, LLAssetType::EType atype,
LLGetAssetCallback cb, void *user_data, bool is_priority = false); // Get a particular inventory item.
// Check if an asset is in the toxic map. If it is, the entry is updated
bool isAssetToxic( const LLUUID& uuid );
// Clean the toxic asset list, remove old entries
void flushOldToxicAssets( bool force_it );
// Add an item to the toxic asset map
void markAssetToxic( const LLUUID& uuid );
protected:
bool findInCacheAndInvokeCallback(const LLUUID& uuid, LLAssetType::EType type,
LLGetAssetCallback callback, void *user_data);
LLSD getPendingDetailsImpl(const request_list_t* requests,
LLAssetType::EType asset_type,
const std::string& detail_prefix) const;
LLSD getPendingRequestImpl(const request_list_t* requests,
LLAssetType::EType asset_type,
const LLUUID& asset_id) const;
bool deletePendingRequestImpl(request_list_t* requests,
LLAssetType::EType asset_type,
const LLUUID& asset_id);
public:
static const LLAssetRequest* findRequest(const request_list_t* requests,
LLAssetType::EType asset_type,
const LLUUID& asset_id);
static LLAssetRequest* findRequest(request_list_t* requests,
LLAssetType::EType asset_type,
const LLUUID& asset_id);
request_list_t* getRequestList(ERequestType rt);
const request_list_t* getRequestList(ERequestType rt) const;
static std::string getRequestName(ERequestType rt);
S32 getNumPendingDownloads() const;
S32 getNumPendingUploads() const;
S32 getNumPendingLocalUploads();
S32 getNumPending(ERequestType rt) const;
LLSD getPendingDetails(ERequestType rt,
LLAssetType::EType asset_type,
const std::string& detail_prefix) const;
LLSD getPendingRequest(ERequestType rt,
LLAssetType::EType asset_type,
const LLUUID& asset_id) const;
bool deletePendingRequest(ERequestType rt,
LLAssetType::EType asset_type,
const LLUUID& asset_id);
static void removeAndCallbackPendingDownloads(const LLUUID& file_id, LLAssetType::EType file_type,
const LLUUID& callback_id, LLAssetType::EType callback_type,
S32 result_code, LLExtStat ext_status,
S32 bytes_fetched);
// download process callbacks
static void downloadCompleteCallback(
S32 result,
const LLUUID& file_id,
LLAssetType::EType file_type,
LLBaseDownloadRequest* user_data, LLExtStat ext_status);
static void downloadEstateAssetCompleteCallback(
S32 result,
const LLUUID& file_id,
LLAssetType::EType file_type,
LLBaseDownloadRequest* user_data, LLExtStat ext_status);
static void downloadInvItemCompleteCallback(
S32 result,
const LLUUID& file_id,
LLAssetType::EType file_type,
LLBaseDownloadRequest* user_data, LLExtStat ext_status);
// upload process callbacks
static void uploadCompleteCallback(const LLUUID&, void *user_data, S32 result, LLExtStat ext_status);
static void processUploadComplete(LLMessageSystem *msg, void **this_handle);
// debugging
static const char* getErrorString( S32 status );
// deprecated file-based methods
// Not overriden
void getAssetData(const LLUUID uuid, LLAssetType::EType type, void (*callback)(const char*, const LLUUID&, void *, S32, LLExtStat), void *user_data, bool is_priority = false);
/*
* TransactionID version
*/
virtual void storeAssetData(
const std::string& filename,
const LLTransactionID &transaction_id,
LLAssetType::EType type,
LLStoreAssetCallback callback,
void *user_data,
bool temp_file = false,
bool is_priority = false,
bool user_waiting = false,
F64Seconds timeout = LL_ASSET_STORAGE_TIMEOUT) = 0;
static void legacyGetDataCallback(const LLUUID &uuid, LLAssetType::EType, void *user_data, S32 status, LLExtStat ext_status);
static void legacyStoreDataCallback(const LLUUID &uuid, void *user_data, S32 status, LLExtStat ext_status);
// add extra methods to handle metadata
protected:
void _cleanupRequests(bool all, S32 error);
void _callUploadCallbacks(const LLUUID &uuid, const LLAssetType::EType asset_type, bool success, LLExtStat ext_status);
virtual void _queueDataRequest(const LLUUID& uuid, LLAssetType::EType type, LLGetAssetCallback callback,
void *user_data, bool duplicate,
bool is_priority) = 0;
private:
void _init(LLMessageSystem *msg,
LLXferManager *xfer,
const LLHost &upstream_host);
protected:
enum EMetricResult
{
// Static valued enums for #dw readability - please copy this
// declaration to them on updates -- source in llassetstorage.h
MR_INVALID = -1, // Makes no sense
MR_OKAY = 0, // Success - no metric normally
MR_ZERO_SIZE = 1, // Zero size asset
MR_BAD_FUNCTION = 2, // Tried to use a virtual base (PROGRAMMER ERROR)
MR_FILE_NONEXIST = 3, // Old format store call - source file does not exist
MR_NO_FILENAME = 4, // Old format store call - source filename is NULL/0-length
MR_NO_UPSTREAM = 5, // Upstream provider is missing
MR_CACHE_CORRUPTION = 6 // cache is corrupt - too-large or mismatched stated/returned sizes
};
static class LLMetrics *metric_recipient;
static void reportMetric( const LLUUID& asset_id, const LLAssetType::EType asset_type, const std::string& filename,
const LLUUID& agent_id, S32 asset_size, EMetricResult result,
const char* file, const S32 line, const std::string& message );
public:
static void setMetricRecipient( LLMetrics *recip )
{
metric_recipient = recip;
}
};
////////////////////////////////////////////////////////////////////////
// Wrappers to replicate deprecated API
////////////////////////////////////////////////////////////////////////
class LLLegacyAssetRequest
{
public:
void (*mDownCallback)(const char *, const LLUUID&, void *, S32, LLExtStat);
LLStoreAssetCallback mUpCallback;
void *mUserData;
};
extern LLAssetStorage *gAssetStorage;
extern const LLUUID CATEGORIZE_LOST_AND_FOUND_ID;
#endif
+340
View File
@@ -0,0 +1,340 @@
/**
* @file llavatarname.cpp
* @brief Represents name-related data for an avatar, such as the
* username/SLID ("bobsmith123" or "james.linden") and the display
* name ("James Cook")
*
* $LicenseInfo:firstyear=2010&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 "llavatarname.h"
#include "lldate.h"
#include "llframetimer.h"
#include "llsd.h"
// Store these in pre-built std::strings to avoid memory allocations in
// LLSD map lookups
static const std::string USERNAME("username");
static const std::string DISPLAY_NAME("display_name");
static const std::string LEGACY_FIRST_NAME("legacy_first_name");
static const std::string LEGACY_LAST_NAME("legacy_last_name");
static const std::string IS_DISPLAY_NAME_DEFAULT("is_display_name_default");
static const std::string DISPLAY_NAME_EXPIRES("display_name_expires");
static const std::string DISPLAY_NAME_NEXT_UPDATE("display_name_next_update");
bool LLAvatarName::sUseDisplayNames = true;
bool LLAvatarName::sUseUsernames = true;
bool LLAvatarName::sUseLegacyNameFormat = false; // <FS:CR> Legacy name option
bool LLAvatarName::sTrimResidentSurname = true; // FIRE-6659 - Trim "Resident" from legacy name
// Minimum time-to-live (in seconds) for a name entry.
// Avatar name should always guarantee to expire reasonably soon by default
// so if the failure to get a valid expiration time was due to something temporary
// we will eventually request and get the right data.
const F64 MIN_ENTRY_LIFETIME = 60.0;
LLAvatarName::LLAvatarName()
: mUsername(),
mDisplayName(),
mLegacyFirstName(),
mLegacyLastName(),
mIsDisplayNameDefault(false),
mIsTemporaryName(false),
mExpires(F64_MAX),
mNextUpdate(0.0)
{ }
bool LLAvatarName::operator<(const LLAvatarName& rhs) const
{
if (mUsername == rhs.mUsername)
return mDisplayName < rhs.mDisplayName;
else
return mUsername < rhs.mUsername;
}
//static
void LLAvatarName::setUseDisplayNames(bool use)
{
sUseDisplayNames = use;
}
//static
bool LLAvatarName::useDisplayNames()
{
return sUseDisplayNames;
}
void LLAvatarName::setUseUsernames(bool use)
{
sUseUsernames = use;
}
bool LLAvatarName::useUsernames()
{
return sUseUsernames;
}
LLSD LLAvatarName::asLLSD() const
{
LLSD sd;
sd[USERNAME] = mUsername;
sd[DISPLAY_NAME] = mDisplayName;
sd[LEGACY_FIRST_NAME] = mLegacyFirstName;
sd[LEGACY_LAST_NAME] = mLegacyLastName;
sd[IS_DISPLAY_NAME_DEFAULT] = mIsDisplayNameDefault;
sd[DISPLAY_NAME_EXPIRES] = LLDate(mExpires);
sd[DISPLAY_NAME_NEXT_UPDATE] = LLDate(mNextUpdate);
return sd;
}
void LLAvatarName::fromLLSD(const LLSD& sd)
{
mUsername = sd[USERNAME].asString();
mDisplayName = sd[DISPLAY_NAME].asString();
mLegacyFirstName = sd[LEGACY_FIRST_NAME].asString();
mLegacyLastName = sd[LEGACY_LAST_NAME].asString();
mIsDisplayNameDefault = sd[IS_DISPLAY_NAME_DEFAULT].asBoolean();
LLDate expires = sd[DISPLAY_NAME_EXPIRES];
mExpires = expires.secondsSinceEpoch();
LLDate next_update = sd[DISPLAY_NAME_NEXT_UPDATE];
mNextUpdate = next_update.secondsSinceEpoch();
// Some avatars don't have explicit display names set. Force a legible display name here.
if (mDisplayName.empty())
{
mDisplayName = mUsername;
// <FS:Ansariel> OpenSim GetDisplayNames cap support
mIsDisplayNameDefault = true;
}
}
// Transform a string (typically provided by the legacy service) into a decent
// avatar name instance.
void LLAvatarName::fromString(const std::string& full_name)
{
mDisplayName = full_name;
std::string::size_type index = full_name.find(' ');
if (index != std::string::npos)
{
// The name is in 2 parts (first last)
mLegacyFirstName = full_name.substr(0, index);
mLegacyLastName = full_name.substr(index+1);
// <FS:CR> FIRE-6659 - Trim "Resident" from legacy name
//if (mLegacyLastName != "Resident")
if ((mLegacyLastName != "Resident") || !sTrimResidentSurname)
// </FS:CR>
{
mUsername = mLegacyFirstName + "." + mLegacyLastName;
mDisplayName = full_name;
LLStringUtil::toLower(mUsername);
}
else
{
// Very old names do have a dummy "Resident" last name
// that we choose to hide from users.
mUsername = mLegacyFirstName;
mDisplayName = mLegacyFirstName;
}
}
else
{
mLegacyFirstName = full_name;
mLegacyLastName = "";
mUsername = full_name;
mDisplayName = full_name;
}
mIsDisplayNameDefault = true;
mIsTemporaryName = true;
setExpires(MIN_ENTRY_LIFETIME);
}
void LLAvatarName::setExpires(F64 expires)
{
mExpires = LLFrameTimer::getTotalSeconds() + expires;
}
std::string LLAvatarName::getCompleteName(bool use_parentheses, bool force_use_complete_name) const
{
std::string name;
if (sUseDisplayNames || force_use_complete_name)
{
if (mUsername.empty() || mIsDisplayNameDefault)
{
// If this particular display name is defaulted (i.e. based on user name),
// then display only the easier to read instance of the person's name.
// <FS:CR> FIRE-6659 - Trim "Resident" from legacy name
//name = mDisplayName;
if (sTrimResidentSurname || mLegacyFirstName.empty())
{
name = mDisplayName;
}
else if (mLegacyLastName.empty())
{
name = mLegacyFirstName + " Resident";
}
else
{
name = mLegacyFirstName + " " + mLegacyLastName;
}
// </FS:CR>
}
// <FS:CR> Option to show legacy name format instead of username
else if (sUseLegacyNameFormat)
{
// FIRE-6659
if (sTrimResidentSurname && (mLegacyLastName == "Resident" || mLegacyLastName.empty()))
{
name = mDisplayName + " (" + mLegacyFirstName + ")";
}
else if (mLegacyLastName.empty() && !sTrimResidentSurname)
{
name = mDisplayName + " (" + mLegacyLastName + " Resident)";
}
else
{
name = mDisplayName + " (" + mLegacyFirstName + " " + mLegacyLastName + ")";
}
}
// </FS:CR>
else
{
name = mDisplayName;
if(sUseUsernames || force_use_complete_name)
{
if(use_parentheses)
{
name += " (" + mUsername + ")";
}
else
{
name += " [ " + mUsername + " ]";
}
}
}
}
else
{
// <FS:CR> FIRE-6659 - Trim "Resident" from legacy name
//return getUserName();
return getUserNameForDisplay();
// </FS:CR>
}
return name;
}
std::string LLAvatarName::getLegacyName() const
{
if (mLegacyFirstName.empty() && mLegacyLastName.empty()) // display names disabled?
{
return mDisplayName;
}
std::string name;
name.reserve( mLegacyFirstName.size() + 1 + mLegacyLastName.size() );
name = mLegacyFirstName;
name += " ";
name += mLegacyLastName;
return name;
}
std::string LLAvatarName::getDisplayName(bool force_use_display_name) const
{
if (sUseDisplayNames || force_use_display_name)
{
return mDisplayName;
}
else
{
// <FS:CR> FIRE-6659 - Trim "Resident" from legacy name
//return getUserName();
return getUserNameForDisplay();
// </FS:CR>
}
}
std::string LLAvatarName::getUserName(bool lowercase) const
{
std::string name;
if (mLegacyLastName.empty() || (mLegacyLastName == "Resident"))
{
if (mLegacyFirstName.empty())
{
// If we cannot create a user name from the legacy strings, use the display name
name = mDisplayName;
}
else
{
// The last name might be empty if it defaulted to "Resident"
name = mLegacyFirstName;
}
}
else
{
if(lowercase)
{
name = mLegacyFirstName + "." + mLegacyLastName;
LLStringUtil::toLower(name);
}
else
{
name = mLegacyFirstName + " " + mLegacyLastName;
}
}
return name;
}
// <FS:CR> Returns the same as getUserName() but honors sTrimResidentSurname
std::string LLAvatarName::getUserNameForDisplay() const
{
std::string name;
if (mLegacyFirstName.empty() && mLegacyLastName.empty())
{
// If we cannot create a user name from the legacy strings, use the display name
name = mDisplayName;
}
else if ((mLegacyLastName.empty() || (mLegacyLastName == "Resident")) && sTrimResidentSurname)
{
// The last name might be empty if it defaulted to "Resident"
name = mLegacyFirstName;
}
else if (mLegacyLastName.empty() && !sTrimResidentSurname)
{
name = mLegacyFirstName + " Resident";
}
else
{
name = mLegacyFirstName + " " + mLegacyLastName;
}
return name;
}
// </FS:CR>
void LLAvatarName::dump() const
{
LL_DEBUGS("AvNameCache") << "LLAvatarName: "
<< "user '" << mUsername << "' "
<< "display '" << mDisplayName << "' "
<< "expires in " << mExpires - LLFrameTimer::getTotalSeconds() << " seconds"
<< LL_ENDL;
}
+157
View File
@@ -0,0 +1,157 @@
/**
* @file llavatarname.h
* @brief Represents name-related data for an avatar, such as the
* username/SLID ("bobsmith123" or "james.linden") and the display
* name ("James Cook")
*
* $LicenseInfo:firstyear=2010&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 LLAVATARNAME_H
#define LLAVATARNAME_H
#include <string>
class LLSD;
class LL_COMMON_API LLAvatarName
{
public:
LLAvatarName();
bool operator<(const LLAvatarName& rhs) const;
// Conversion to and from LLSD (cache file or server response)
LLSD asLLSD() const;
void fromLLSD(const LLSD& sd);
// Used only in legacy mode when the display name capability is not provided server side
// or to otherwise create a temporary valid item.
void fromString(const std::string& full_name);
// Set the name object to become invalid in "expires" seconds from now
void setExpires(F64 expires);
// Set and get the display name flag set by the user in preferences.
static void setUseDisplayNames(bool use);
static bool useDisplayNames();
// <FS:CR> Set and return the legacy name flag
static void setUseLegacyFormat(bool use) { sUseLegacyNameFormat = use; };
static bool useLegacyFormat() { return sUseLegacyNameFormat; };
// <FS:CR> Set and return the Resident trim flag
static void setTrimResidentSurname(bool use) { sTrimResidentSurname = use; };
static bool trimResidentSurname() { return sTrimResidentSurname; };
static void setUseUsernames(bool use);
static bool useUsernames();
// A name object is valid if not temporary and not yet expired (default is expiration not checked)
bool isValidName(F64 max_unrefreshed = 0.0f) const { return !mIsTemporaryName && (mExpires >= max_unrefreshed); }
// Return true if the name is made up from legacy or temporary data
bool isDisplayNameDefault() const { return mIsDisplayNameDefault; }
// For normal names, returns "James Linden (james.linden)"
// When display names are disabled returns just "James Linden"
std::string getCompleteName(bool use_parentheses = true, bool force_use_complete_name = false) const;
// Returns "James Linden" or "bobsmith123 Resident" for backwards
// compatibility with systems like voice and muting
// *TODO: Eliminate this in favor of username only
std::string getLegacyName() const;
// "José Sanchez" or "James Linden", UTF-8 encoded Unicode
// Takes the display name preference into account. This is truly the name that should
// be used for all UI where an avatar name has to be used unless we truly want something else (rare)
std::string getDisplayName(bool force_use_display_name = false) const;
// Returns "James Linden" or "bobsmith123 Resident"
// Used where we explicitely prefer or need a non UTF-8 legacy (ASCII) name
// Also used for backwards compatibility with systems like voice and muting
std::string getUserName(bool lowercase = false) const;
// <FS:CR> FIRE-6659 - Returns the same as getUserName() but honors sTrimResidentSurname
std::string getUserNameForDisplay() const;
// Returns "james.linden" or the legacy name for very old names
std::string getAccountName() const { return mUsername; }
// Debug print of the object
void dump() const;
// Names can change, so need to keep track of when name was
// last checked.
// Unix time-from-epoch seconds for efficiency
F64 mExpires;
// You can only change your name every N hours, so record
// when the next update is allowed
// Unix time-from-epoch seconds
F64 mNextUpdate;
private:
// "bobsmith123" or "james.linden", US-ASCII only
std::string mUsername;
// "José Sanchez" or "James Linden", UTF-8 encoded Unicode
// Contains data whether or not user has explicitly set
// a display name; may duplicate their username.
std::string mDisplayName;
// For "James Linden", "James"
// For "bobsmith123", "bobsmith123"
// Used to communicate with legacy systems like voice and muting which
// rely on old-style names.
// *TODO: Eliminate this in favor of username only
std::string mLegacyFirstName;
// For "James Linden", "Linden"
// For "bobsmith123", "Resident"
// see above for rationale
std::string mLegacyLastName;
// If true, both display name and SLID were generated from
// a legacy first and last name, like "James Linden (james.linden)"
bool mIsDisplayNameDefault;
// Under error conditions, we may insert "dummy" records with
// names like "???" into caches as placeholders. These can be
// shown in UI, but are not serialized.
bool mIsTemporaryName;
// Global flag indicating if display name should be used or not
// This will affect the output of the high level "get" methods
static bool sUseDisplayNames;
// Flag indicating if username should be shown after display name or not
static bool sUseUsernames;
/// <FS:CR> Global flag indicating using legacy format (First Last)
/// over username format (first.last)
static bool sUseLegacyNameFormat;
// <FS:CR> Flag indicating trimming "Resident" from names
static bool sTrimResidentSurname;
};
#endif
File diff suppressed because it is too large Load Diff
+221
View File
@@ -0,0 +1,221 @@
/**
* @file llavatarnamecache.h
* @brief Provides lookup of avatar SLIDs ("bobsmith123") and display names
* ("James Cook") from avatar UUIDs.
*
* $LicenseInfo:firstyear=2010&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 LLAVATARNAMECACHE_H
#define LLAVATARNAMECACHE_H
#include "llavatarname.h" // for convenience
#include "llsingleton.h"
#include <boost/signals2.hpp>
#include <set>
class LLSD;
class LLUUID;
class LLAvatarNameCache : public LLSingleton<LLAvatarNameCache>
{
LLSINGLETON(LLAvatarNameCache);
~LLAvatarNameCache();
public:
typedef boost::signals2::signal<void (void)> use_display_name_signal_t;
typedef boost::function<void (const LLUUID id, const LLAvatarName& av_name)> account_name_changed_callback_t;
// <FS:Ansariel> Contact sets
typedef boost::function<bool(const LLUUID& id, bool& dn_removed, std::string& custom_name)> custom_name_check_callback_t;
void setCustomNameCheckCallback(custom_name_check_callback_t cb)
{
mCustomNameCheckCallback = cb;
}
// </FS:Ansariel>
// Import/export the name cache to file.
bool importFile(std::istream& istr);
void exportFile(std::ostream& ostr);
// On the viewer, usually a simulator capabilities.
// If empty, name cache will fall back to using legacy name lookup system.
void setNameLookupURL(const std::string& name_lookup_url);
// Do we have a valid lookup URL, i.e. are we trying to use the
// more recent display name lookup system?
bool hasNameLookupURL();
void setUsePeopleAPI(bool use_api);
bool usePeopleAPI();
// Periodically makes a batch request for display names not already in
// cache. Called once per frame.
void idle();
// If name is in cache, returns true and fills in provided LLAvatarName
// otherwise returns false.
static bool get(const LLUUID& agent_id, LLAvatarName *av_name);
bool getName(const LLUUID& agent_id, LLAvatarName *av_name);
// Callback types for get() below
typedef boost::signals2::signal<
void (const LLUUID& agent_id, const LLAvatarName& av_name)>
callback_signal_t;
typedef callback_signal_t::slot_type callback_slot_t;
typedef boost::signals2::connection callback_connection_t;
// Fetches name information and calls callbacks.
// If name information is in cache, callbacks will be called immediately.
static callback_connection_t get(const LLUUID& agent_id, callback_slot_t slot);
callback_connection_t getNameCallback(const LLUUID& agent_id, callback_slot_t slot);
// Set display name: flips the switch and triggers the callbacks.
void setUseDisplayNames(bool use);
void setUseUsernames(bool use);
void insert(const LLUUID& agent_id, const LLAvatarName& av_name);
// [RLVa:KB] - Checked: 2010-12-08 (RLVa-1.4.0a) | Added: RLVa-1.2.2c
bool getForceDisplayNames();
void setForceDisplayNames(bool force);
// [/RLVa:KB]
void erase(const LLUUID& agent_id);
// A way to find agent id by UUID, very slow, also unreliable
// since it doesn't request names, just serch exsisting ones
// that are likely not in cache.
//
// Todo: Find a way to remove this.
// Curently this method is used for chat history and in some cases notices.
LLUUID findIdByName(const std::string& name);
/// Provide some fallback for agents that return errors.
void handleAgentError(const LLUUID& agent_id);
// Force a re-fetch of the most recent data, but keep the current
// data in cache
void fetch(const LLUUID& agent_id); // FS:TM used in LGGContactSets
// Compute name expiration time from HTTP Cache-Control header,
// or return default value, in seconds from epoch.
F64 nameExpirationFromHeaders(const LLSD& headers);
void addUseDisplayNamesCallback(const use_display_name_signal_t::slot_type& cb);
void setAccountNameChangedCallback(const account_name_changed_callback_t& cb) { mAccountNameChangedCallback = cb; }
// <FS:Ansariel> FIRE-6659: Legacy "Resident" name toggle
void clearCache();
private:
// Handle name response off network.
void processName(const LLUUID& agent_id,
const LLAvatarName& av_name);
void requestNamesViaCapability();
// Legacy name system callbacks
static void legacyNameCallback(const LLUUID& agent_id,
const std::string& full_name,
bool is_group);
static void legacyNameFetch(const LLUUID& agent_id,
const std::string& full_name,
bool is_group);
void requestNamesViaLegacy();
// Do a single callback to a given slot
void fireSignal(const LLUUID& agent_id,
const callback_slot_t& slot,
const LLAvatarName& av_name);
// Is a request in-flight over the network?
bool isRequestPending(const LLUUID& agent_id);
// Erase expired names from cache
void eraseUnrefreshed();
bool expirationFromCacheControl(const LLSD& headers, F64 *expires);
// This is a coroutine.
static void requestAvatarNameCache_(std::string url, std::vector<LLUUID> agentIds);
void handleAvNameCacheSuccess(const LLSD &data, const LLSD &httpResult);
private:
use_display_name_signal_t mUseDisplayNamesSignal;
account_name_changed_callback_t mAccountNameChangedCallback;
// Cache starts in a paused state until we can determine if the
// current region supports display names.
bool mRunning;
// Use the People API (modern) for fetching name if true. Use the old legacy protocol if false.
// For testing, there's a UsePeopleAPI setting that can be flipped (must restart viewer).
bool mUsePeopleAPI;
// [RLVa:KB] - Checked: 2010-12-08 (RLVa-1.4.0a) | Added: RLVa-1.2.2c
// RLVa override for display names
bool mRlvForceDisplayNames = false;
// [/RLVa:KB]
// Base lookup URL for name service.
// On simulator, loaded from indra.xml
// On viewer, usually a simulator capability (at People API team's request)
// Includes the trailing slash, like "http://pdp60.lindenlab.com:8000/agents/"
std::string mNameLookupURL;
// Accumulated agent IDs for next query against service
typedef std::set<LLUUID> ask_queue_t;
ask_queue_t mAskQueue;
// Agent IDs that have been requested, but with no reply.
// Maps agent ID to frame time request was made.
typedef std::map<LLUUID, F64> pending_queue_t;
pending_queue_t mPendingQueue;
// Callbacks to fire when we received a name.
// May have multiple callbacks for a single ID, which are
// represented as multiple slots bound to the signal.
// Avoid copying signals via pointers.
typedef std::map<LLUUID, callback_signal_t*> signal_map_t;
signal_map_t mSignalMap;
// The cache at last, i.e. avatar names we know about.
typedef std::map<LLUUID, LLAvatarName> cache_t;
cache_t mCache;
// Time when unrefreshed cached names were checked last.
F64 mLastExpireCheck;
// <FS:Ansariel> Contact sets
custom_name_check_callback_t mCustomNameCheckCallback;
};
// Parse a cache-control header to get the max-age delta-seconds.
// Returns true if header has max-age param and it parses correctly.
// Exported here to ease unit testing.
bool max_age_from_cache_control(const std::string& cache_control, S32 *max_age);
#endif
+176
View File
@@ -0,0 +1,176 @@
/**
* @file llblowfishcipher.cpp
* @brief Wrapper around OpenSSL Blowfish encryption algorithm.
*
* $LicenseInfo:firstyear=2007&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 "llblowfishcipher.h"
#include <openssl/evp.h>
LLBlowfishCipher::LLBlowfishCipher(const U8* secret, size_t secret_size)
: LLCipher()
{
llassert(secret);
mSecretSize = secret_size;
mSecret = new U8[mSecretSize];
memcpy(mSecret, secret, mSecretSize);
}
LLBlowfishCipher::~LLBlowfishCipher()
{
delete [] mSecret;
mSecret = NULL;
}
// virtual
U32 LLBlowfishCipher::encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len)
{
if (!src || !src_len || !dst || !dst_len) return 0;
if (src_len > dst_len) return 0;
// OpenSSL uses "cipher contexts" to hold encryption parameters.
EVP_CIPHER_CTX *context = EVP_CIPHER_CTX_new();
if (!context)
{
LL_WARNS() << "LLBlowfishCipher::encrypt EVP_CIPHER_CTX initiation failure" << LL_ENDL;
return 0;
}
// We want a blowfish cyclic block chain cipher, but need to set
// the key length before we pass in a key, so call EncryptInit
// first with NULLs.
EVP_EncryptInit_ex(context, EVP_bf_cbc(), NULL, NULL, NULL);
EVP_CIPHER_CTX_set_key_length(context, (int)mSecretSize);
// Complete initialization. Per EVP_EncryptInit man page, the
// cipher pointer must be NULL. Apparently initial_vector must
// be 8 bytes for blowfish, as this is the block size.
unsigned char initial_vector[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
EVP_EncryptInit_ex(context, NULL, NULL, mSecret, initial_vector);
int blocksize = EVP_CIPHER_CTX_block_size(context);
int keylen = EVP_CIPHER_CTX_key_length(context);
int iv_length = EVP_CIPHER_CTX_iv_length(context);
LL_DEBUGS() << "LLBlowfishCipher blocksize " << blocksize
<< " keylen " << keylen
<< " iv_len " << iv_length
<< LL_ENDL;
int output_len = 0;
int temp_len = 0;
if (!EVP_EncryptUpdate(context,
dst,
&output_len,
src,
src_len))
{
LL_WARNS() << "LLBlowfishCipher::encrypt EVP_EncryptUpdate failure" << LL_ENDL;
goto BF_ENCRYPT_ERROR;
}
// There may be some final data left to encrypt if the input is
// not an exact multiple of the block size.
if (!EVP_EncryptFinal_ex(context, (unsigned char*)(dst + output_len), &temp_len))
{
LL_WARNS() << "LLBlowfishCipher::encrypt EVP_EncryptFinal failure" << LL_ENDL;
goto BF_ENCRYPT_ERROR;
}
output_len += temp_len;
EVP_CIPHER_CTX_free(context);
return output_len;
BF_ENCRYPT_ERROR:
EVP_CIPHER_CTX_free(context);
return 0;
}
// virtual
U32 LLBlowfishCipher::decrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len)
{
// <FS:CR> Blowfish decrypt
//LL_ERRS() << "LLBlowfishCipher decrypt unsupported" << LL_ENDL;
//return 0;
if (!src || !src_len || !dst || !dst_len) return 0;
if (src_len > dst_len) return 0;
EVP_CIPHER_CTX *context = EVP_CIPHER_CTX_new();
if (!context)
{
LL_WARNS() << "LLBlowfishCipher::encrypt EVP_CIPHER_CTX initiation failure" << LL_ENDL;
return 0;
}
EVP_DecryptInit_ex(context, EVP_bf_cbc(), NULL, NULL, NULL);
EVP_CIPHER_CTX_set_key_length(context, (int)mSecretSize);
unsigned char initial_vector[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
EVP_DecryptInit_ex(context, NULL, NULL, mSecret, initial_vector);
int blocksize = EVP_CIPHER_CTX_block_size(context);
int keylen = EVP_CIPHER_CTX_key_length(context);
int iv_length = EVP_CIPHER_CTX_iv_length(context);
LL_DEBUGS() << "LLBlowfishCipher blocksize " << blocksize
<< " keylen " << keylen
<< " iv_len " << iv_length
<< LL_ENDL;
int out_len = 0;
int tmp_len = 0;
if (!EVP_DecryptUpdate(context, dst, &out_len, src, src_len))
{
LL_WARNS() << "LLBlowfishCipher::decrypt EVP_DecryptUpdate failure" << LL_ENDL;
goto ERROR;
}
if (!EVP_DecryptFinal_ex(context, dst + out_len, &tmp_len))
{
LL_WARNS() << "LLBlowfishCipher::decrypt EVP_DecryptFinal failure" << LL_ENDL;
goto ERROR;
}
out_len += tmp_len;
EVP_CIPHER_CTX_free(context);
return out_len;
ERROR:
EVP_CIPHER_CTX_free(context);
return 0;
// </FS:CR>
}
// virtual
U32 LLBlowfishCipher::requiredEncryptionSpace(U32 len) const
{
// *HACK: We know blowfish uses an 8 byte block size.
// Oddly, sometimes EVP_Encrypt produces an extra block
// if the input is an exact multiple of the block size.
// So round up.
const U32 BLOCK_SIZE = 8;
len += BLOCK_SIZE;
len -= (len % BLOCK_SIZE);
return len;
}
+57
View File
@@ -0,0 +1,57 @@
/**
* @file llblowfishcipher.h
* @brief A symmetric block cipher, designed in 1993 by Bruce Schneier.
* We use it because it has an 8 byte block size, allowing encryption of
* two UUIDs and a timestamp (16x2 + 4 = 36 bytes) with only 40 bytes of
* output. AES has a block size of 32 bytes, so this would require 64 bytes.
*
* $LicenseInfo:firstyear=2007&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 LLBLOWFISHCIPHER_H
#define LLBLOWFISHCIPHER_H
#include "llcipher.h"
class LLBlowfishCipher : public LLCipher
{
public:
// Secret may be up to 56 bytes in length per Blowfish spec.
LLBlowfishCipher(const U8* secret, size_t secret_size);
virtual ~LLBlowfishCipher();
// See llcipher.h for documentation.
/*virtual*/ U32 encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len);
/*virtual*/ U32 decrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len);
/*virtual*/ U32 requiredEncryptionSpace(U32 src_len) const;
#ifdef _DEBUG
static bool testHarness();
#endif
private:
U8* mSecret;
size_t mSecretSize;
};
#endif // LL_LLCRYPTO_H
+908
View File
@@ -0,0 +1,908 @@
/**
* @file llbuffer.cpp
* @author Phoenix
* @date 2005-09-20
* @brief Implementation of the segments, buffers, and buffer arrays.
*
* $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 "llbuffer.h"
#include "llmath.h"
#include "llstl.h"
#include "llthread.h"
#include "llmutex.h"
#include <iterator>
#define ASSERT_LLBUFFERARRAY_MUTEX_LOCKED() llassert(!mMutexp || mMutexp->isSelfLocked())
/**
* LLSegment
*/
LLSegment::LLSegment() :
mChannel(0),
mData(NULL),
mSize(0)
{
}
LLSegment::LLSegment(S32 channel, U8* data, S32 data_len) :
mChannel(channel),
mData(data),
mSize(data_len)
{
}
LLSegment::~LLSegment()
{
}
bool LLSegment::isOnChannel(S32 channel) const
{
return (mChannel == channel);
}
S32 LLSegment::getChannel() const
{
return mChannel;
}
void LLSegment::setChannel(S32 channel)
{
mChannel = channel;
}
U8* LLSegment::data() const
{
return mData;
}
S32 LLSegment::size() const
{
return mSize;
}
bool LLSegment::operator==(const LLSegment& rhs) const
{
if((mData != rhs.mData)||(mSize != rhs.mSize)||(mChannel != rhs.mChannel))
{
return false;
}
return true;
}
/**
* LLHeapBuffer
*/
LLHeapBuffer::LLHeapBuffer() :
mBuffer(NULL),
mSize(0),
mNextFree(NULL),
mReclaimedBytes(0)
{
const S32 DEFAULT_HEAP_BUFFER_SIZE = 16384;
allocate(DEFAULT_HEAP_BUFFER_SIZE);
}
LLHeapBuffer::LLHeapBuffer(S32 size) :
mBuffer(NULL),
mSize(0),
mNextFree(NULL),
mReclaimedBytes(0)
{
allocate(size);
}
LLHeapBuffer::LLHeapBuffer(const U8* src, S32 len) :
mBuffer(NULL),
mSize(0),
mNextFree(NULL),
mReclaimedBytes(0)
{
if((len > 0) && src)
{
allocate(len);
if(mBuffer)
{
memcpy(mBuffer, src, len); /*Flawfinder: ignore*/
}
}
}
// virtual
LLHeapBuffer::~LLHeapBuffer()
{
delete[] mBuffer;
mBuffer = NULL;
mSize = 0;
mNextFree = NULL;
}
S32 LLHeapBuffer::bytesLeft() const
{
return (mSize - (S32)(mNextFree - mBuffer));
}
// virtual
bool LLHeapBuffer::createSegment(
S32 channel,
S32 size,
LLSegment& segment)
{
// get actual size of the segment.
S32 actual_size = llmin(size, (mSize - S32(mNextFree - mBuffer)));
// bail if we cannot build a valid segment
if(actual_size <= 0)
{
return false;
}
// Yay, we're done.
segment = LLSegment(channel, mNextFree, actual_size);
mNextFree += actual_size;
return true;
}
// virtual
bool LLHeapBuffer::reclaimSegment(const LLSegment& segment)
{
if(containsSegment(segment))
{
mReclaimedBytes += segment.size();
if(mReclaimedBytes == mSize)
{
// We have reclaimed all of the memory from this
// buffer. Therefore, we can reset the mNextFree to the
// start of the buffer, and reset the reclaimed bytes.
mReclaimedBytes = 0;
mNextFree = mBuffer;
}
else if(mReclaimedBytes > mSize)
{
LL_WARNS() << "LLHeapBuffer reclaimed more memory than allocated."
<< " This is probably programmer error." << LL_ENDL;
}
return true;
}
return false;
}
// virtual
bool LLHeapBuffer::containsSegment(const LLSegment& segment) const
{
// *NOTE: this check is fairly simple because heap buffers are
// simple contiguous chunks of heap memory.
if((mBuffer > segment.data())
|| ((mBuffer + mSize) < (segment.data() + segment.size())))
{
return false;
}
return true;
}
void LLHeapBuffer::allocate(S32 size)
{
mReclaimedBytes = 0;
mBuffer = new U8[size];
if(mBuffer)
{
mSize = size;
mNextFree = mBuffer;
}
}
/**
* LLBufferArray
*/
LLBufferArray::LLBufferArray() :
mNextBaseChannel(0),
mMutexp(NULL)
{
}
LLBufferArray::~LLBufferArray()
{
std::for_each(mBuffers.begin(), mBuffers.end(), DeletePointer());
mBuffers.clear();
delete mMutexp;
}
// static
LLChannelDescriptors LLBufferArray::makeChannelConsumer(
const LLChannelDescriptors& channels)
{
LLChannelDescriptors rv(channels.out());
return rv;
}
void LLBufferArray::lock()
{
if(mMutexp)
{
mMutexp->lock() ;
}
}
void LLBufferArray::unlock()
{
if(mMutexp)
{
mMutexp->unlock() ;
}
}
LLMutex* LLBufferArray::getMutex()
{
return mMutexp ;
}
void LLBufferArray::setThreaded(bool threaded)
{
if(threaded)
{
if(!mMutexp)
{
mMutexp = new LLMutex();
}
}
else
{
if(mMutexp)
{
delete mMutexp ;
mMutexp = NULL ;
}
}
}
LLChannelDescriptors LLBufferArray::nextChannel()
{
LLChannelDescriptors rv(mNextBaseChannel++);
return rv;
}
//mMutexp should be locked before calling this.
S32 LLBufferArray::capacity() const
{
ASSERT_LLBUFFERARRAY_MUTEX_LOCKED();
S32 total = 0;
const_buffer_iterator_t iter = mBuffers.begin();
const_buffer_iterator_t end = mBuffers.end();
for(; iter != end; ++iter)
{
total += (*iter)->capacity();
}
return total;
}
bool LLBufferArray::append(S32 channel, const U8* src, S32 len)
{
LLMutexLock lock(mMutexp) ;
std::vector<LLSegment> segments;
if(copyIntoBuffers(channel, src, len, segments))
{
mSegments.insert(mSegments.end(), segments.begin(), segments.end());
return true;
}
return false;
}
//mMutexp should be locked before calling this.
bool LLBufferArray::prepend(S32 channel, const U8* src, S32 len)
{
ASSERT_LLBUFFERARRAY_MUTEX_LOCKED();
std::vector<LLSegment> segments;
if(copyIntoBuffers(channel, src, len, segments))
{
mSegments.insert(mSegments.begin(), segments.begin(), segments.end());
return true;
}
return false;
}
bool LLBufferArray::insertAfter(
segment_iterator_t segment,
S32 channel,
const U8* src,
S32 len)
{
std::vector<LLSegment> segments;
LLMutexLock lock(mMutexp) ;
if(mSegments.end() != segment)
{
++segment;
}
if(copyIntoBuffers(channel, src, len, segments))
{
mSegments.insert(segment, segments.begin(), segments.end());
return true;
}
return false;
}
//mMutexp should be locked before calling this.
LLBufferArray::segment_iterator_t LLBufferArray::splitAfter(U8* address)
{
ASSERT_LLBUFFERARRAY_MUTEX_LOCKED();
segment_iterator_t end = mSegments.end();
segment_iterator_t it = getSegment(address);
if(it == end)
{
return end;
}
// We have the location and the segment.
U8* base = (*it).data();
S32 size = (*it).size();
if(address == (base + size))
{
// No need to split, since this is the last byte of the
// segment. We do not want to have zero length segments, since
// that will only incur processing overhead with no advantage.
return it;
}
S32 channel = (*it).getChannel();
LLSegment segment1(channel, base, (S32)((address - base) + 1));
*it = segment1;
segment_iterator_t rv = it;
++it;
LLSegment segment2(channel, address + 1, (S32)(size - (address - base) - 1));
mSegments.insert(it, segment2);
return rv;
}
//mMutexp should be locked before calling this.
LLBufferArray::segment_iterator_t LLBufferArray::beginSegment()
{
ASSERT_LLBUFFERARRAY_MUTEX_LOCKED();
return mSegments.begin();
}
//mMutexp should be locked before calling this.
LLBufferArray::segment_iterator_t LLBufferArray::endSegment()
{
ASSERT_LLBUFFERARRAY_MUTEX_LOCKED();
return mSegments.end();
}
//mMutexp should be locked before calling this.
LLBufferArray::segment_iterator_t LLBufferArray::constructSegmentAfter(
U8* address,
LLSegment& segment)
{
ASSERT_LLBUFFERARRAY_MUTEX_LOCKED();
segment_iterator_t rv = mSegments.begin();
segment_iterator_t end = mSegments.end();
if(!address)
{
if(rv != end)
{
segment = (*rv);
}
}
else
{
// we have an address - find the segment it is in.
for( ; rv != end; ++rv)
{
if((address >= (*rv).data())
&& (address < ((*rv).data() + (*rv).size())))
{
if((++address) < ((*rv).data() + (*rv).size()))
{
// it's in this segment - construct an appropriate
// sub-segment.
segment = LLSegment(
(*rv).getChannel(),
address,
(*rv).size() - (S32)(address - (*rv).data()));
}
else
{
++rv;
if(rv != end)
{
segment = (*rv);
}
}
break;
}
}
}
if(rv == end)
{
segment = LLSegment();
}
return rv;
}
//mMutexp should be locked before calling this.
LLBufferArray::segment_iterator_t LLBufferArray::getSegment(U8* address)
{
ASSERT_LLBUFFERARRAY_MUTEX_LOCKED();
segment_iterator_t end = mSegments.end();
if(!address)
{
return end;
}
segment_iterator_t it = mSegments.begin();
for( ; it != end; ++it)
{
if((address >= (*it).data())&&(address < (*it).data() + (*it).size()))
{
// found it.
return it;
}
}
return end;
}
//mMutexp should be locked before calling this.
LLBufferArray::const_segment_iterator_t LLBufferArray::getSegment(
U8* address) const
{
ASSERT_LLBUFFERARRAY_MUTEX_LOCKED();
const_segment_iterator_t end = mSegments.end();
if(!address)
{
return end;
}
const_segment_iterator_t it = mSegments.begin();
for( ; it != end; ++it)
{
if((address >= (*it).data())
&& (address < (*it).data() + (*it).size()))
{
// found it.
return it;
}
}
return end;
}
/*
U8* LLBufferArray::getAddressAfter(U8* address)
{
U8* rv = NULL;
segment_iterator_t it = getSegment(address);
segment_iterator_t end = mSegments.end();
if(it != end)
{
if(++address < ((*it).data() + (*it).size()))
{
// it's in the same segment
rv = address;
}
else
{
// it's in the next segment
if(++it != end)
{
rv = (*it).data();
}
}
}
return rv;
}
*/
S32 LLBufferArray::countAfter(S32 channel, U8* start) const
{
S32 count = 0;
S32 offset = 0;
const_segment_iterator_t it;
LLMutexLock lock(mMutexp) ;
const_segment_iterator_t end = mSegments.end();
if(start)
{
it = getSegment(start);
if(it == end)
{
return count;
}
if(++start < ((*it).data() + (*it).size()))
{
// it's in the same segment
offset = (S32)(start - (*it).data());
}
else if(++it == end)
{
// it's in the next segment
return count;
}
}
else
{
it = mSegments.begin();
}
while(it != end)
{
if((*it).isOnChannel(channel))
{
count += (*it).size() - offset;
}
offset = 0;
++it;
}
return count;
}
U8* LLBufferArray::readAfter(
S32 channel,
U8* start,
U8* dest,
S32& len) const
{
U8* rv = start;
if(!dest || len <= 0)
{
return rv;
}
S32 bytes_left = len;
len = 0;
S32 bytes_to_copy = 0;
const_segment_iterator_t it;
LLMutexLock lock(mMutexp) ;
const_segment_iterator_t end = mSegments.end();
if(start)
{
it = getSegment(start);
if(it == end)
{
return rv;
}
if((++start < ((*it).data() + (*it).size()))
&& (*it).isOnChannel(channel))
{
// copy the data out of this segment
S32 bytes_in_segment = (*it).size() - (S32)(start - (*it).data());
bytes_to_copy = llmin(bytes_left, bytes_in_segment);
memcpy(dest, start, bytes_to_copy); /*Flawfinder: ignore*/
len += bytes_to_copy;
bytes_left -= bytes_to_copy;
rv = start + bytes_to_copy - 1;
++it;
}
else
{
++it;
}
}
else
{
it = mSegments.begin();
}
while(bytes_left && (it != end))
{
if(!((*it).isOnChannel(channel)))
{
++it;
continue;
}
bytes_to_copy = llmin(bytes_left, (*it).size());
memcpy(dest + len, (*it).data(), bytes_to_copy); /*Flawfinder: ignore*/
len += bytes_to_copy;
bytes_left -= bytes_to_copy;
rv = (*it).data() + bytes_to_copy - 1;
++it;
}
return rv;
}
U8* LLBufferArray::seek(
S32 channel,
U8* start,
S32 delta) const
{
ASSERT_LLBUFFERARRAY_MUTEX_LOCKED();
const_segment_iterator_t it;
const_segment_iterator_t end = mSegments.end();
U8* rv = start;
if(0 == delta)
{
if((U8*)npos == start)
{
// someone is looking for end of data.
segment_list_t::const_reverse_iterator rit = mSegments.rbegin();
segment_list_t::const_reverse_iterator rend = mSegments.rend();
while(rit != rend)
{
if(!((*rit).isOnChannel(channel)))
{
++rit;
continue;
}
rv = (*rit).data() + (*rit).size();
break;
}
}
else if(start)
{
// This is sort of a weird case - check if zero bytes away
// from current position is on channel and return start if
// that is true. Otherwise, return NULL.
it = getSegment(start);
if((it == end) || !(*it).isOnChannel(channel))
{
rv = NULL;
}
}
else
{
// Start is NULL, so return the very first byte on the
// channel, or NULL.
it = mSegments.begin();
while((it != end) && !(*it).isOnChannel(channel))
{
++it;
}
if(it != end)
{
rv = (*it).data();
}
}
return rv;
}
if(start)
{
it = getSegment(start);
if((it != end) && (*it).isOnChannel(channel))
{
if(delta > 0)
{
S32 bytes_in_segment = (*it).size() - (S32)(start - (*it).data());
S32 local_delta = llmin(delta, bytes_in_segment);
rv += local_delta;
delta -= local_delta;
++it;
}
else
{
S32 bytes_in_segment = (S32)(start - (*it).data());
S32 local_delta = llmin(llabs(delta), bytes_in_segment);
rv -= local_delta;
delta += local_delta;
}
}
}
else if(delta < 0)
{
// start is NULL, and delta indicates seeking backwards -
// return NULL.
return NULL;
}
else
{
// start is NULL and delta > 0
it = mSegments.begin();
}
if(delta > 0)
{
// At this point, we have an iterator into the segments, and
// are seeking forward until delta is zero or we run out
while(delta && (it != end))
{
if(!((*it).isOnChannel(channel)))
{
++it;
continue;
}
if(delta <= (*it).size())
{
// it's in this segment
rv = (*it).data() + delta;
}
delta -= (*it).size();
++it;
}
if(delta && (it == end))
{
// Whoops - sought past end.
rv = NULL;
}
}
else //if(delta < 0)
{
// We are at the beginning of a segment, and need to search
// backwards.
segment_list_t::const_reverse_iterator rit(it);
segment_list_t::const_reverse_iterator rend = mSegments.rend();
while(delta && (rit != rend))
{
if(!((*rit).isOnChannel(channel)))
{
++rit;
continue;
}
if(llabs(delta) <= (*rit).size())
{
// it's in this segment.
rv = (*rit).data() + (*rit).size() + delta;
delta = 0;
}
else
{
delta += (*rit).size();
}
++rit;
}
if(delta && (rit == rend))
{
// sought past the beginning.
rv = NULL;
}
}
return rv;
}
//test use only
bool LLBufferArray::takeContents(LLBufferArray& source)
{
LLMutexLock lock(mMutexp);
source.lock();
std::copy(
source.mBuffers.begin(),
source.mBuffers.end(),
std::back_insert_iterator<buffer_list_t>(mBuffers));
source.mBuffers.clear();
std::copy(
source.mSegments.begin(),
source.mSegments.end(),
std::back_insert_iterator<segment_list_t>(mSegments));
source.mSegments.clear();
source.mNextBaseChannel = 0;
source.unlock();
return true;
}
//mMutexp should be locked before calling this.
LLBufferArray::segment_iterator_t LLBufferArray::makeSegment(
S32 channel,
S32 len)
{
ASSERT_LLBUFFERARRAY_MUTEX_LOCKED();
// start at the end of the buffers, because it is the most likely
// to have free space.
LLSegment segment;
buffer_list_t::reverse_iterator it = mBuffers.rbegin();
buffer_list_t::reverse_iterator end = mBuffers.rend();
bool made_segment = false;
for(; it != end; ++it)
{
if((*it)->createSegment(channel, len, segment))
{
made_segment = true;
break;
}
}
segment_iterator_t send = mSegments.end();
if(!made_segment)
{
LLBuffer* buf = new LLHeapBuffer;
mBuffers.push_back(buf);
if(!buf->createSegment(channel, len, segment))
{
// failed. this should never happen.
return send;
}
}
// store and return the newly made segment
mSegments.insert(send, segment);
std::list<LLSegment>::reverse_iterator rv = mSegments.rbegin();
++rv;
send = rv.base();
return send;
}
//mMutexp should be locked before calling this.
bool LLBufferArray::eraseSegment(const segment_iterator_t& erase_iter)
{
ASSERT_LLBUFFERARRAY_MUTEX_LOCKED();
// Find out which buffer contains the segment, and if it is found,
// ask it to reclaim the memory.
bool rv = false;
LLSegment segment(*erase_iter);
buffer_iterator_t iter = mBuffers.begin();
buffer_iterator_t end = mBuffers.end();
for(; iter != end; ++iter)
{
// We can safely call reclaimSegment on every buffer, and once
// it returns true, the segment was found.
if((*iter)->reclaimSegment(segment))
{
rv = true;
break;
}
}
// No need to get the return value since we are not interested in
// the interator retured by the call.
(void)mSegments.erase(erase_iter);
return rv;
}
//mMutexp should be locked before calling this.
bool LLBufferArray::copyIntoBuffers(
S32 channel,
const U8* src,
S32 len,
std::vector<LLSegment>& segments)
{
ASSERT_LLBUFFERARRAY_MUTEX_LOCKED();
if(!src || !len) return false;
S32 copied = 0;
LLSegment segment;
buffer_iterator_t it = mBuffers.begin();
buffer_iterator_t end = mBuffers.end();
for(; it != end;)
{
if(!(*it)->createSegment(channel, len, segment))
{
++it;
continue;
}
segments.push_back(segment);
S32 bytes = llmin(segment.size(), len);
memcpy(segment.data(), src + copied, bytes); /* Flawfinder: Ignore */
copied += bytes;
len -= bytes;
if(0 == len)
{
break;
}
}
while(len)
{
LLBuffer* buf = new LLHeapBuffer;
mBuffers.push_back(buf);
if(!buf->createSegment(channel, len, segment))
{
// this totally failed - bail. This is the weird corner
// case were we 'leak' memory. No worries about an actual
// leak - we will still reclaim the memory later, but this
// particular buffer array is hosed for some reason.
// This should never happen.
return false;
}
segments.push_back(segment);
memcpy(segment.data(), src + copied, segment.size()); /*Flawfinder: ignore*/
copied += segment.size();
len -= segment.size();
}
return true;
}
+625
View File
@@ -0,0 +1,625 @@
/**
* @file llbuffer.h
* @author Phoenix
* @date 2005-09-20
* @brief Declaration of buffer and buffer arrays primarily used in I/O.
*
* $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_LLBUFFER_H
#define LL_LLBUFFER_H
/**
* Declaration of classes used for minimizing calls to new[],
* memcpy(), and delete[]. Typically, you would create an LLBufferArray,
* feed it data, modify and add segments as you process it, and feed
* it to a sink.
*/
#include <list>
#include <vector>
class LLMutex;
/**
* @class LLChannelDescriptors
* @brief A way simple interface to accesss channels inside a buffer
*/
class LLChannelDescriptors
{
public:
// enumeration for segmenting the channel information
enum { E_CHANNEL_COUNT = 3 };
LLChannelDescriptors() : mBaseChannel(0) {}
explicit LLChannelDescriptors(S32 base) : mBaseChannel(base) {}
S32 in() const { return mBaseChannel; }
S32 out() const { return mBaseChannel + 1; }
//S32 err() const { return mBaseChannel + 2; }
protected:
S32 mBaseChannel;
};
/**
* @class LLSegment
* @brief A segment is a single, contiguous chunk of memory in a buffer
*
* Each segment represents a contiguous addressable piece of memory
* which is located inside a buffer. The segment is not responsible
* for allocation or deallcoation of the data. Each segment is a light
* weight object, and simple enough to copy around, use, and generate
* as necessary.
* This is the preferred interface for working with memory blocks,
* since it is the only way to safely, inexpensively, and directly
* access linear blocks of memory.
*/
class LLSegment
{
public:
LLSegment();
LLSegment(S32 channel, U8* data, S32 data_len);
~LLSegment();
/**
* @brief Check if this segment is on the given channel.
*
*/
bool isOnChannel(S32 channel) const;
/**
* @brief Get the channel
*/
S32 getChannel() const;
/**
* @brief Set the channel
*/
void setChannel(S32 channel);
/**
* @brief Return a raw pointer to the current data set.
*
* The pointer returned can be used for reading or even adjustment
* if you are a bit crazy up to size() bytes into memory.
* @return A potentially NULL pointer to the raw buffer data
*/
U8* data() const;
/**
* @brief Return the size of the segment
*/
S32 size() const;
/**
* @brief Check if two segments are the same.
*
* Two segments are considered equal if they are on the same
* channel and cover the exact same address range.
* @param rhs the segment to compare with this segment.
* @return Returns true if they are equal.
*/
bool operator==(const LLSegment& rhs) const;
protected:
S32 mChannel;
U8* mData;
S32 mSize;
};
/**
* @class LLBuffer
* @brief Abstract base class for buffers
*
* This class declares the interface necessary for buffer arrays. A
* buffer is not necessarily a single contiguous memory chunk, so
* please do not circumvent the segment API.
*/
class LLBuffer
{
public:
/**
* @brief The buffer base class should have no responsibilities
* other than an interface.
*/
virtual ~LLBuffer() {}
/**
* @brief Generate a segment for this buffer.
*
* The segment returned is always contiguous memory. This call can
* fail if no contiguous memory is available, eg, offset is past
* the end. The segment returned may be smaller than the requested
* size. The segment will never be larger than the requested size.
* @param channel The channel for the segment.
* @param offset The offset from zero in the buffer.
* @param size The requested size of the segment.
* @param segment[out] The out-value from the operation
* @return Returns true if a segment was found.
*/
virtual bool createSegment(S32 channel, S32 size, LLSegment& segment) = 0;
/**
* @brief Reclaim a segment from this buffer.
*
* This method is called on a buffer object when a caller is done
* with a contiguous segment of memory inside this buffer. Since
* segments can be cut arbitrarily outside of the control of the
* buffer, this segment may not match any segment returned from
* <code>createSegment()</code>.
* @param segment The contiguous buffer segment to reclaim.
* @return Returns true if the call was successful.
*/
virtual bool reclaimSegment(const LLSegment& segment) = 0;
/**
* @brief Test if a segment is inside this buffer.
*
* @param segment The contiguous buffer segment to test.
* @return Returns true if the segment is in the bufffer.
*/
virtual bool containsSegment(const LLSegment& segment) const = 0;
/**
* @brief Return the current number of bytes allocated.
*
* This was implemented as a debugging tool, and it is not
* necessarily a good idea to use it for anything else.
*/
virtual S32 capacity() const = 0;
};
/**
* @class LLHeapBuffer
* @brief A large contiguous buffer allocated on the heap with new[].
*
* This class is a simple buffer implementation which allocates chunks
* off the heap. Once a buffer is constructed, it's buffer has a fixed
* length.
*/
class LLHeapBuffer : public LLBuffer
{
public:
/**
* @brief Construct a heap buffer with a reasonable default size.
*/
LLHeapBuffer();
/**
* @brief Construct a heap buffer with a specified size.
*
* @param size The minimum size of the buffer.
*/
explicit LLHeapBuffer(S32 size);
/**
* @brief Construct a heap buffer of minimum size len, and copy from src.
*
* @param src The source of the data to be copied.
* @param len The minimum size of the buffer.
*/
LLHeapBuffer(const U8* src, S32 len);
/**
* @brief Simple destruction.
*/
virtual ~LLHeapBuffer();
/**
* @brief Get the number of bytes left in the buffer.
*
* Note that this is not a virtual function, and only available in
* the LLHeapBuffer as a debugging aid.
* @return Returns the number of bytes left.
*/
S32 bytesLeft() const;
/**
* @brief Generate a segment for this buffer.
*
* The segment returned is always contiguous memory. This call can
* fail if no contiguous memory is available, eg, offset is past
* the end. The segment returned may be smaller than the requested
* size. It is up to the caller to delete the segment returned.
* @param channel The channel for the segment.
* @param offset The offset from zero in the buffer
* @param size The requested size of the segment
* @param segment[out] The out-value from the operation
* @return Returns true if a segment was found.
*/
virtual bool createSegment(S32 channel, S32 size, LLSegment& segment);
/**
* @brief reclaim a segment from this buffer.
*
* This method is called on a buffer object when a caller is done
* with a contiguous segment of memory inside this buffer. Since
* segments can be cut arbitrarily outside of the control of the
* buffer, this segment may not match any segment returned from
* <code>createSegment()</code>.
* This call will fail if the segment passed in is note completely
* inside the buffer, eg, if the segment starts before this buffer
* in memory or ends after it.
* @param segment The contiguous buffer segment to reclaim.
* @return Returns true if the call was successful.
*/
virtual bool reclaimSegment(const LLSegment& segment);
/**
* @brief Test if a segment is inside this buffer.
*
* @param segment The contiguous buffer segment to test.
* @return Returns true if the segment is in the bufffer.
*/
virtual bool containsSegment(const LLSegment& segment) const;
/**
* @brief Return the current number of bytes allocated.
*/
virtual S32 capacity() const { return mSize; }
protected:
U8* mBuffer;
S32 mSize;
U8* mNextFree;
S32 mReclaimedBytes;
private:
/**
* @brief Helper method to allocate a buffer and correctly set
* intertnal state of this buffer.
*/
void allocate(S32 size);
};
/**
* @class LLBufferArray
* @brief Class to represent scattered memory buffers and in-order segments
* of that buffered data.
*
* *NOTE: This class needs to have an iovec interface
*/
class LLBufferArray
{
public:
typedef std::vector<LLBuffer*> buffer_list_t;
typedef buffer_list_t::iterator buffer_iterator_t;
typedef buffer_list_t::const_iterator const_buffer_iterator_t;
typedef std::list<LLSegment> segment_list_t;
typedef segment_list_t::const_iterator const_segment_iterator_t;
typedef segment_list_t::iterator segment_iterator_t;
enum { npos = 0xffffffff };
LLBufferArray();
~LLBufferArray();
/* @name Channel methods
*/
//@{
/**
* @brief Generate the a channel descriptor which consumes the
* output for the channel passed in.
*/
static LLChannelDescriptors makeChannelConsumer(
const LLChannelDescriptors& channels);
/**
* @brief Generate the next channel descriptor for this buffer array.
*
* The channel descriptor interface is how the buffer array
* clients can know where to read and write data. Use this
* interface to get the 'next' channel set for usage. This is a
* bit of a simple hack until it's utility indicates it should be
* extended.
* @return Returns a valid channel descriptor set for input and output.
*/
LLChannelDescriptors nextChannel();
//@}
/* @name Data methods
*/
//@{
/**
* @brief Return the sum of all allocated bytes.
*/
S32 capacity() const;
// These methods will be useful once there is any kind of buffer
// besides a heap buffer.
//bool append(EBufferChannel channel, LLBuffer* data);
//bool prepend(EBufferChannel channel, LLBuffer* data);
//bool insertAfter(
// segment_iterator_t segment,
// EBufferChannel channel,
// LLBuffer* data);
/**
* @brief Put data on a channel at the end of this buffer array.
*
* The data is copied from src into the buffer array. At least one
* new segment is created and put on the end of the array. This
* object will internally allocate new buffers if necessary.
* @param channel The channel for this data
* @param src The start of memory for the data to be copied
* @param len The number of bytes of data to copy
* @return Returns true if the method worked.
*/
bool append(S32 channel, const U8* src, S32 len);
/**
* @brief Put data on a channel at the front of this buffer array.
*
* The data is copied from src into the buffer array. At least one
* new segment is created and put in the front of the array. This
* object will internally allocate new buffers if necessary.
* @param channel The channel for this data
* @param src The start of memory for the data to be copied
* @param len The number of bytes of data to copy
* @return Returns true if the method worked.
*/
bool prepend(S32 channel, const U8* src, S32 len);
/**
* @brief Insert data into a buffer array after a particular segment.
*
* The data is copied from src into the buffer array. At least one
* new segment is created and put in the array. This object will
* internally allocate new buffers if necessary.
* @param segment The segment in front of the new segments location
* @param channel The channel for this data
* @param src The start of memory for the data to be copied
* @param len The number of bytes of data to copy
* @return Returns true if the method worked.
*/
bool insertAfter(
segment_iterator_t segment,
S32 channel,
const U8* src,
S32 len);
/**
* @brief Count bytes in the buffer array on the specified channel
*
* @param channel The channel to count.
* @param start The start address in the array for counting. You
* can specify NULL to start at the beginning.
* @return Returns the number of bytes in the channel after start
*/
S32 countAfter(S32 channel, U8* start) const;
/**
* @brief Count all bytes on channel.
*
* Helper method which just calls countAfter().
* @param channel The channel to count.
* @return Returns the number of bytes in the channel.
*/
S32 count(S32 channel) const
{
return countAfter(channel, NULL);
}
/**
* @brief Read bytes in the buffer array on the specified channel
*
* You should prefer iterating over segments is possible since
* this method requires you to allocate large buffers - precisely
* what this class is trying to prevent. This method will skip
* any segments which are not on the given channel, so this method
* would usually be used to read a channel and copy that to a log
* or a socket buffer or something.
* @param channel The channel to read.
* @param start The start address in the array for reading. You
* can specify NULL to start at the beginning.
* @param dest The destination of the data read. This must be at
* least len bytes long.
* @param len[in,out] <b>in</b> How many bytes to read. <b>out</b> How
* many bytes were read.
* @return Returns the address of the last read byte.
*/
U8* readAfter(S32 channel, U8* start, U8* dest, S32& len) const;
/**
* @brief Find an address in a buffer array
*
* @param channel The channel to seek in.
* @param start The start address in the array for the seek
* operation. You can specify NULL to start the seek at the
* beginning, or pass in npos to start at the end.
* @param delta How many bytes to seek through the array.
* @return Returns the address of the last read byte.
*/
U8* seek(S32 channel, U8* start, S32 delta) const;
//@}
/* @name Buffer interaction
*/
//@{
/**
* @brief Take the contents of another buffer array
*
* This method simply strips the contents out of the source
* buffery array - segments, buffers, etc, and appends them to
* this instance. After this operation, the source is empty and
* ready for reuse.
* @param source The source buffer
* @return Returns true if the operation succeeded.
*/
bool takeContents(LLBufferArray& source);
//@}
/* @name Segment methods
*/
//@{
/**
* @brief Split a segments so that address is the last address of
* one segment, and the rest of the original segment becomes
* another segment on the same channel.
*
* After this method call,
* <code>getLastSegmentAddress(*getSegment(address)) ==
* address</code> should be true. This call will only create a new
* segment if the statement above is false before the call. Since
* you usually call splitAfter() to change a segment property, use
* getSegment() to perform those operations.
* @param address The address which will become the last address
* of the segment it is in.
* @return Returns an iterator to the segment which contains
* <code>address</code> which is <code>endSegment()</code> on
* failure.
*/
segment_iterator_t splitAfter(U8* address);
/**
* @brief Get the first segment in the buffer array.
*
* @return Returns the segment if there is one.
*/
segment_iterator_t beginSegment();
/**
* @brief Get the one-past-the-end segment in the buffer array
*
* @return Returns the iterator for an invalid segment location.
*/
segment_iterator_t endSegment();
/**
* @brief Get the segment which holds the given address.
*
* As opposed to some methods, passing a NULL will result in
* returning the end segment.
* @param address An address in the middle of the sought segment.
* @return Returns the iterator for the segment or endSegment() on
* failure.
*/
const_segment_iterator_t getSegment(U8* address) const;
/**
* @brief Get the segment which holds the given address.
*
* As opposed to some methods, passing a NULL will result in
* returning the end segment.
* @param address An address in the middle of the sought segment.
* @return Returns the iterator for the segment or endSegment() on
* failure.
*/
segment_iterator_t getSegment(U8* address);
/**
* @brief Get a segment iterator after address, and a constructed
* segment to represent the next linear block of memory.
*
* This method is a helper by giving you the largest segment
* possible in the out-value param after the address provided. The
* iterator will be useful for iteration, while the segment can be
* used for direct access to memory after address if the return
* values isnot end. Passing in NULL will return beginSegment()
* which may be endSegment(). The segment returned will only be
* zero length if the return value equals end.
* This is really just a helper method, since all the information
* returned could be constructed through other methods.
* @param address An address in the middle of the sought segment.
* @param segment[out] segment to be used for reading or writing
* @return Returns an iterator which contains at least segment or
* endSegment() on failure.
*/
segment_iterator_t constructSegmentAfter(U8* address, LLSegment& segment);
/**
* @brief Make a new segment at the end of buffer array
*
* This method will attempt to create a new and empty segment of
* the specified length. The segment created may be shorter than
* requested.
* @param channel[in] The channel for the newly created segment.
* @param length[in] The requested length of the segment.
* @return Returns an iterator which contains at least segment or
* endSegment() on failure.
*/
segment_iterator_t makeSegment(S32 channel, S32 length);
/**
* @brief Erase the segment if it is in the buffer array.
*
* @param iter An iterator referring to the segment to erase.
* @return Returns true on success.
*/
bool eraseSegment(const segment_iterator_t& iter);
/**
* @brief Lock the mutex if it exists
* This method locks mMutexp to make accessing LLBufferArray thread-safe
*/
void lock();
/**
* @brief Unlock the mutex if it exists
*/
void unlock();
/**
* @brief Return mMutexp
*/
LLMutex* getMutex();
/**
* @brief Set LLBufferArray to be shared across threads or not
* This method is to create mMutexp if is threaded.
* @param threaded Indicates this LLBufferArray instance is shared across threads if true.
*/
void setThreaded(bool threaded);
//@}
protected:
/**
* @brief Optimally put data in buffers, and reutrn segments.
*
* This is an internal function used to create buffers as
* necessary, and sequence the segments appropriately for the
* various ways to copy data from src into this.
* If this method fails, it may actually leak some space inside
* buffers, but I am not too worried about the slim possibility
* that we may have some 'dead' space which will be recovered when
* the buffer (which we will not lose) is deleted. Addressing this
* weakness will make the buffers almost as complex as a general
* memory management system.
* @param channel The channel for this data
* @param src The start of memory for the data to be copied
* @param len The number of bytes of data to copy
* @param segments Out-value for the segments created.
* @return Returns true if the method worked.
*/
bool copyIntoBuffers(
S32 channel,
const U8* src,
S32 len,
std::vector<LLSegment>& segments);
protected:
S32 mNextBaseChannel;
buffer_list_t mBuffers;
segment_list_t mSegments;
LLMutex* mMutexp;
};
#endif // LL_LLBUFFER_H
+344
View File
@@ -0,0 +1,344 @@
/**
* @file llbufferstream.cpp
* @author Phoenix
* @date 2005-10-10
* @brief Implementation of the buffer iostream 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 "llbufferstream.h"
#include "llbuffer.h"
#include "llthread.h"
#include "llmutex.h"
static const S32 DEFAULT_OUTPUT_SEGMENT_SIZE = 1024 * 4;
/*
* LLBufferStreamBuf
*/
LLBufferStreamBuf::LLBufferStreamBuf(
const LLChannelDescriptors& channels,
LLBufferArray* buffer) :
mChannels(channels),
mBuffer(buffer)
{
}
LLBufferStreamBuf::~LLBufferStreamBuf()
{
sync();
}
// virtual
int LLBufferStreamBuf::underflow()
{
//LL_DEBUGS() << "LLBufferStreamBuf::underflow()" << LL_ENDL;
if(!mBuffer)
{
return EOF;
}
LLMutexLock lock(mBuffer->getMutex());
LLBufferArray::segment_iterator_t iter;
LLBufferArray::segment_iterator_t end = mBuffer->endSegment();
U8* last_pos = (U8*)gptr();
LLSegment segment;
if(last_pos)
{
// Back up into a piece of memory we know that we have
// allocated so that calls for the next segment based on
// 'after' will succeed.
--last_pos;
iter = mBuffer->splitAfter(last_pos);
if(iter != end)
{
// We need to clear the read segment just in case we have
// an early exit in the function and never collect the
// next segment. Calling eraseSegment() with the same
// segment twice is just like double deleting -- nothing
// good comes from it.
mBuffer->eraseSegment(iter++);
if(iter != end) segment = (*iter);
}
else
{
// This should never really happen, but somehow, the
// istream is telling the buf that it just finished
// reading memory that is not in the buf. I think this
// would only happen if there were a bug in the c++ stream
// class. Just bail.
// *TODO: can we set the fail bit on the stream somehow?
return EOF;
}
}
else
{
// Get iterator to full segment containing last_pos
// and construct sub-segment starting at last_pos.
// Note: segment may != *it at this point
iter = mBuffer->constructSegmentAfter(last_pos, segment);
}
if(iter == end)
{
return EOF;
}
// Iterate through segments to find a non-empty segment on input channel.
while((!segment.isOnChannel(mChannels.in()) || (segment.size() == 0)))
{
++iter;
if(iter == end)
{
return EOF;
}
segment = *(iter);
}
// set up the stream to read from the next segment.
char* start = (char*)segment.data();
setg(start, start, start + segment.size());
return *gptr();
}
// virtual
int LLBufferStreamBuf::overflow(int c)
{
if(!mBuffer)
{
return EOF;
}
if(EOF == c)
{
// if someone puts an EOF, I suppose we should sync and return
// success.
if(0 == sync())
{
return 1;
}
else
{
return EOF;
}
}
// since we got here, we have a buffer, and we have a character to
// put on it.
LLBufferArray::segment_iterator_t it;
LLMutexLock lock(mBuffer->getMutex());
it = mBuffer->makeSegment(mChannels.out(), DEFAULT_OUTPUT_SEGMENT_SIZE);
if(it != mBuffer->endSegment())
{
char* start = (char*)(*it).data();
(*start) = (char)(c);
setp(start + 1, start + (*it).size());
return c;
}
else
{
return EOF;
}
}
// virtual
int LLBufferStreamBuf::sync()
{
int return_value = -1;
if(!mBuffer)
{
return return_value;
}
// This chunk of code is not necessary because typically, users of
// the stream will read until EOF. Therefore, underflow was called
// and the segment was discarded before the sync() was called in
// the destructor. Theoretically, we could keep some more data
// around and detect the rare case where an istream was deleted
// before reading to the end, but that will only leave behind some
// unavailable but still referenced memory. Also, if another
// istream is constructed, it will re-read that segment, and then
// discard it.
//U8* last_pos = (U8*)gptr();
//if(last_pos)
//{
// // Looks like we read something. Discard what we have read.
// // gptr() actually returns the currrent position, but we call
// // it last_pos because of how it is used in the split call
// // below.
// --last_pos;
// LLBufferArray::segment_iterator_t iter;
// iter = mBuffer->splitAfter(last_pos);
// if(iter != mBuffer->endSegment())
// {
// // We need to clear the read segment just in case we have
// // an early exit in the function and never collect the
// // next segment. Calling eraseSegment() with the same
// // segment twice is just like double deleting -- nothing
// // good comes from it.
// mBuffer->eraseSegment(iter);
// }
//}
// set the put pointer so that we force an overflow on the next
// write.
U8* address = (U8*)pptr();
setp(NULL, NULL);
// *NOTE: I bet we could just --address if address is not NULL.
// Need to think about that.
LLMutexLock lock(mBuffer->getMutex());
address = mBuffer->seek(mChannels.out(), address, -1);
if(address)
{
LLBufferArray::segment_iterator_t it;
it = mBuffer->splitAfter(address);
LLBufferArray::segment_iterator_t end = mBuffer->endSegment();
if(it != end)
{
++it;
if(it != end)
{
mBuffer->eraseSegment(it);
}
return_value = 0;
}
}
else
{
// nothing was put on the buffer, so the sync() is a no-op.
return_value = 0;
}
return return_value;
}
// virtual
#if( LL_WINDOWS || __GNUC__ > 2)
LLBufferStreamBuf::pos_type LLBufferStreamBuf::seekoff(
LLBufferStreamBuf::off_type off,
std::ios::seekdir way,
std::ios::openmode which)
#else
streampos LLBufferStreamBuf::seekoff(
streamoff off,
std::ios::seekdir way,
std::ios::openmode which)
#endif
{
if(!mBuffer
|| ((way == std::ios::beg) && (off < 0))
|| ((way == std::ios::end) && (off > 0)))
{
return -1;
}
U8* address = NULL;
if(which & std::ios::in)
{
U8* base_addr = NULL;
switch(way)
{
case std::ios::end:
base_addr = (U8*)LLBufferArray::npos;
break;
case std::ios::cur:
// get the current get pointer and adjust it for buffer
// array semantics.
base_addr = (U8*)gptr();
break;
case std::ios::beg:
default:
// NULL is fine
break;
}
LLMutexLock lock(mBuffer->getMutex());
address = mBuffer->seek(mChannels.in(), base_addr, (S32)off);
if(address)
{
LLBufferArray::segment_iterator_t iter;
iter = mBuffer->getSegment(address);
char* start = (char*)(*iter).data();
setg(start, (char*)address, start + (*iter).size());
}
else
{
address = (U8*)(-1);
}
}
if(which & std::ios::out)
{
U8* base_addr = NULL;
switch(way)
{
case std::ios::end:
base_addr = (U8*)LLBufferArray::npos;
break;
case std::ios::cur:
// get the current put pointer and adjust it for buffer
// array semantics.
base_addr = (U8*)pptr();
break;
case std::ios::beg:
default:
// NULL is fine
break;
}
LLMutexLock lock(mBuffer->getMutex());
address = mBuffer->seek(mChannels.out(), base_addr, (S32)off);
if(address)
{
LLBufferArray::segment_iterator_t iter;
iter = mBuffer->getSegment(address);
setp((char*)address, (char*)(*iter).data() + (*iter).size());
}
else
{
address = (U8*)(-1);
}
}
#if( LL_WINDOWS || __GNUC__ > 2 )
S32 rv = (S32)(intptr_t)address;
return (pos_type)rv;
#else
return (streampos)address;
#endif
}
/*
* LLBufferStream
*/
LLBufferStream::LLBufferStream(
const LLChannelDescriptors& channels,
LLBufferArray* buffer) :
std::iostream(&mStreamBuf),
mStreamBuf(channels, buffer)
{
}
LLBufferStream::~LLBufferStream()
{
}
+152
View File
@@ -0,0 +1,152 @@
/**
* @file llbufferstream.h
* @author Phoenix
* @date 2005-10-10
* @brief Classes to treat an LLBufferArray as a c++ iostream.
*
* $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_LLBUFFERSTREAM_H
#define LL_LLBUFFERSTREAM_H
#include <iosfwd>
#include <iostream>
#include "llbuffer.h"
/**
* @class LLBufferStreamBuf
* @brief This implements the buffer wrapper for an istream
*
* The buffer array passed in is not owned by the stream buf object.
*/
class LLBufferStreamBuf : public std::streambuf
{
public:
LLBufferStreamBuf(
const LLChannelDescriptors& channels,
LLBufferArray* buffer);
virtual ~LLBufferStreamBuf();
protected:
#if( LL_WINDOWS || __GNUC__ > 2 )
typedef std::streambuf::pos_type pos_type;
typedef std::streambuf::off_type off_type;
#endif
/* @name streambuf vrtual implementations
*/
//@{
/*
* @brief called when we hit the end of input
*
* @return Returns the character at the current position or EOF.
*/
virtual int underflow();
/*
* @brief called when we hit the end of output
*
* @param c The character to store at the current put position
* @return Returns EOF if the function failed. Any other value on success.
*/
virtual int overflow(int c);
/*
* @brief synchronize the buffer
*
* @return Returns 0 on success or -1 on failure.
*/
virtual int sync();
/*
* @brief Seek to an offset position in a stream.
*
* @param off Offset value relative to way paramter
* @param way The seek direction. One of ios::beg, ios::cur, and ios::end.
* @param which Which pointer to modify. One of ios::in, ios::out,
* or both masked together.
* @return Returns the new position or an invalid position on failure.
*/
#if( LL_WINDOWS || __GNUC__ > 2)
virtual pos_type seekoff(
off_type off,
std::ios::seekdir way,
std::ios::openmode which);
#else
virtual streampos seekoff(
streamoff off,
std::ios::seekdir way,
std::ios::openmode which);
#endif
/*
* @brief Get s sequence of characters from the input
*
* @param dst Pointer to a block of memory to accept the characters
* @param length Number of characters to be read
* @return Returns the number of characters read
*/
//virtual streamsize xsgetn(char* dst, streamsize length);
/*
* @brief Write some characters to output
*
* @param src Pointer to a sequence of characters to be output
* @param length Number of characters to be put
* @return Returns the number of characters written
*/
//virtual streamsize xsputn(char* src, streamsize length);
//@}
protected:
// This channels we are working on.
LLChannelDescriptors mChannels;
// The buffer we work on
LLBufferArray* mBuffer;
};
/**
* @class LLBufferStream
* @brief This implements an istream based wrapper around an LLBufferArray.
*
* This class does not own the buffer array, and does not hold a
* shared pointer to it. Since the class itself is fairly ligthweight,
* just make one on the stack when needed and let it fall out of
* scope.
*/
class LLBufferStream : public std::iostream
{
public:
LLBufferStream(
const LLChannelDescriptors& channels,
LLBufferArray* buffer);
~LLBufferStream();
protected:
LLBufferStreamBuf mStreamBuf;
};
#endif // LL_LLBUFFERSTREAM_H
File diff suppressed because it is too large Load Diff
+154
View File
@@ -0,0 +1,154 @@
/**
* @file llcachename.h
* @brief A cache of names from UUIDs.
*
* $LicenseInfo:firstyear=2002&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_LLCACHENAME_H
#define LL_LLCACHENAME_H
#include <boost/bind.hpp>
#include <boost/signals2.hpp>
class LLMessageSystem;
class LLHost;
class LLUUID;
typedef boost::signals2::signal<void (const LLUUID& id,
const std::string& name,
bool is_group)> LLCacheNameSignal;
typedef LLCacheNameSignal::slot_type LLCacheNameCallback;
// Old callback with user data for compatibility
typedef void (*old_callback_t)(const LLUUID&, const std::string&, bool, void*);
// Here's the theory:
// If you request a name that isn't in the cache, it returns "waiting"
// and requests the data. After the data arrives, you get that on
// subsequent calls.
// If the data hasn't been updated in an hour, it requests it again,
// but keeps giving you the old value until new data arrives.
// If you haven't requested the data in an hour, it releases it.
class LLCacheName
{
public:
LLCacheName(LLMessageSystem* msg);
LLCacheName(LLMessageSystem* msg, const LLHost& upstream_host);
~LLCacheName();
// registers the upstream host
// for viewers, this is the currently connected simulator
// for simulators, this is the data server
void setUpstream(const LLHost& upstream_host);
boost::signals2::connection addObserver(const LLCacheNameCallback& callback);
// storing cache on disk; for viewer, in name.cache
bool importFile(std::istream& istr);
void exportFile(std::ostream& ostr);
// If available, copies name ("bobsmith123" or "James Linden") into string
// If not available, copies the string "waiting".
// Returns true if available.
bool getFullName(const LLUUID& id, std::string& full_name);
bool getFirstLastName(const LLUUID& id, std::string& first, std::string& last); // <FS:CR> returns first name, last name
// Reverse lookup of UUID from name
bool getUUID(const std::string& first, const std::string& last, LLUUID& id);
bool getUUID(const std::string& fullname, LLUUID& id);
// IDEVO Temporary code
// Clean up new-style "bobsmith123 Resident" names to "bobsmith123" for display
static std::string buildFullName(const std::string& first, const std::string& last);
// Clean up legacy "bobsmith123 Resident" to "bobsmith123"
// If name does not contain "Resident" returns it unchanged.
static std::string cleanFullName(const std::string& full_name);
// Converts a standard legacy name to a username
// "bobsmith123 Resident" -> "bobsmith"
// "Random Linden" -> "random.linden"
static std::string buildUsername(const std::string& name);
// Converts a complete display name to a legacy name
// if possible, otherwise returns the input
// "Alias (random.linden)" -> "Random Linden"
// "Something random" -> "Something random"
static std::string buildLegacyName(const std::string& name);
// If available, this method copies the group name into the string
// provided. The caller must allocate at least
// DB_GROUP_NAME_BUF_SIZE characters. If not available, this
// method copies the string "waiting". Returns true if available.
bool getGroupName(const LLUUID& id, std::string& group);
// Call the callback with the group or avatar name.
// If the data is currently available, may call the callback immediatly
// otherwise, will request the data, and will call the callback when
// available. There is no garuntee the callback will ever be called.
boost::signals2::connection get(const LLUUID& id, bool is_group, const LLCacheNameCallback& callback);
// NaCl - Sound explorer
bool getIfThere(const LLUUID& id, std::string& fullname, bool& is_group);
// NaCl end
// Convenience method for looking up a group name, so you can
// tell the difference between avatar lookup and group lookup
// in global searches
boost::signals2::connection getGroup(const LLUUID& group_id, const LLCacheNameCallback& callback);
// LEGACY
boost::signals2::connection get(const LLUUID& id, bool is_group, old_callback_t callback, void* user_data);
// This method needs to be called from time to time to send out
// requests.
void processPending();
// Expire entries created more than "secs" seconds ago.
void deleteEntriesOlderThan(S32 secs);
// Debugging
void dump(); // Dumps the contents of the cache
void dumpStats(); // Dumps the sizes of the cache and associated queues.
void clear(); // Deletes all entries from the cache
std::string getDefaultName();
// Returns "Resident", the default last name for SLID-based accounts
// that have no last name.
static std::string getDefaultLastName();
void localizeCacheName(std::string key, std::string value);
private:
std::map<std::string, std::string> mCacheName;
class Impl;
Impl& impl;
};
extern LLCacheName* gCacheName;
#endif
+88
View File
@@ -0,0 +1,88 @@
/**
* @file llchainio.cpp
* @author Phoenix
* @date 2005-08-04
* @brief Implementaiton of the chain factory.
*
* $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 "llchainio.h"
#include "lliopipe.h"
#include "llioutil.h"
/**
* LLDeferredChain
*/
// static
bool LLDeferredChain::addToPump(
LLPumpIO* pump,
F32 in_seconds,
const LLPumpIO::chain_t& deferred_chain,
F32 chain_timeout)
{
if(!pump) return false;
LLPumpIO::chain_t sleep_chain;
sleep_chain.push_back(LLIOPipe::ptr_t(new LLIOSleep(in_seconds)));
sleep_chain.push_back(
LLIOPipe::ptr_t(new LLIOAddChain(deferred_chain, chain_timeout)));
// give it a litle bit of padding.
pump->addChain(sleep_chain, in_seconds + 10.0f);
return true;
}
/**
* LLChainIOFactory
*/
LLChainIOFactory::LLChainIOFactory()
{
}
// virtual
LLChainIOFactory::~LLChainIOFactory()
{
}
#if 0
bool LLChainIOFactory::build(LLIOPipe* in, LLIOPipe* out) const
{
if(!in || !out)
{
return false;
}
LLIOPipe* first = NULL;
LLIOPipe* last = NULL;
if(build_impl(first, last) && first && last)
{
in->connect(first);
last->connect(out);
return true;
}
LLIOPipe::ptr_t foo(first);
LLIOPipe::ptr_t bar(last);
return false;
}
#endif
+135
View File
@@ -0,0 +1,135 @@
/**
* @file llchainio.h
* @author Phoenix
* @date 2005-08-04
* @brief This class declares the interface for constructing io chains.
*
* $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_LLCHAINIO_H
#define LL_LLCHAINIO_H
#include "llpumpio.h"
/**
* @class LLDeferredChain
* @brief This class allows easy addition of a chain which will sleep
* and then process another chain.
*/
class LLDeferredChain
{
public:
/**
* @brief Add a chain to a pump in a finite # of seconds
*
* @prarm pump The pump to work on.
* @prarm in_seconds The number of seconds from now when chain should start.
* @prarm chain The chain to add in in_seconds seconds.
* @prarm chain_timeout timeout for chain on the pump.
* @return Returns true if the operation was queued.
*/
static bool addToPump(
LLPumpIO* pump,
F32 in_seconds,
const LLPumpIO::chain_t& chain,
F32 chain_timeout);
};
/**
* @class LLChainIOFactory
* @brief This class is an abstract base class for building io chains.
*
* This declares an abstract base class for a chain factory. The
* factory is used to connect an input pipe to the first pipe in the
* chain, and an output pipe to the last pipe in the chain. This will
* allow easy construction for buffer based io like services to for
* API centered IO while abstracting the input and output to simple
* data passing.
* To use this class, you should derive a class which implements the
* <code>build</code> method.
*/
class LLChainIOFactory
{
public:
// Constructor
LLChainIOFactory();
// Destructor
virtual ~LLChainIOFactory();
/**
* @brief Build the chian with in as the first and end as the last
*
* The caller of the LLChainIOFactory is responsible for managing
* the memory of the in pipe. All of the chains generated by the
* factory will be ref counted as usual, so the caller will also
* need to break the links in the chain.
* @param chain The chain which will have new pipes appended
* @param context A context for use by this factory if you choose
* @retrun Returns true if the call was successful.
*/
virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const = 0;
protected:
};
/**
* @class LLSimpleIOFactory
* @brief Basic implementation for making a factory that returns a
* 'chain' of one object
*/
template<class Pipe>
class LLSimpleIOFactory : public LLChainIOFactory
{
public:
virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const
{
chain.push_back(LLIOPipe::ptr_t(new Pipe));
return true;
}
};
/**
* @class LLCloneIOFactory
* @brief Implementation for a facory which copies a particular pipe.
*/
template<class Pipe>
class LLCloneIOFactory : public LLChainIOFactory
{
public:
LLCloneIOFactory(Pipe* original) :
mHandle(original),
mOriginal(original) {}
virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const
{
chain.push_back(LLIOPipe::ptr_t(new Pipe(*mOriginal)));
return true;
}
protected:
LLIOPipe::ptr_t mHandle;
Pipe* mOriginal;
};
#endif // LL_LLCHAINIO_H
+56
View File
@@ -0,0 +1,56 @@
/**
* @file llcipher.h
* @brief Abstract base class for encryption ciphers.
*
* $LicenseInfo:firstyear=2003&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 LLCIPHER_H
#define LLCIPHER_H
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLCipher
//
// Abstract base class for a cipher object.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLCipher
{
public:
virtual ~LLCipher() {}
// encrypt src and place result into dst. returns true if
// Returns number of bytes written into dst, or 0 on error.
virtual U32 encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len) = 0;
// decrypt src and place result into dst.
// Returns number of bytes written into dst, or 0 on error.
virtual U32 decrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len) = 0;
// returns the minimum amount of space required to encrypt for a
// unencrypted source buffer of length len.
// *NOTE: This is estimated space and you should check the return value
// of the encrypt function.
virtual U32 requiredEncryptionSpace(U32 src_len) const = 0 ;
};
#endif
File diff suppressed because it is too large Load Diff
+355
View File
@@ -0,0 +1,355 @@
/**
* @file llcircuit.h
* @brief Provides a method for tracking network circuit information
* for the UDP message system
*
* $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$
*/
#ifndef LL_LLCIRCUIT_H
#define LL_LLCIRCUIT_H
#include <map>
#include <vector>
#include "llerror.h"
#include "lltimer.h"
#include "net.h"
#include "llhost.h"
#include "llpacketack.h"
#include "lluuid.h"
#include "llthrottle.h"
//
// Constants
//
const F32 LL_AVERAGED_PING_ALPHA = 0.2f; // relaxation constant on ping running average
const F32Milliseconds LL_AVERAGED_PING_MAX(2000);
const F32Milliseconds LL_AVERAGED_PING_MIN(100); // increased to avoid retransmits when a process is slow
const U32Milliseconds INITIAL_PING_VALUE_MSEC(1000); // initial value for the ping delay, or for ping delay for an unknown circuit
const TPACKETID LL_MAX_OUT_PACKET_ID = 0x01000000;
const int LL_ERR_CIRCUIT_GONE = -23017;
const int LL_ERR_TCP_TIMEOUT = -23016;
// 0 - flags
// [1,4] - packetid
// 5 - data offset (after message name)
const U8 LL_PACKET_ID_SIZE = 6;
const S32 LL_MAX_RESENT_PACKETS_PER_FRAME = 100;
const S32 LL_MAX_ACKED_PACKETS_PER_FRAME = 200;
const F32 LL_COLLECT_ACK_TIME_MAX = 2.f;
//
// Prototypes and Predefines
//
class LLMessageSystem;
class LLEncodedDatagramService;
class LLSD;
//
// Classes
//
class LLCircuitData
{
public:
LLCircuitData(const LLHost &host, TPACKETID in_id,
const F32Seconds circuit_heartbeat_interval, const F32Seconds circuit_timeout);
~LLCircuitData();
S32 resendUnackedPackets(const F64Seconds now);
void clearDuplicateList(TPACKETID oldest_id);
void dumpResendCountAndReset(); // Used for tracking how many resends are being done on a circuit.
// Public because stupid message system callbacks uses it.
void pingTimerStart();
void pingTimerStop(const U8 ping_id);
void ackReliablePacket(TPACKETID packet_num);
// remote computer information
const LLUUID& getRemoteID() const { return mRemoteID; }
const LLUUID& getRemoteSessionID() const { return mRemoteSessionID; }
void setRemoteID(const LLUUID& id) { mRemoteID = id; }
void setRemoteSessionID(const LLUUID& id) { mRemoteSessionID = id; }
void setTrusted(bool t);
// The local end point ID is used when establishing a trusted circuit.
// no matching set function for getLocalEndPointID()
// mLocalEndPointID should only ever be setup in the LLCircuitData constructor
const LLUUID& getLocalEndPointID() const { return mLocalEndPointID; }
U32Milliseconds getPingDelay() const;
S32 getPingsInTransit() const { return mPingsInTransit; }
// ACCESSORS
bool isAlive() const;
bool isBlocked() const;
bool getAllowTimeout() const;
F32Milliseconds getPingDelayAveraged();
F32Milliseconds getPingInTransitTime();
U32 getPacketsIn() const;
S32Bytes getBytesIn() const;
S32Bytes getBytesOut() const;
U32 getPacketsOut() const;
U32 getPacketsLost() const;
TPACKETID getPacketOutID() const;
bool getTrusted() const;
F32 getAgeInSeconds() const;
S32 getUnackedPacketCount() const { return mUnackedPacketCount; }
S32 getUnackedPacketBytes() const { return mUnackedPacketBytes; }
F64Seconds getNextPingSendTime() const { return mNextPingSendTime; }
U32 getLastPacketGap() const { return mLastPacketGap; }
LLHost getHost() const { return mHost; }
F64Seconds getLastPacketInTime() const { return mLastPacketInTime; }
LLThrottleGroup &getThrottleGroup() { return mThrottles; }
class less
{
public:
bool operator()(const LLCircuitData* lhs, const LLCircuitData* rhs) const
{
if (lhs->getNextPingSendTime() < rhs->getNextPingSendTime())
{
return true;
}
else if (lhs->getNextPingSendTime() > rhs->getNextPingSendTime())
{
return false;
}
else return lhs > rhs;
}
};
//
// Debugging stuff (not necessary for operation)
//
void checkPeriodTime(); // Reset per-period counters if necessary.
friend std::ostream& operator<<(std::ostream& s, LLCircuitData &circuit);
void getInfo(LLSD& info) const;
friend class LLCircuit;
friend class LLMessageSystem;
friend class LLEncodedDatagramService;
friend void crash_on_spaceserver_timeout (const LLHost &host, void *); // HACK, so it has access to setAlive() so it can send a final shutdown message.
protected:
TPACKETID nextPacketOutID();
void setPacketInID(TPACKETID id);
void checkPacketInID(TPACKETID id, bool receive_resent);
void setPingDelay(U32Milliseconds ping);
bool checkCircuitTimeout(); // Return false if the circuit is dead and should be cleaned up
void addBytesIn(S32Bytes bytes);
void addBytesOut(S32Bytes bytes);
U8 nextPingID() { mLastPingID++; return mLastPingID; }
bool updateWatchDogTimers(LLMessageSystem *msgsys); // Return false if the circuit is dead and should be cleaned up
void addReliablePacket(S32 mSocket, U8 *buf_ptr, S32 buf_len, LLReliablePacketParams *params);
bool isDuplicateResend(TPACKETID packetnum);
// Call this method when a reliable message comes in - this will
// correctly place the packet in the correct list to be acked
// later. RAack = requested ack
bool collectRAck(TPACKETID packet_num);
void setTimeoutCallback(void (*callback_func)(const LLHost &host, void *user_data), void *user_data);
void setAlive(bool b_alive);
void setAllowTimeout(bool allow);
protected:
// Identification for this circuit.
LLHost mHost;
LLUUID mRemoteID;
LLUUID mRemoteSessionID;
LLThrottleGroup mThrottles;
TPACKETID mWrapID;
// Current packet IDs of incoming/outgoing packets
// Used for packet sequencing/packet loss detection.
TPACKETID mPacketsOutID;
TPACKETID mPacketsInID;
TPACKETID mHighestPacketID;
// Callback and data to run in the case of a circuit timeout.
// Used primarily to try and reconnect to servers if they crash/die.
void (*mTimeoutCallback)(const LLHost &host, void *user_data);
void *mTimeoutUserData;
bool mTrusted; // Is this circuit trusted?
bool mbAllowTimeout; // Machines can "pause" circuits, forcing them not to be dropped
bool mbAlive; // Indicates whether a circuit is "alive", i.e. responded to pings
bool mBlocked; // Blocked is true if the circuit is hosed, i.e. far behind on pings
// Not sure what the difference between this and mLastPingSendTime is
F64Seconds mPingTime; // Time at which a ping was sent.
F64Seconds mLastPingSendTime; // Time we last sent a ping
F64Seconds mLastPingReceivedTime; // Time we last received a ping
F64Seconds mNextPingSendTime; // Time to try and send the next ping
S32 mPingsInTransit; // Number of pings in transit
U8 mLastPingID; // ID of the last ping that we sent out
// Used for determining the resend time for reliable resends.
U32Milliseconds mPingDelay; // raw ping delay
F32Milliseconds mPingDelayAveraged; // averaged ping delay (fast attack/slow decay)
typedef std::map<TPACKETID, U64Microseconds> packet_time_map;
packet_time_map mPotentialLostPackets;
packet_time_map mRecentlyReceivedReliablePackets;
std::vector<TPACKETID> mAcks;
F32 mAckCreationTime; // first ack creation time
typedef std::map<TPACKETID, LLReliablePacket *> reliable_map;
typedef reliable_map::iterator reliable_iter;
reliable_map mUnackedPackets;
reliable_map mFinalRetryPackets;
S32 mUnackedPacketCount;
S32 mUnackedPacketBytes;
F64Seconds mLastPacketInTime; // Time of last packet arrival
LLUUID mLocalEndPointID;
//
// These variables are being used for statistical and debugging purpose ONLY,
// as far as I can tell.
//
U32 mPacketsOut;
U32 mPacketsIn;
S32 mPacketsLost;
S32Bytes mBytesIn,
mBytesOut;
F32Seconds mLastPeriodLength;
S32Bytes mBytesInLastPeriod;
S32Bytes mBytesOutLastPeriod;
S32Bytes mBytesInThisPeriod;
S32Bytes mBytesOutThisPeriod;
F32 mPeakBPSIn; // bits per second, max of all period bps
F32 mPeakBPSOut; // bits per second, max of all period bps
F64Seconds mPeriodTime;
LLTimer mExistenceTimer; // initialized when circuit created, used to track bandwidth numbers
S32 mCurrentResendCount; // Number of resent packets since last spam
U32 mLastPacketGap; // Gap in sequence number of last packet.
const F32Seconds mHeartbeatInterval;
const F32Seconds mHeartbeatTimeout;
// <FS:ND> Throttle to prevent log spam.
F64 mLastPacketLog;
U32 mLogMessagesSkipped;
// </FS:ND>
};
// Actually a singleton class -- the global messagesystem
// has a single LLCircuit member.
class LLCircuit
{
public:
// CREATORS
LLCircuit(const F32Seconds circuit_heartbeat_interval, const F32Seconds circuit_timeout);
~LLCircuit();
// ACCESSORS
LLCircuitData* findCircuit(const LLHost& host) const;
bool isCircuitAlive(const LLHost& host) const;
// MANIPULATORS
LLCircuitData *addCircuitData(const LLHost &host, TPACKETID in_id);
void removeCircuitData(const LLHost &host);
void updateWatchDogTimers(LLMessageSystem *msgsys);
void resendUnackedPackets(S32& unacked_list_length, S32& unacked_list_size);
// this method is called during the message system processAcks()
// to send out any acks that did not get sent already.
void sendAcks(F32 collect_time);
friend std::ostream& operator<<(std::ostream& s, LLCircuit &circuit);
void getInfo(LLSD& info) const;
void dumpResends();
typedef std::map<LLHost, LLCircuitData*> circuit_data_map;
/**
* @brief This method gets an iterator range starting after key in
* the circuit data map.
*
* @param key The the host before first.
* @param first[out] The first matching value after key. This
* value will equal end if there are no entries.
* @param end[out] The end of the iteration sequence.
*/
void getCircuitRange(
const LLHost& key,
circuit_data_map::iterator& first,
circuit_data_map::iterator& end);
// Lists that optimize how many circuits we need to traverse a frame
// HACK - this should become protected eventually, but stupid !@$@# message system/circuit classes are jumbling things up.
circuit_data_map mUnackedCircuitMap; // Map of circuits with unacked data
circuit_data_map mSendAckMap; // Map of circuits which need to send acks
protected:
circuit_data_map mCircuitData;
typedef std::set<LLCircuitData *, LLCircuitData::less> ping_set_t; // Circuits sorted by next ping time
ping_set_t mPingSet;
// This variable points to the last circuit data we found to
// optimize the many, many times we call findCircuit. This may be
// set in otherwise const methods, so it is declared mutable.
mutable LLCircuitData* mLastCircuit;
private:
const F32Seconds mHeartbeatInterval;
const F32Seconds mHeartbeatTimeout;
};
#endif
+84
View File
@@ -0,0 +1,84 @@
/**
* @file llclassifiedflags.cpp
* @brief
*
* $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
* 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$
*/
//*****************************************************************************
// llclassifiedflags.cpp
//
// Some exported symbols and functions for dealing with classified flags.
//
// Copyright 2005, Linden Research, Inc
//*****************************************************************************
#include "linden_common.h"
#include "llclassifiedflags.h"
ClassifiedFlags pack_classified_flags_request(bool auto_renew, bool inc_pg, bool inc_mature, bool inc_adult)
{
U8 rv = 0;
if(inc_pg) rv |= CLASSIFIED_QUERY_INC_PG;
if(inc_mature) rv |= CLASSIFIED_QUERY_INC_MATURE;
if (inc_pg && !inc_mature) rv |= CLASSIFIED_FLAG_MATURE;
if(inc_adult) rv |= CLASSIFIED_QUERY_INC_ADULT;
if(auto_renew) rv |= CLASSIFIED_FLAG_AUTO_RENEW;
return rv;
}
ClassifiedFlags pack_classified_flags(bool auto_renew, bool inc_pg, bool inc_mature, bool inc_adult)
{
U8 rv = 0;
if(inc_pg) rv |= CLASSIFIED_QUERY_INC_PG;
if(inc_mature)
{
rv |= CLASSIFIED_QUERY_INC_MATURE;
rv |= CLASSIFIED_FLAG_MATURE;
}
if(inc_adult) rv |= CLASSIFIED_QUERY_INC_ADULT;
if(auto_renew) rv |= CLASSIFIED_FLAG_AUTO_RENEW;
return rv;
}
bool is_cf_mature(ClassifiedFlags flags)
{
return ((flags & CLASSIFIED_FLAG_MATURE) != 0) || ((flags & CLASSIFIED_QUERY_INC_MATURE) != 0);
}
// Deprecated, but leaving commented out because someday we might
// want to let users enable/disable classifieds. JC
//bool is_cf_enabled(ClassifiedFlags flags)
//{
// return ((flags & CLASSIFIED_FLAG_ENABLED) == CLASSIFIED_FLAG_ENABLED);
//}
bool is_cf_update_time(ClassifiedFlags flags)
{
return ((flags & CLASSIFIED_FLAG_UPDATE_TIME) != 0);
}
bool is_cf_auto_renew(ClassifiedFlags flags)
{
return ((flags & CLASSIFIED_FLAG_AUTO_RENEW) != 0);
}
+62
View File
@@ -0,0 +1,62 @@
/**
* @file llclassifiedflags.h
* @brief Flags used in the classifieds.
*
* $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_LLCLASSIFIEDFLAGS_H
#define LL_LLCLASSIFIEDFLAGS_H
typedef U8 ClassifiedFlags;
const U8 CLASSIFIED_FLAG_NONE = 1 << 0;
const U8 CLASSIFIED_FLAG_MATURE = 1 << 1;
//const U8 CLASSIFIED_FLAG_ENABLED = 1 << 2; // see llclassifiedflags.cpp
//const U8 CLASSIFIED_FLAG_HAS_PRICE= 1 << 3; // deprecated
const U8 CLASSIFIED_FLAG_UPDATE_TIME= 1 << 4;
const U8 CLASSIFIED_FLAG_AUTO_RENEW = 1 << 5;
const U8 CLASSIFIED_QUERY_FILTER_MATURE = 1 << 1;
//const U8 CLASSIFIED_QUERY_FILTER_ENABLED = 1 << 2;
//const U8 CLASSIFIED_QUERY_FILTER_PRICE = 1 << 3;
// These are new with Adult-enabled viewers (1.23 and later)
const U8 CLASSIFIED_QUERY_INC_PG = 1 << 2;
const U8 CLASSIFIED_QUERY_INC_MATURE = 1 << 3;
const U8 CLASSIFIED_QUERY_INC_ADULT = 1 << 6;
const U8 CLASSIFIED_QUERY_INC_NEW_VIEWER = (CLASSIFIED_QUERY_INC_PG | CLASSIFIED_QUERY_INC_MATURE | CLASSIFIED_QUERY_INC_ADULT);
const S32 MAX_CLASSIFIEDS = 100;
// This function is used in AO viewers to pack old query flags into the request
// so that they can talk to old dataservers properly. When the AO servers are deployed on agni
// we can revert back to ClassifiedFlags pack_classified_flags and get rider of this one.
ClassifiedFlags pack_classified_flags_request(bool auto_renew, bool is_pg, bool is_mature, bool is_adult);
ClassifiedFlags pack_classified_flags(bool auto_renew, bool is_pg, bool is_mature, bool is_adult);
bool is_cf_mature(ClassifiedFlags flags);
//bool is_cf_enabled(ClassifiedFlags flags);
bool is_cf_update_time(ClassifiedFlags flags);
bool is_cf_auto_renew(ClassifiedFlags flags);
#endif
+487
View File
@@ -0,0 +1,487 @@
/**
* @file LLCoprocedurePool.cpp
* @author Rider Linden
* @brief Singleton class for managing asset uploads to the sim.
*
* $LicenseInfo:firstyear=2015&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2015, 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 "llwin32headers.h"
#include "linden_common.h"
#include "llcoproceduremanager.h"
#include <chrono>
#include <boost/fiber/buffered_channel.hpp>
#include "llexception.h"
#include "stringize.h"
//=========================================================================
// Map of pool sizes for known pools
static const std::map<std::string, U32> DefaultPoolSizes{
{std::string("Upload"), 1},
{std::string("AIS"), 1},
// *TODO: Rider for the moment keep AIS calls serialized otherwise the COF will tend to get out of sync.
};
static const U32 DEFAULT_POOL_SIZE = 5;
// SL-14399: When we teleport to a brand-new simulator, the coprocedure queue
// gets absolutely slammed with fetch requests. Make this queue effectively
// unlimited.
const U32 LLCoprocedureManager::DEFAULT_QUEUE_SIZE = 1024*1024;
//=========================================================================
class LLCoprocedurePool: private boost::noncopyable
{
public:
typedef LLCoprocedureManager::CoProcedure_t CoProcedure_t;
LLCoprocedurePool(const std::string &name, size_t size);
~LLCoprocedurePool();
/// Places the coprocedure on the queue for processing.
///
/// @param name Is used for debugging and should identify this coroutine.
/// @param proc Is a bound function to be executed
///
/// @return This method returns a UUID that can be used later to cancel execution.
LLUUID enqueueCoprocedure(const std::string &name, CoProcedure_t proc);
/// Returns the number of coprocedures in the queue awaiting processing.
///
inline size_t countPending() const
{
return mPending;
}
/// Returns the number of coprocedures actively being processed.
///
inline size_t countActive() const
{
return mActiveCoprocsCount;
}
/// Returns the total number of coprocedures either queued or in active processing.
///
inline S32 count() const
{
return static_cast<S32>(countPending() + countActive());
}
void close();
private:
struct QueuedCoproc
{
typedef std::shared_ptr<QueuedCoproc> ptr_t;
QueuedCoproc(const std::string &name, const LLUUID &id, CoProcedure_t proc) :
mName(name),
mId(id),
mProc(proc)
{}
std::string mName;
LLUUID mId;
CoProcedure_t mProc;
};
// we use a buffered_channel here rather than unbuffered_channel since we want to be able to
// push values without blocking,even if there's currently no one calling a pop operation (due to
// fiber running right now)
typedef boost::fibers::buffered_channel<QueuedCoproc::ptr_t> CoprocQueue_t;
// Use shared_ptr to control the lifespan of our CoprocQueue_t instance
// because the consuming coroutine might outlive this LLCoprocedurePool
// instance.
typedef std::shared_ptr<CoprocQueue_t> CoprocQueuePtr;
std::string mPoolName;
size_t mPoolSize, mActiveCoprocsCount, mPending;
CoprocQueuePtr mPendingCoprocs;
LLTempBoundListener mStatusListener;
typedef std::map<std::string, LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t> CoroAdapterMap_t;
LLCore::HttpRequest::policy_t mHTTPPolicy;
CoroAdapterMap_t mCoroMapping;
void coprocedureInvokerCoro(CoprocQueuePtr pendingCoprocs,
LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter);
};
//=========================================================================
LLCoprocedureManager::LLCoprocedureManager()
{
}
LLCoprocedureManager::~LLCoprocedureManager()
{
close();
}
void LLCoprocedureManager::initializePool(const std::string &poolName)
{
poolMap_t::iterator it = mPoolMap.find(poolName);
if (it != mPoolMap.end())
{
// Pools are not supposed to be initialized twice
// Todo: ideally restrict init to STATE_FIRST
LL_WARNS("CoProcMgr") << "Pool is already present " << poolName << LL_ENDL;
return;
}
// Attempt to look up a pool size in the configuration. If found use that
std::string keyName = "PoolSize" + poolName;
int size = 0;
LL_ERRS_IF(poolName.empty(), "CoprocedureManager") << "Poolname must not be empty" << LL_ENDL;
LL_INFOS("CoprocedureManager") << "Initializing pool " << poolName << LL_ENDL;
if (mPropertyQueryFn)
{
size = mPropertyQueryFn(keyName);
}
if (size == 0)
{
// if not found grab the know default... if there is no known
// default use a reasonable number like 5.
auto it = DefaultPoolSizes.find(poolName);
size = (it != DefaultPoolSizes.end()) ? it->second : DEFAULT_POOL_SIZE;
if (mPropertyDefineFn)
{
mPropertyDefineFn(keyName, size, "Coroutine Pool size for " + poolName);
}
LL_WARNS("CoProcMgr") << "LLCoprocedureManager: No setting for \"" << keyName << "\" setting pool size to default of " << size << LL_ENDL;
}
poolPtr_t pool(new LLCoprocedurePool(poolName, size));
LL_ERRS_IF(!pool, "CoprocedureManager") << "Unable to create pool named \"" << poolName << "\" FATAL!" << LL_ENDL;
bool inserted = mPoolMap.emplace(poolName, pool).second;
LL_ERRS_IF(!inserted, "CoprocedureManager") << "Unable to add pool named \"" << poolName << "\" to map. FATAL!" << LL_ENDL;
}
//-------------------------------------------------------------------------
LLUUID LLCoprocedureManager::enqueueCoprocedure(const std::string &pool, const std::string &name, CoProcedure_t proc)
{
// Attempt to find the pool and enqueue the procedure. If the pool does
// not exist, create it.
poolMap_t::iterator it = mPoolMap.find(pool);
if (it == mPoolMap.end())
{
// initializing pools in enqueueCoprocedure is not thread safe,
// at the moment pools need to be initialized manually
LL_ERRS() << "Uninitialized pool " << pool << LL_ENDL;
}
poolPtr_t targetPool = it->second;
return targetPool->enqueueCoprocedure(name, proc);
}
void LLCoprocedureManager::setPropertyMethods(SettingQuery_t queryfn, SettingUpdate_t updatefn)
{
// functions to discover and store the pool sizes
// Might be a better idea to make an initializePool(name, size) to init everything externally
mPropertyQueryFn = queryfn;
mPropertyDefineFn = updatefn;
initializePool("Upload");
initializePool("AIS"); // it might be better to have some kind of on-demand initialization for AIS
// "ExpCache" pool gets initialized in LLExperienceCache
// asset storage pool gets initialized in LLViewerAssetStorage
}
//-------------------------------------------------------------------------
size_t LLCoprocedureManager::countPending() const
{
size_t count = 0;
for (const auto& pair : mPoolMap)
{
count += pair.second->countPending();
}
return count;
}
size_t LLCoprocedureManager::countPending(const std::string &pool) const
{
poolMap_t::const_iterator it = mPoolMap.find(pool);
if (it == mPoolMap.end())
return 0;
return it->second->countPending();
}
size_t LLCoprocedureManager::countActive() const
{
size_t count = 0;
for (poolMap_t::const_iterator it = mPoolMap.begin(); it != mPoolMap.end(); ++it)
{
count += it->second->countActive();
}
return count;
}
size_t LLCoprocedureManager::countActive(const std::string &pool) const
{
poolMap_t::const_iterator it = mPoolMap.find(pool);
if (it == mPoolMap.end())
{
return 0;
}
return it->second->countActive();
}
size_t LLCoprocedureManager::count() const
{
size_t count = 0;
for (const auto& pair : mPoolMap)
{
count += pair.second->count();
}
return count;
}
size_t LLCoprocedureManager::count(const std::string &pool) const
{
poolMap_t::const_iterator it = mPoolMap.find(pool);
if (it == mPoolMap.end())
return 0;
return it->second->count();
}
void LLCoprocedureManager::close()
{
for(auto & poolEntry : mPoolMap)
{
poolEntry.second->close();
}
}
void LLCoprocedureManager::close(const std::string &pool)
{
poolMap_t::iterator it = mPoolMap.find(pool);
if (it != mPoolMap.end())
{
it->second->close();
}
}
//=========================================================================
LLCoprocedurePool::LLCoprocedurePool(const std::string &poolName, size_t size):
mPoolName(poolName),
mPoolSize(size),
mActiveCoprocsCount(0),
mPending(0),
mHTTPPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID),
mCoroMapping()
{
try
{
mPendingCoprocs = std::make_shared<CoprocQueue_t>(LLCoprocedureManager::DEFAULT_QUEUE_SIZE);
// store in our LLTempBoundListener so that when the LLCoprocedurePool is
// destroyed, we implicitly disconnect from this LLEventPump
// Monitores application status
mStatusListener = LLEventPumps::instance().obtain("LLApp").listen(
poolName + "_pool", // Make sure it won't repeat names from lleventcoro
[pendingCoprocs = mPendingCoprocs, poolName](const LLSD& status)
{
auto& statsd = status["status"];
if (statsd.asString() != "running")
{
LL_INFOS("CoProcMgr") << "Pool " << poolName
<< " closing queue because status " << statsd
<< LL_ENDL;
// This should ensure that all waiting coprocedures in this
// pool will wake up and terminate.
pendingCoprocs->close();
}
return false;
});
}
catch (const LLEventPump::DupListenerName &)
{
// This shounldn't be possible since LLCoprocedurePool is supposed to have unique names,
// yet it somehow did happen, as result pools got '_pool' suffix and this catch.
//
// If this somehow happens again it is better to crash later on shutdown due to pump
// not stopping coroutine and see warning in logs than on startup or during login.
LL_WARNS("CoProcMgr") << "Attempted to register dupplicate listener name: " << poolName
<< "_pool. Failed to start listener." << LL_ENDL;
llassert(0); // Fix Me! Ignoring missing listener!
}
catch (std::bad_alloc&)
{
LLError::LLUserWarningMsg::showOutOfMemory();
LL_ERRS("CoProcMgr") << "Bad memory allocation in LLCoprocedurePool::LLCoprocedurePool!" << LL_ENDL;
}
for (size_t count = 0; count < mPoolSize; ++count)
{
LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter( mPoolName + "Adapter", mHTTPPolicy));
std::string pooledCoro = LLCoros::instance().launch(
"LLCoprocedurePool("+mPoolName+")::coprocedureInvokerCoro",
boost::bind(&LLCoprocedurePool::coprocedureInvokerCoro, this,
mPendingCoprocs, httpAdapter));
mCoroMapping.insert(CoroAdapterMap_t::value_type(pooledCoro, httpAdapter));
}
LL_INFOS("CoProcMgr") << "Created coprocedure pool named \"" << mPoolName << "\" with " << size << " items, queue max " << LLCoprocedureManager::DEFAULT_QUEUE_SIZE << LL_ENDL;
}
LLCoprocedurePool::~LLCoprocedurePool()
{
}
//-------------------------------------------------------------------------
LLUUID LLCoprocedurePool::enqueueCoprocedure(const std::string &name, LLCoprocedurePool::CoProcedure_t proc)
{
LLUUID id(LLUUID::generateNewID());
if (mPoolName == "AIS")
{
// Fetch is going to be spammy.
LL_DEBUGS("CoProcMgr", "Inventory") << "Coprocedure(" << name << ") enqueuing with id=" << id.asString() << " in pool \"" << mPoolName
<< "\" at "
<< mPending << LL_ENDL;
if (mPending >= (LLCoprocedureManager::DEFAULT_QUEUE_SIZE - 1))
{
// If it's all used up (not supposed to happen,
// fetched should cap it), we are going to crash
LL_WARNS("CoProcMgr", "Inventory") << "About to run out of queue space for Coprocedure(" << name
<< ") enqueuing with id=" << id.asString() << " Already pending:" << mPending << LL_ENDL;
}
}
else
{
LL_DEBUGS("CoProcMgr") << "Coprocedure(" << name << ") enqueuing with id=" << id.asString() << " in pool \"" << mPoolName << "\" at "
<< mPending << LL_ENDL;
}
auto pushed = mPendingCoprocs->try_push(std::make_shared<QueuedCoproc>(name, id, proc));
if (pushed == boost::fibers::channel_op_status::success)
{
++mPending;
return id;
}
// Here we didn't succeed in pushing. Shutdown could be the reason.
if (pushed == boost::fibers::channel_op_status::closed)
{
LL_WARNS("CoProcMgr") << "Discarding coprocedure '" << name << "' because shutdown" << LL_ENDL;
return {};
}
// The queue should never fill up.
LL_ERRS("CoProcMgr") << "Enqueue into '" << name << "' failed (" << unsigned(pushed) << "; pending: " << mPending <<")" << LL_ENDL;
return {}; // never executed, pacify the compiler
}
//-------------------------------------------------------------------------
void LLCoprocedurePool::coprocedureInvokerCoro(
CoprocQueuePtr pendingCoprocs,
LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter)
{
for (;;)
{
// It is VERY IMPORTANT that we instantiate a new ptr_t just before
// the pop_wait_for() call below. When this ptr_t was declared at
// function scope (outside the for loop), NickyD correctly diagnosed a
// mysterious hang condition due to:
// - the second time through the loop, the ptr_t held the last pointer
// to the previous QueuedCoproc, which indirectly held the last
// LLPointer to an LLInventoryCallback instance
// - while holding the lock on pendingCoprocs, pop_wait_for() assigned
// the popped value to the ptr_t variable
// - assignment destroyed the previous value of that variable, which
// indirectly destroyed the LLInventoryCallback
// - whose destructor called ~LLRequestServerAppearanceUpdateOnDestroy()
// - which called LLAppearanceMgr::requestServerAppearanceUpdate()
// - which called enqueueCoprocedure()
// - which tried to acquire the lock on pendingCoprocs... alas.
// Using a fresh, clean ptr_t ensures that no previous value is
// destroyed during pop_wait_for().
QueuedCoproc::ptr_t coproc;
boost::fibers::channel_op_status status;
{
LLCoros::TempStatus st("waiting for work for 10s");
status = pendingCoprocs->pop_wait_for(coproc, std::chrono::seconds(10));
}
if (status == boost::fibers::channel_op_status::closed)
{
break;
}
if(status == boost::fibers::channel_op_status::timeout)
{
LL_DEBUGS_ONCE("CoProcMgr") << "pool '" << mPoolName << "' waiting." << LL_ENDL;
continue;
}
// we actually popped an item
--mPending;
mActiveCoprocsCount++;
LL_DEBUGS("CoProcMgr") << "Dequeued and invoking coprocedure(" << coproc->mName << ") with id=" << coproc->mId.asString() << " in pool \"" << mPoolName << "\" (" << mPending << " left)" << LL_ENDL;
try
{
coproc->mProc(httpAdapter, coproc->mId);
}
catch (const LLCoros::Stop &e)
{
LL_INFOS("LLCoros") << "coprocedureInvokerCoro terminating because "
<< e.what() << LL_ENDL;
throw; // let toplevel handle this as LLContinueError
}
catch (...)
{
LOG_UNHANDLED_EXCEPTION(STRINGIZE("Coprocedure('" << coproc->mName
<< "', id=" << coproc->mId.asString()
<< ") in pool '" << mPoolName << "'"));
// must NOT omit this or we deplete the pool
mActiveCoprocsCount--;
continue;
}
// Nicky: This is super spammy. Consider using LL_DEBUGS here?
LL_DEBUGS("CoProcMgr") << "Finished coprocedure(" << coproc->mName << ")" << " in pool \"" << mPoolName << "\"" << LL_ENDL;
mActiveCoprocsCount--;
}
}
void LLCoprocedurePool::close()
{
mPendingCoprocs->close();
}
+98
View File
@@ -0,0 +1,98 @@
/**
* @file llcoproceduremanager.h
* @author Rider Linden
* @brief Singleton class for managing asset uploads to the sim.
*
* $LicenseInfo:firstyear=2015&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2015, 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_COPROCEDURE_MANAGER_H
#define LL_COPROCEDURE_MANAGER_H
#include "lleventcoro.h"
#include "llcoros.h"
#include "llcorehttputil.h"
#include "lluuid.h"
class LLCoprocedurePool;
class LLCoprocedureManager : public LLSingleton < LLCoprocedureManager >
{
LLSINGLETON(LLCoprocedureManager);
virtual ~LLCoprocedureManager();
public:
typedef boost::function<U32(const std::string &)> SettingQuery_t;
typedef boost::function<void(const std::string &, U32, const std::string &)> SettingUpdate_t;
typedef boost::function<void(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &, const LLUUID &id)> CoProcedure_t;
/// Places the coprocedure on the queue for processing.
///
/// @param name Is used for debugging and should identify this coroutine.
/// @param proc Is a bound function to be executed
///
/// @return This method returns a UUID that can be used later to cancel execution.
LLUUID enqueueCoprocedure(const std::string &pool, const std::string &name, CoProcedure_t proc);
/// Cancel a coprocedure. If the coprocedure is already being actively executed
/// this method calls cancelYieldingOperation() on the associated HttpAdapter
/// If it has not yet been dequeued it is simply removed from the queue.
//void cancelCoprocedure(const LLUUID &id);
void setPropertyMethods(SettingQuery_t queryfn, SettingUpdate_t updatefn);
/// Returns the number of coprocedures in the queue awaiting processing.
///
size_t countPending() const;
size_t countPending(const std::string &pool) const;
/// Returns the number of coprocedures actively being processed.
///
size_t countActive() const;
size_t countActive(const std::string &pool) const;
/// Returns the total number of coprocedures either queued or in active processing.
///
size_t count() const;
size_t count(const std::string &pool) const;
void close();
void close(const std::string &pool);
void initializePool(const std::string &poolName);
private:
typedef std::shared_ptr<LLCoprocedurePool> poolPtr_t;
typedef std::map<std::string, poolPtr_t> poolMap_t;
poolMap_t mPoolMap;
SettingQuery_t mPropertyQueryFn;
SettingUpdate_t mPropertyDefineFn;
public:
static const U32 DEFAULT_QUEUE_SIZE;
};
#endif
File diff suppressed because it is too large Load Diff
+680
View File
@@ -0,0 +1,680 @@
/**
* @file llcorehttputil.h
* @date 2014-08-25
* @brief Adapter and utility classes expanding the llcorehttp interfaces.
*
* $LicenseInfo:firstyear=2014&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2014, 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_LLCOREHTTPUTIL_H
#define LL_LLCOREHTTPUTIL_H
#include <string>
#include "httpcommon.h"
#include "httprequest.h"
#include "httpresponse.h"
#include "httpheaders.h"
#include "httpoptions.h"
#include "httphandler.h"
#include "llhttpconstants.h" // *TODO: move to llcorehttp
#include "bufferarray.h"
#include "bufferstream.h"
#include "llsd.h"
#include "llevents.h"
#include "llcoros.h"
#include "lleventcoro.h"
#include "llassettype.h"
#include "lluuid.h"
///
/// The base llcorehttp library implements many HTTP idioms
/// used in the viewer but not all. That library intentionally
/// avoids the use of LLSD and its conventions which aren't
/// universally applicable. This module, using namespace
/// LLCoreHttpUtil, provides the additional helper functions
/// that support idiomatic LLSD transport via the newer
/// llcorehttp library.
///
namespace LLCoreHttpUtil
{
/// Allow access to to the property settings methods.
typedef boost::function<bool(const std::string &)> BoolSettingQuery_t;
typedef boost::function<void(const std::string &, bool, const std::string &)> BoolSettingUpdate_t;
void setPropertyMethods(BoolSettingQuery_t queryfn, BoolSettingUpdate_t updatefn);
extern const F32 HTTP_REQUEST_EXPIRY_SECS;
/// Attempt to convert a response object's contents to LLSD.
/// It is expected that the response body will be of non-zero
/// length on input but basic checks will be performed and
/// and error (false status) returned if there is no data.
/// If there is data but it cannot be successfully parsed,
/// an error is also returned. If successfully parsed,
/// the output LLSD object, out_llsd, is written with the
/// result and true is returned.
///
/// @arg response Response object as returned in
/// in an HttpHandler onCompleted() callback.
/// @arg log If true, LLSD parser will emit errors
/// as LL_INFOS-level messages as it parses.
/// Otherwise, it *should* be a quiet parse.
/// @arg out_llsd Output LLSD object written only upon
/// successful parse of the response object.
///
/// @return Returns true (and writes to out_llsd) if
/// parse was successful. False otherwise.
///
bool responseToLLSD(LLCore::HttpResponse * response,
bool log,
LLSD & out_llsd);
/// Create a std::string representation of a response object
/// suitable for logging. Mainly intended for logging of
/// failures and debug information. This won't be fast,
/// just adequate.
std::string responseToString(LLCore::HttpResponse * response);
/// Issue a standard HttpRequest::requestPost() call but using
/// and LLSD object as the request body. Conventions are the
/// same as with that method. Caller is expected to provide
/// an HttpHeaders object with a correct 'Content-Type:' header.
/// One will not be provided by this call. You might look after
/// the 'Accept:' header as well.
///
/// @return If request is successfully issued, the
/// HttpHandle representing the request.
/// On error, LLCORE_HTTP_HANDLE_INVALID
/// is returned and caller can fetch detailed
/// status with the getStatus() method on the
/// request object. In case of error, no
/// request is queued and caller may need to
/// perform additional cleanup such as freeing
/// a now-useless HttpHandler object.
///
LLCore::HttpHandle requestPostWithLLSD(LLCore::HttpRequest * request,
LLCore::HttpRequest::policy_t policy_id,
const std::string & url,
const LLSD & body,
const LLCore::HttpOptions::ptr_t &options,
const LLCore::HttpHeaders::ptr_t &headers,
const LLCore::HttpHandler::ptr_t &handler);
inline LLCore::HttpHandle requestPostWithLLSD(LLCore::HttpRequest::ptr_t & request,
LLCore::HttpRequest::policy_t policy_id,
const std::string & url,
const LLSD & body,
const LLCore::HttpOptions::ptr_t & options,
const LLCore::HttpHeaders::ptr_t & headers,
const LLCore::HttpHandler::ptr_t & handler)
{
return requestPostWithLLSD(request.get(), policy_id,
url, body, options, headers, handler);
}
inline LLCore::HttpHandle requestPostWithLLSD(LLCore::HttpRequest::ptr_t & request,
LLCore::HttpRequest::policy_t policy_id,
const std::string & url,
const LLSD & body,
const LLCore::HttpHandler::ptr_t &handler)
{
LLCore::HttpOptions::ptr_t options;
LLCore::HttpHeaders::ptr_t headers;
return requestPostWithLLSD(request.get(), policy_id,
url, body, options, headers, handler);
}
/// Issue a standard HttpRequest::requestPut() call but using
/// and LLSD object as the request body. Conventions are the
/// same as with that method. Caller is expected to provide
/// an HttpHeaders object with a correct 'Content-Type:' header.
/// One will not be provided by this call.
///
/// @return If request is successfully issued, the
/// HttpHandle representing the request.
/// On error, LLCORE_HTTP_HANDLE_INVALID
/// is returned and caller can fetch detailed
/// status with the getStatus() method on the
/// request object. In case of error, no
/// request is queued and caller may need to
/// perform additional cleanup such as freeing
/// a now-useless HttpHandler object.
///
LLCore::HttpHandle requestPutWithLLSD(LLCore::HttpRequest * request,
LLCore::HttpRequest::policy_t policy_id,
const std::string & url,
const LLSD & body,
const LLCore::HttpOptions::ptr_t &options,
const LLCore::HttpHeaders::ptr_t &headers,
const LLCore::HttpHandler::ptr_t &handler);
inline LLCore::HttpHandle requestPutWithLLSD(LLCore::HttpRequest::ptr_t & request,
LLCore::HttpRequest::policy_t policy_id,
const std::string & url,
const LLSD & body,
const LLCore::HttpOptions::ptr_t & options,
const LLCore::HttpHeaders::ptr_t & headers,
LLCore::HttpHandler::ptr_t handler)
{
return requestPutWithLLSD(request.get(), policy_id,
url, body, options, headers, handler);
}
inline LLCore::HttpHandle requestPutWithLLSD(LLCore::HttpRequest::ptr_t & request,
LLCore::HttpRequest::policy_t policy_id,
const std::string & url,
const LLSD & body,
LLCore::HttpHandler::ptr_t handler)
{
LLCore::HttpOptions::ptr_t options;
LLCore::HttpHeaders::ptr_t headers;
return requestPutWithLLSD(request.get(), policy_id,
url, body, options, headers, handler);
}
/// Issue a standard HttpRequest::requestPatch() call but using
/// and LLSD object as the request body. Conventions are the
/// same as with that method. Caller is expected to provide
/// an HttpHeaders object with a correct 'Content-Type:' header.
/// One will not be provided by this call.
///
/// @return If request is successfully issued, the
/// HttpHandle representing the request.
/// On error, LLCORE_HTTP_HANDLE_INVALID
/// is returned and caller can fetch detailed
/// status with the getStatus() method on the
/// request object. In case of error, no
/// request is queued and caller may need to
/// perform additional cleanup such as freeing
/// a now-useless HttpHandler object.
///
LLCore::HttpHandle requestPatchWithLLSD(LLCore::HttpRequest * request,
LLCore::HttpRequest::policy_t policy_id,
const std::string & url,
const LLSD & body,
const LLCore::HttpOptions::ptr_t &options,
const LLCore::HttpHeaders::ptr_t &headers,
const LLCore::HttpHandler::ptr_t &handler);
inline LLCore::HttpHandle requestPatchWithLLSD(LLCore::HttpRequest::ptr_t & request,
LLCore::HttpRequest::policy_t policy_id,
const std::string & url,
const LLSD & body,
const LLCore::HttpOptions::ptr_t & options,
const LLCore::HttpHeaders::ptr_t & headers,
const LLCore::HttpHandler::ptr_t & handler)
{
return requestPatchWithLLSD(request.get(), policy_id,
url, body, options, headers, handler);
}
inline LLCore::HttpHandle requestPatchWithLLSD(LLCore::HttpRequest::ptr_t & request,
LLCore::HttpRequest::policy_t policy_id,
const std::string & url,
const LLSD & body,
const LLCore::HttpHandler::ptr_t &handler)
{
LLCore::HttpOptions::ptr_t options;
LLCore::HttpHeaders::ptr_t headers;
return requestPatchWithLLSD(request.get(), policy_id,
url, body, options, headers, handler);
}
//=========================================================================
/// The HttpCoroHandler is a specialization of the LLCore::HttpHandler for
/// interacting with coroutines. When the request is completed the response
/// will be posted onto the supplied Event Pump.
///
/// The LLSD posted back to the coroutine will have the following additions:
/// llsd["http_result"] -+- ["message"] - An error message returned from the HTTP status
/// +- ["status"] - The status code associated with the HTTP call
/// +- ["success"] - Success of failure of the HTTP call and LLSD parsing.
/// +- ["type"] - The LLCore::HttpStatus type associted with the HTTP call
/// +- ["url"] - The URL used to make the call.
/// +- ["headers"] - A map of name name value pairs with the HTTP headers.
///
class HttpCoroHandler : public LLCore::HttpHandler
{
public:
typedef std::shared_ptr<HttpCoroHandler> ptr_t;
typedef std::weak_ptr<HttpCoroHandler> wptr_t;
HttpCoroHandler(LLEventStream &reply);
static void writeStatusCodes(LLCore::HttpStatus status, const std::string &url, LLSD &result);
virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response);
inline LLEventStream &getReplyPump()
{
return mReplyPump;
}
protected:
/// this method may modify the status value
virtual LLSD handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status) = 0;
virtual LLSD parseBody(LLCore::HttpResponse *response, bool &success) = 0;
private:
void buildStatusEntry(LLCore::HttpResponse *response, LLCore::HttpStatus status, LLSD &result);
LLEventStream &mReplyPump;
};
//=========================================================================
/// An adapter to handle some of the boilerplate code surrounding HTTP and coroutine
/// interaction.
///
/// Construct an HttpCoroutineAdapter giving it a name and policy Id. After
/// any application specific setup call the post, put or get method. The request
/// will be automatically pumped and the method will return with an LLSD describing
/// the result of the operation. See HttpCoroHandler for a description of the
/// decoration done to the returned LLSD.
///
/// Posting through the adapter will automatically add the following headers to
/// the request if they have not been previously specified in a supplied
/// HttpHeaders object:
/// "Accept=application/llsd+xml"
/// "X-SecondLife-UDP-Listen-Port=###"
///
class HttpCoroutineAdapter
{
public:
static const std::string HTTP_RESULTS;
static const std::string HTTP_RESULTS_SUCCESS;
static const std::string HTTP_RESULTS_TYPE;
static const std::string HTTP_RESULTS_STATUS;
static const std::string HTTP_RESULTS_MESSAGE;
static const std::string HTTP_RESULTS_URL;
static const std::string HTTP_RESULTS_HEADERS;
static const std::string HTTP_RESULTS_CONTENT;
static const std::string HTTP_RESULTS_RAW;
typedef std::shared_ptr<HttpCoroutineAdapter> ptr_t;
typedef std::weak_ptr<HttpCoroutineAdapter> wptr_t;
HttpCoroutineAdapter(const std::string &name, LLCore::HttpRequest::policy_t policyId);
~HttpCoroutineAdapter();
/// Execute a Post transaction on the supplied URL and yield execution of
/// the coroutine until a result is available.
///
/// @Note: the request's smart pointer is passed by value so that it will
/// not be deallocated during the yield.
LLSD postAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url, const LLSD & body,
LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
LLSD postAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url, LLCore::BufferArray::ptr_t rawbody,
LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
LLSD postAndSuspend(LLCore::HttpRequest::ptr_t &request,
const std::string & url, const LLSD & body,
LLCore::HttpHeaders::ptr_t &headers)
{
return postAndSuspend(request, url, body,
LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers);
}
LLSD postAndSuspend(LLCore::HttpRequest::ptr_t &request,
const std::string & url, LLCore::BufferArray::ptr_t &rawbody,
LLCore::HttpHeaders::ptr_t &headers)
{
return postAndSuspend(request, url, rawbody,
LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers);
}
LLSD postRawAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url, LLCore::BufferArray::ptr_t rawbody,
LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
LLSD postRawAndSuspend(LLCore::HttpRequest::ptr_t &request,
const std::string & url, LLCore::BufferArray::ptr_t &rawbody,
LLCore::HttpHeaders::ptr_t &headers)
{
return postRawAndSuspend(request, url, rawbody,
LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers);
}
LLSD postFileAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url, std::string fileName,
LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
LLSD postFileAndSuspend(LLCore::HttpRequest::ptr_t &request,
const std::string & url, std::string fileName,
LLCore::HttpHeaders::ptr_t &headers)
{
return postFileAndSuspend(request, url, fileName,
LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers);
}
LLSD postFileAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url, LLUUID assetId, LLAssetType::EType assetType,
LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
LLSD postFileAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url, LLUUID assetId, LLAssetType::EType assetType,
LLCore::HttpHeaders::ptr_t &headers)
{
return postFileAndSuspend(request, url, assetId, assetType,
LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers);
}
LLSD postJsonAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url, const LLSD & body,
LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
LLSD postJsonAndSuspend(LLCore::HttpRequest::ptr_t &request,
const std::string & url, const LLSD & body,
LLCore::HttpHeaders::ptr_t &headers)
{
return postJsonAndSuspend(request, url, body,
LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers);
}
/// Execute a Put transaction on the supplied URL and yield execution of
/// the coroutine until a result is available.
///
/// @Note: the request's smart pointer is passed by value so that it will
/// not be deallocated during the yield.
LLSD putAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url, const LLSD & body,
LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
LLSD putAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url, const LLSD & body,
LLCore::HttpHeaders::ptr_t headers)
{
return putAndSuspend(request, url, body,
LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers);
}
LLSD putJsonAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url, const LLSD & body,
LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
LLSD putJsonAndSuspend(LLCore::HttpRequest::ptr_t &request,
const std::string & url, const LLSD & body,
LLCore::HttpHeaders::ptr_t &headers)
{
return putJsonAndSuspend(request, url, body,
LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers);
}
/// Execute a Get transaction on the supplied URL and yield execution of
/// the coroutine until a result is available.
///
/// @Note: the request's smart pointer is passed by value so that it will
/// not be deallocated during the yield.
///
LLSD getAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url,
LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
LLSD getAndSuspend(LLCore::HttpRequest::ptr_t &request,
const std::string & url, LLCore::HttpHeaders::ptr_t &headers)
{
return getAndSuspend(request, url,
LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
headers);
}
LLSD getRawAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url,
LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
LLSD getRawAndSuspend(LLCore::HttpRequest::ptr_t &request,
const std::string & url, LLCore::HttpHeaders::ptr_t &headers)
{
return getRawAndSuspend(request, url,
LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
headers);
}
/// These methods have the same behavior as @getAndSuspend() however they are
/// expecting the server to return the results formatted in a JSON string.
/// On a successful GET call the JSON results will be converted into LLSD
/// before being returned to the caller.
LLSD getJsonAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url,
LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
LLSD getJsonAndSuspend(LLCore::HttpRequest::ptr_t &request,
const std::string & url, LLCore::HttpHeaders::ptr_t &headers)
{
return getJsonAndSuspend(request, url,
LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
headers);
}
/// Execute a DELETE transaction on the supplied URL and yield execution of
/// the coroutine until a result is available.
///
/// @Note: the request's smart pointer is passed by value so that it will
/// not be deallocated during the yield.
LLSD deleteAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url,
LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
LLSD deleteAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url, LLCore::HttpHeaders::ptr_t headers)
{
return deleteAndSuspend(request, url,
LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
headers);
}
/// These methods have the same behavior as @deleteAndSuspend() however they are
/// expecting the server to return any results formatted in a JSON string.
/// On a successful DELETE call the JSON results will be converted into LLSD
/// before being returned to the caller.
LLSD deleteJsonAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url,
LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
LLSD deleteJsonAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url, LLCore::HttpHeaders::ptr_t headers)
{
return deleteJsonAndSuspend(request, url,
LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
headers);
}
/// Execute a PATCH transaction on the supplied URL and yield execution of
/// the coroutine until a result is available.
///
/// @Note: the request's smart pointer is passed by value so that it will
/// not be deallocated during the yield.
LLSD patchAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url, const LLSD & body,
LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
LLSD patchAndSuspend(LLCore::HttpRequest::ptr_t &request,
const std::string & url, const LLSD & body,
LLCore::HttpHeaders::ptr_t &headers)
{
return patchAndSuspend(request, url, body,
LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers);
}
/// Execute a COPY transaction on the supplied URL and yield execution of
/// the coroutine until a result is available.
///
/// @Note: The destination is passed through the HTTP pipe as a header
/// The header used is defined as: HTTP_OUT_HEADER_DESTINATION("Destination");
///
/// @Note: the request's smart pointer is passed by value so that it will
/// not be deallocated during the yield.
LLSD copyAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url, const std::string dest,
LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
LLSD copyAndSuspend(LLCore::HttpRequest::ptr_t &request,
const std::string & url, const std::string & dest,
LLCore::HttpHeaders::ptr_t &headers)
{
return copyAndSuspend(request, url, dest,
LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers);
}
/// Execute a MOVE transaction on the supplied URL and yield execution of
/// the coroutine until a result is available.
///
/// @Note: The destination is passed through the HTTP pipe in the headers.
/// The header used is defined as: HTTP_OUT_HEADER_DESTINATION("Destination");
///
/// @Note: the request's smart pointer is passed by value so that it will
/// not be deallocated during the yield.
LLSD moveAndSuspend(LLCore::HttpRequest::ptr_t request,
const std::string & url, const std::string dest,
LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
LLSD moveAndSuspend(LLCore::HttpRequest::ptr_t &request,
const std::string & url, const std::string & dest,
LLCore::HttpHeaders::ptr_t &headers)
{
return moveAndSuspend(request, url, dest,
LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers);
}
///
void cancelSuspendedOperation();
static LLCore::HttpStatus getStatusFromLLSD(const LLSD &httpResults);
/// The convenience routines below can be provided with callback functors
/// which will be invoked in the case of success or failure. These callbacks
/// should match this form.
/// @sa callbackHttpGet
/// @sa callbackHttpPost
typedef boost::function<void(const LLSD &)> completionCallback_t;
static void callbackHttpGet(const std::string &url, LLCore::HttpRequest::policy_t policyId, completionCallback_t success = NULL, completionCallback_t failure = NULL);
static void callbackHttpGet(const std::string &url, completionCallback_t success = NULL, completionCallback_t failure = NULL)
{
callbackHttpGet(url, LLCore::HttpRequest::DEFAULT_POLICY_ID, success, failure);
}
static void callbackHttpPost(const std::string &url, LLCore::HttpRequest::policy_t policyId, const LLSD &postData, completionCallback_t success = NULL, completionCallback_t failure = NULL);
static void callbackHttpPost(const std::string &url, const LLSD &postData, completionCallback_t success = NULL, completionCallback_t failure = NULL)
{
callbackHttpPost(url, LLCore::HttpRequest::DEFAULT_POLICY_ID, postData, success, failure);
}
static void callbackHttpDel(const std::string &url, LLCore::HttpRequest::policy_t policyId, completionCallback_t success = NULL,
completionCallback_t failure = NULL);
/// Generic Get and post routines for HTTP via coroutines.
/// These static methods do all required setup for the GET or POST operation.
/// When the operation completes successfully they will put the success message in the log at INFO level,
/// If the operation fails the failure message is written to the log at WARN level.
///
static void messageHttpGet(const std::string &url, const std::string &success = std::string(), const std::string &failure = std::string());
static void messageHttpPost(const std::string &url, const LLSD &postData, const std::string &success, const std::string &failure);
private:
static LLSD buildImmediateErrorResult(const LLCore::HttpRequest::ptr_t &request, const std::string &url);
void saveState(LLCore::HttpHandle yieldingHandle, LLCore::HttpRequest::ptr_t &request,
HttpCoroHandler::ptr_t &handler);
void cleanState();
LLSD postAndSuspend_(LLCore::HttpRequest::ptr_t &request,
const std::string & url, const LLSD & body,
LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
HttpCoroHandler::ptr_t &handler);
LLSD postAndSuspend_(LLCore::HttpRequest::ptr_t &request,
const std::string & url, LLCore::BufferArray::ptr_t &rawbody,
LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
HttpCoroHandler::ptr_t &handler);
LLSD putAndSuspend_(LLCore::HttpRequest::ptr_t &request,
const std::string & url, const LLSD & body,
LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
HttpCoroHandler::ptr_t &handler);
LLSD putAndSuspend_(LLCore::HttpRequest::ptr_t &request,
const std::string & url, const LLCore::BufferArray::ptr_t & rawbody,
LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
HttpCoroHandler::ptr_t &handler);
LLSD getAndSuspend_(LLCore::HttpRequest::ptr_t &request,
const std::string & url, LLCore::HttpOptions::ptr_t &options,
LLCore::HttpHeaders::ptr_t &headers, HttpCoroHandler::ptr_t &handler);
LLSD deleteAndSuspend_(LLCore::HttpRequest::ptr_t &request,
const std::string & url, LLCore::HttpOptions::ptr_t &options,
LLCore::HttpHeaders::ptr_t &headers, HttpCoroHandler::ptr_t &handler);
LLSD patchAndSuspend_(LLCore::HttpRequest::ptr_t &request,
const std::string & url, const LLSD & body,
LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
HttpCoroHandler::ptr_t &handler);
LLSD copyAndSuspend_(LLCore::HttpRequest::ptr_t &request,
const std::string & url,
LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
HttpCoroHandler::ptr_t &handler);
LLSD moveAndSuspend_(LLCore::HttpRequest::ptr_t &request,
const std::string & url,
LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
HttpCoroHandler::ptr_t &handler);
static void trivialGetCoro(std::string url, LLCore::HttpRequest::policy_t policyId, completionCallback_t success, completionCallback_t failure);
static void trivialPostCoro(std::string url, LLCore::HttpRequest::policy_t policyId, LLSD postData, completionCallback_t success, completionCallback_t failure);
static void trivialDelCoro(std::string url, LLCore::HttpRequest::policy_t policyId, completionCallback_t success, completionCallback_t failure);
void checkDefaultHeaders(LLCore::HttpHeaders::ptr_t &headers);
std::string mAdapterName;
LLCore::HttpRequest::policy_t mPolicyId;
LLCore::HttpHandle mYieldingHandle;
LLCore::HttpRequest::wptr_t mWeakRequest;
HttpCoroHandler::wptr_t mWeakHandler;
};
} // end namespace LLCoreHttpUtil
#endif // LL_LLCOREHTTPUTIL_H
File diff suppressed because it is too large Load Diff
+437
View File
@@ -0,0 +1,437 @@
/**
* @file lldatapacker.h
* @brief Data packer declaration for tightly storing binary data.
*
* $LicenseInfo:firstyear=2002&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_LLDATAPACKER_H
#define LL_LLDATAPACKER_H
#include "nd/ndexceptions.h" // <FS:ND/> For ndxran
class LLColor4;
class LLColor4U;
class LLVector2;
class LLVector3;
class LLVector4;
class LLUUID;
class LLDataPacker
{
public:
virtual ~LLDataPacker() {}
// Not required to override, but error to call?
virtual void reset();
virtual void dumpBufferToLog();
virtual bool hasNext() const = 0;
virtual bool packString(const std::string& value, const char *name) = 0;
virtual bool unpackString(std::string& value, const char *name) = 0;
virtual bool packBinaryData(const U8 *value, S32 size, const char *name) = 0;
virtual bool unpackBinaryData(U8 *value, S32 &size, const char *name) = 0;
// Constant size binary data packing
virtual bool packBinaryDataFixed(const U8 *value, S32 size, const char *name) = 0;
virtual bool unpackBinaryDataFixed(U8 *value, S32 size, const char *name) = 0;
virtual bool packU8(const U8 value, const char *name) = 0;
virtual bool unpackU8(U8 &value, const char *name) = 0;
virtual bool packU16(const U16 value, const char *name) = 0;
virtual bool unpackU16(U16 &value, const char *name) = 0;
bool unpackU16s(U16 *value, S32 count, const char *name);
virtual bool packS16(const S16 value, const char *name) = 0;
virtual bool unpackS16(S16 &value, const char *name) = 0;
bool unpackS16s(S16 *value, S32 count, const char *name);
virtual bool packU32(const U32 value, const char *name) = 0;
virtual bool unpackU32(U32 &value, const char *name) = 0;
virtual bool packS32(const S32 value, const char *name) = 0;
virtual bool unpackS32(S32 &value, const char *name) = 0;
virtual bool packF32(const F32 value, const char *name) = 0;
virtual bool unpackF32(F32 &value, const char *name) = 0;
bool unpackF32s(F32 *values, S32 count, const char *name);
// Packs a float into an integer, using the given size
// and picks the right U* data type to pack into.
bool packFixed(const F32 value, const char *name,
const bool is_signed, const U32 int_bits, const U32 frac_bits);
bool unpackFixed(F32 &value, const char *name,
const bool is_signed, const U32 int_bits, const U32 frac_bits);
virtual bool packColor4(const LLColor4 &value, const char *name) = 0;
virtual bool unpackColor4(LLColor4 &value, const char *name) = 0;
virtual bool packColor4U(const LLColor4U &value, const char *name) = 0;
virtual bool unpackColor4U(LLColor4U &value, const char *name) = 0;
bool unpackColor4Us(LLColor4U *values, S32 count, const char *name);
virtual bool packVector2(const LLVector2 &value, const char *name) = 0;
virtual bool unpackVector2(LLVector2 &value, const char *name) = 0;
virtual bool packVector3(const LLVector3 &value, const char *name) = 0;
virtual bool unpackVector3(LLVector3 &value, const char *name) = 0;
virtual bool packVector4(const LLVector4 &value, const char *name) = 0;
virtual bool unpackVector4(LLVector4 &value, const char *name) = 0;
virtual bool packUUID(const LLUUID &value, const char *name) = 0;
virtual bool unpackUUID(LLUUID &value, const char *name) = 0;
bool unpackUUIDs(LLUUID *values, S32 count, const char *name);
U32 getPassFlags() const { return mPassFlags; }
void setPassFlags(U32 flags) { mPassFlags = flags; }
protected:
LLDataPacker();
protected:
U32 mPassFlags;
bool mWriteEnabled; // disable this to do things like determine filesize without actually copying data
};
class LLDataPackerBinaryBuffer : public LLDataPacker
{
public:
LLDataPackerBinaryBuffer(U8 *bufferp, S32 size)
: LLDataPacker(),
mBufferp(bufferp),
mCurBufferp(bufferp),
mBufferSize(size)
{
mWriteEnabled = true;
}
LLDataPackerBinaryBuffer()
: LLDataPacker(),
mBufferp(NULL),
mCurBufferp(NULL),
mBufferSize(0)
{
}
/*virtual*/ bool packString(const std::string& value, const char *name);
/*virtual*/ bool unpackString(std::string& value, const char *name);
/*virtual*/ bool packBinaryData(const U8 *value, S32 size, const char *name);
/*virtual*/ bool unpackBinaryData(U8 *value, S32 &size, const char *name);
// Constant size binary data packing
/*virtual*/ bool packBinaryDataFixed(const U8 *value, S32 size, const char *name);
/*virtual*/ bool unpackBinaryDataFixed(U8 *value, S32 size, const char *name);
/*virtual*/ bool packU8(const U8 value, const char *name);
/*virtual*/ bool unpackU8(U8 &value, const char *name);
/*virtual*/ bool packU16(const U16 value, const char *name);
/*virtual*/ bool unpackU16(U16 &value, const char *name);
/*virtual*/ bool packS16(const S16 value, const char *name);
/*virtual*/ bool unpackS16(S16 &value, const char *name);
/*virtual*/ bool packU32(const U32 value, const char *name);
/*virtual*/ bool unpackU32(U32 &value, const char *name);
/*virtual*/ bool packS32(const S32 value, const char *name);
/*virtual*/ bool unpackS32(S32 &value, const char *name);
/*virtual*/ bool packF32(const F32 value, const char *name);
/*virtual*/ bool unpackF32(F32 &value, const char *name);
/*virtual*/ bool packColor4(const LLColor4 &value, const char *name);
/*virtual*/ bool unpackColor4(LLColor4 &value, const char *name);
/*virtual*/ bool packColor4U(const LLColor4U &value, const char *name);
/*virtual*/ bool unpackColor4U(LLColor4U &value, const char *name);
/*virtual*/ bool packVector2(const LLVector2 &value, const char *name);
/*virtual*/ bool unpackVector2(LLVector2 &value, const char *name);
/*virtual*/ bool packVector3(const LLVector3 &value, const char *name);
/*virtual*/ bool unpackVector3(LLVector3 &value, const char *name);
/*virtual*/ bool packVector4(const LLVector4 &value, const char *name);
/*virtual*/ bool unpackVector4(LLVector4 &value, const char *name);
/*virtual*/ bool packUUID(const LLUUID &value, const char *name);
/*virtual*/ bool unpackUUID(LLUUID &value, const char *name);
S32 getCurrentSize() const { return (S32)(mCurBufferp - mBufferp); }
S32 getBufferSize() const { return mBufferSize; }
const U8* getBuffer() const { return mBufferp; }
void reset() { mCurBufferp = mBufferp; mWriteEnabled = (mCurBufferp != NULL); }
void shift(S32 offset) { reset(); mCurBufferp += offset;}
void freeBuffer() { delete [] mBufferp; mBufferp = mCurBufferp = NULL; mBufferSize = 0; mWriteEnabled = false; }
void assignBuffer(U8 *bufferp, S32 size)
{
if(mBufferp && mBufferp != bufferp)
{
freeBuffer() ;
}
mBufferp = bufferp;
mCurBufferp = bufferp;
mBufferSize = size;
mWriteEnabled = true;
}
const LLDataPackerBinaryBuffer& operator=(const LLDataPackerBinaryBuffer &a);
/*virtual*/ bool hasNext() const { return getCurrentSize() < getBufferSize(); }
/*virtual*/ void dumpBufferToLog();
protected:
inline bool verifyLength(const S32 data_size, const char *name);
U8 *mBufferp;
U8 *mCurBufferp;
S32 mBufferSize;
};
inline bool LLDataPackerBinaryBuffer::verifyLength(const S32 data_size, const char *name)
{
if (mWriteEnabled && (mCurBufferp - mBufferp) > mBufferSize - data_size)
{
LL_WARNS() << "Buffer overflow in BinaryBuffer length verify, field name " << name << "!" << LL_ENDL;
LL_WARNS() << "Current pos: " << (int)(mCurBufferp - mBufferp) << " Buffer size: " << mBufferSize << " Data size: " << data_size << LL_ENDL;
return false;
}
return true;
}
class LLDataPackerAsciiBuffer : public LLDataPacker
{
public:
LLDataPackerAsciiBuffer(char* bufferp, S32 size)
{
mBufferp = bufferp;
mCurBufferp = bufferp;
mBufferSize = size;
mPassFlags = 0;
mIncludeNames = false;
mWriteEnabled = true;
}
LLDataPackerAsciiBuffer()
{
mBufferp = NULL;
mCurBufferp = NULL;
mBufferSize = 0;
mPassFlags = 0;
mIncludeNames = false;
mWriteEnabled = false;
}
/*virtual*/ bool packString(const std::string& value, const char *name);
/*virtual*/ bool unpackString(std::string& value, const char *name);
/*virtual*/ bool packBinaryData(const U8 *value, S32 size, const char *name);
/*virtual*/ bool unpackBinaryData(U8 *value, S32 &size, const char *name);
// Constant size binary data packing
/*virtual*/ bool packBinaryDataFixed(const U8 *value, S32 size, const char *name);
/*virtual*/ bool unpackBinaryDataFixed(U8 *value, S32 size, const char *name);
/*virtual*/ bool packU8(const U8 value, const char *name);
/*virtual*/ bool unpackU8(U8 &value, const char *name);
/*virtual*/ bool packU16(const U16 value, const char *name);
/*virtual*/ bool unpackU16(U16 &value, const char *name);
/*virtual*/ bool packS16(const S16 value, const char *name);
/*virtual*/ bool unpackS16(S16 &value, const char *name);
/*virtual*/ bool packU32(const U32 value, const char *name);
/*virtual*/ bool unpackU32(U32 &value, const char *name);
/*virtual*/ bool packS32(const S32 value, const char *name);
/*virtual*/ bool unpackS32(S32 &value, const char *name);
/*virtual*/ bool packF32(const F32 value, const char *name);
/*virtual*/ bool unpackF32(F32 &value, const char *name);
/*virtual*/ bool packColor4(const LLColor4 &value, const char *name);
/*virtual*/ bool unpackColor4(LLColor4 &value, const char *name);
/*virtual*/ bool packColor4U(const LLColor4U &value, const char *name);
/*virtual*/ bool unpackColor4U(LLColor4U &value, const char *name);
/*virtual*/ bool packVector2(const LLVector2 &value, const char *name);
/*virtual*/ bool unpackVector2(LLVector2 &value, const char *name);
/*virtual*/ bool packVector3(const LLVector3 &value, const char *name);
/*virtual*/ bool unpackVector3(LLVector3 &value, const char *name);
/*virtual*/ bool packVector4(const LLVector4 &value, const char *name);
/*virtual*/ bool unpackVector4(LLVector4 &value, const char *name);
/*virtual*/ bool packUUID(const LLUUID &value, const char *name);
/*virtual*/ bool unpackUUID(LLUUID &value, const char *name);
void setIncludeNames(bool b) { mIncludeNames = b; }
// Include the trailing NULL so it's always a valid string
S32 getCurrentSize() const { return (S32)(mCurBufferp - mBufferp) + 1; }
S32 getBufferSize() const { return mBufferSize; }
/*virtual*/ void reset() { mCurBufferp = mBufferp; mWriteEnabled = (mCurBufferp != NULL); }
/*virtual*/ bool hasNext() const { return getCurrentSize() < getBufferSize(); }
inline void freeBuffer();
inline void assignBuffer(char* bufferp, S32 size);
void dump();
protected:
void writeIndentedName(const char *name);
bool getValueStr(const char *name, char *out_value, const S32 value_len);
protected:
inline bool verifyLength(const S32 data_size, const char *name);
char *mBufferp;
char *mCurBufferp;
S32 mBufferSize;
bool mIncludeNames; // useful for debugging, print the name of each field
};
inline void LLDataPackerAsciiBuffer::freeBuffer()
{
delete [] mBufferp;
mBufferp = mCurBufferp = NULL;
mBufferSize = 0;
mWriteEnabled = false;
}
inline void LLDataPackerAsciiBuffer::assignBuffer(char* bufferp, S32 size)
{
mBufferp = bufferp;
mCurBufferp = bufferp;
mBufferSize = size;
mWriteEnabled = true;
}
inline bool LLDataPackerAsciiBuffer::verifyLength(const S32 data_size, const char *name)
{
if (mWriteEnabled && (mCurBufferp - mBufferp) > mBufferSize - data_size)
{
LL_WARNS() << "Buffer overflow in AsciiBuffer length verify, field name " << name << "!" << LL_ENDL;
LL_WARNS() << "Current pos: " << (int)(mCurBufferp - mBufferp) << " Buffer size: " << mBufferSize << " Data size: " << data_size << LL_ENDL;
return false;
}
return true;
}
class LLDataPackerAsciiFile : public LLDataPacker
{
public:
LLDataPackerAsciiFile(LLFILE *fp, const S32 indent = 2)
: LLDataPacker(),
mIndent(indent),
mFP(fp),
mOutputStream(NULL),
mInputStream(NULL)
{
}
LLDataPackerAsciiFile(std::ostream& output_stream, const S32 indent = 2)
: LLDataPacker(),
mIndent(indent),
mFP(NULL),
mOutputStream(&output_stream),
mInputStream(NULL)
{
mWriteEnabled = true;
}
LLDataPackerAsciiFile(std::istream& input_stream, const S32 indent = 2)
: LLDataPacker(),
mIndent(indent),
mFP(NULL),
mOutputStream(NULL),
mInputStream(&input_stream)
{
}
/*virtual*/ bool packString(const std::string& value, const char *name);
/*virtual*/ bool unpackString(std::string& value, const char *name);
/*virtual*/ bool packBinaryData(const U8 *value, S32 size, const char *name);
/*virtual*/ bool unpackBinaryData(U8 *value, S32 &size, const char *name);
/*virtual*/ bool packBinaryDataFixed(const U8 *value, S32 size, const char *name);
/*virtual*/ bool unpackBinaryDataFixed(U8 *value, S32 size, const char *name);
/*virtual*/ bool packU8(const U8 value, const char *name);
/*virtual*/ bool unpackU8(U8 &value, const char *name);
/*virtual*/ bool packU16(const U16 value, const char *name);
/*virtual*/ bool unpackU16(U16 &value, const char *name);
/*virtual*/ bool packS16(const S16 value, const char *name);
/*virtual*/ bool unpackS16(S16 &value, const char *name);
/*virtual*/ bool packU32(const U32 value, const char *name);
/*virtual*/ bool unpackU32(U32 &value, const char *name);
/*virtual*/ bool packS32(const S32 value, const char *name);
/*virtual*/ bool unpackS32(S32 &value, const char *name);
/*virtual*/ bool packF32(const F32 value, const char *name);
/*virtual*/ bool unpackF32(F32 &value, const char *name);
/*virtual*/ bool packColor4(const LLColor4 &value, const char *name);
/*virtual*/ bool unpackColor4(LLColor4 &value, const char *name);
/*virtual*/ bool packColor4U(const LLColor4U &value, const char *name);
/*virtual*/ bool unpackColor4U(LLColor4U &value, const char *name);
/*virtual*/ bool packVector2(const LLVector2 &value, const char *name);
/*virtual*/ bool unpackVector2(LLVector2 &value, const char *name);
/*virtual*/ bool packVector3(const LLVector3 &value, const char *name);
/*virtual*/ bool unpackVector3(LLVector3 &value, const char *name);
/*virtual*/ bool packVector4(const LLVector4 &value, const char *name);
/*virtual*/ bool unpackVector4(LLVector4 &value, const char *name);
/*virtual*/ bool packUUID(const LLUUID &value, const char *name);
/*virtual*/ bool unpackUUID(LLUUID &value, const char *name);
protected:
void writeIndentedName(const char *name);
bool getValueStr(const char *name, char *out_value, const S32 value_len);
/*virtual*/ bool hasNext() const { return true; }
protected:
S32 mIndent;
LLFILE *mFP;
std::ostream* mOutputStream;
std::istream* mInputStream;
};
#endif // LL_LLDATAPACKER
+214
View File
@@ -0,0 +1,214 @@
/**
* @file lldbstrings.h
* @brief Database String Lengths.
*
* $LicenseInfo:firstyear=2002&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_LLDBSTRINGS_H
#define LL_LLDBSTRINGS_H
/**
* Defines the length of strings that are stored in the database (and
* the size of the buffer large enough to hold each one)
*/
// asset.name varchar(63)
// -also-
// user_inventory_item.name varchar(63)
// -also-
// user_inventory_folder.name varchar(63) was CAT_NAME_SIZE
// Must be >= DB_FULL_NAME_STR_LEN so that calling cards work
const S32 DB_INV_ITEM_NAME_STR_LEN = 63; // was MAX_ASSET_NAME_LENGTH
const S32 DB_INV_ITEM_NAME_BUF_SIZE = 64; // was ITEM_NAME_SIZE
// asset.description varchar(127)
// -also-
// user_inventory_item.description varchar(127)
const S32 DB_INV_ITEM_DESC_STR_LEN = 127; // was MAX_ASSET_DESCRIPTION_LENGTH
const S32 DB_INV_ITEM_DESC_BUF_SIZE = 128; // was ITEM_DESC_SIZE
// groups.name varchar(35)
const S32 DB_GROUP_NAME_STR_LEN = 35;
const S32 DB_GROUP_NAME_BUF_SIZE = 36;
const S32 DB_GROUP_NAME_MIN_LEN = 4;
//group_roles.name
const U32 DB_GROUP_ROLE_NAME_STR_LEN = 20;
const U32 DB_GROUP_ROLE_NAME_BUF_SIZE = DB_GROUP_ROLE_NAME_STR_LEN + 1;
//group_roles.title
const U32 DB_GROUP_ROLE_TITLE_STR_LEN = 20;
const U32 DB_GROUP_ROLE_TITLE_BUF_SIZE = DB_GROUP_ROLE_TITLE_STR_LEN + 1;
// group.charter text
const S32 DB_GROUP_CHARTER_STR_LEN = 511;
const S32 DB_GROUP_CHARTER_BUF_SIZE = 512;
// group.officer_title varchar(20)
// -also-
// group.member_title varchar(20)
const S32 DB_GROUP_TITLE_STR_LEN = 20;
const S32 DB_GROUP_TITLE_BUF_SIZE = 21;
// Since chat and im both dump into the database text message log,
// they derive their max size from the same constant.
const S32 MAX_MSG_STR_LEN = 1023;
const S32 MAX_MSG_BUF_SIZE = 1024;
// instant_message.message text
const S32 DB_IM_MSG_STR_LEN = MAX_MSG_STR_LEN;
const S32 DB_IM_MSG_BUF_SIZE = MAX_MSG_BUF_SIZE;
// groupnotices
const S32 DB_GROUP_NOTICE_SUBJ_STR_LEN = 63;
const S32 DB_GROUP_NOTICE_SUBJ_STR_SIZE = 64;
const S32 DB_GROUP_NOTICE_MSG_STR_LEN = MAX_MSG_STR_LEN - DB_GROUP_NOTICE_SUBJ_STR_LEN;
const S32 DB_GROUP_NOTICE_MSG_STR_SIZE = MAX_MSG_BUF_SIZE - DB_GROUP_NOTICE_SUBJ_STR_SIZE;
// log_text_message.message text
const S32 DB_CHAT_MSG_STR_LEN = MAX_MSG_STR_LEN;
const S32 DB_CHAT_MSG_BUF_SIZE = MAX_MSG_BUF_SIZE;
// money_stipend.description varchar(254)
const S32 DB_STIPEND_DESC_STR_LEN = 254;
const S32 DB_STIPEND_DESC_BUF_SIZE = 255;
// script_email_message.from_email varchar(78)
const S32 DB_EMAIL_FROM_STR_LEN = 78;
const S32 DB_EMAIL_FROM_BUF_SIZE = 79;
// script_email_message.subject varchar(72)
const S32 DB_EMAIL_SUBJECT_STR_LEN = 72;
const S32 DB_EMAIL_SUBJECT_BUF_SIZE = 73;
// system_globals.motd varchar(254)
const S32 DB_MOTD_STR_LEN = 254;
const S32 DB_MOTD_BUF_SIZE = 255;
// Must be <= user_inventory_item.name so that calling cards work
// First name + " " + last name...or a system assigned "from" name
// instant_message.from_agent_name varchar(63)
// -also-
// user_mute.mute_agent_name varchar(63)
const S32 DB_FULL_NAME_STR_LEN = 63;
const S32 DB_FULL_NAME_BUF_SIZE = 64; // was USER_NAME_SIZE
// user.username varchar(31)
const S32 DB_FIRST_NAME_STR_LEN = 31;
const S32 DB_FIRST_NAME_BUF_SIZE = 32; // was MAX_FIRST_NAME
// user_last_name.name varchar(31)
const S32 DB_LAST_NAME_STR_LEN = 31;
const S32 DB_LAST_NAME_BUF_SIZE = 32; // was MAX_LAST_NAME
// user.password varchar(100)
const S32 DB_USER_PASSWORD_STR_LEN = 100;
const S32 DB_USER_PASSWORD_BUF_SIZE = 101; // was MAX_PASSWORD
// user.email varchar(254)
const S32 DB_USER_EMAIL_ADDR_STR_LEN = 254;
const S32 DB_USER_EMAIL_ADDR_BUF_SIZE = 255;
// user.about text
const S32 DB_USER_ABOUT_STR_LEN = 511;
const S32 DB_USER_ABOUT_BUF_SIZE = 512;
// user.fl_about_text text
// Must be 255 not 256 as gets packed into message Variable 1
const S32 DB_USER_FL_ABOUT_STR_LEN = 254;
const S32 DB_USER_FL_ABOUT_BUF_SIZE = 255;
// user.profile_url text
// Must be 255 not 256 as gets packed into message Variable 1
const S32 DB_USER_PROFILE_URL_STR_LEN = 254;
const S32 DB_USER_PROFILE_URL_BUF_SIZE = 255;
// user.want_to varchar(254)
const S32 DB_USER_WANT_TO_STR_LEN = 254;
const S32 DB_USER_WANT_TO_BUF_SIZE = 255;
// user.skills varchar(254)
const S32 DB_USER_SKILLS_STR_LEN = 254;
const S32 DB_USER_SKILLS_BUF_SIZE = 255;
// user_nv.name varchar(128)
const S32 DB_NV_NAME_STR_LEN = 128;
const S32 DB_NV_NAME_BUF_SIZE = 129;
// user_start_location.location_name varchar(254)
const S32 DB_START_LOCATION_STR_LEN = 254;
const S32 DB_START_LOCATION_BUF_SIZE = 255;
// money_tax_assessment.sim varchar(100)
//const S32 DB_SIM_NAME_STR_LEN = 100;
//const S32 DB_SIM_NAME_BUF_SIZE = 101;
// born on date date
const S32 DB_BORN_STR_LEN = 15;
const S32 DB_BORN_BUF_SIZE = 16;
// place.name
const S32 DB_PLACE_NAME_LEN = 63;
const S32 DB_PLACE_NAME_SIZE = 64;
const S32 DB_PARCEL_NAME_LEN = 63;
const S32 DB_PARCEL_NAME_SIZE = 64;
// place.desc
const S32 DB_PLACE_DESC_LEN = 255;
const S32 DB_PLACE_DESC_SIZE = 256;
const S32 DB_PARCEL_DESC_LEN = 255;
const S32 DB_PARCEL_DESC_SIZE = 256;
const S32 DB_PARCEL_MUSIC_URL_LEN = 255;
const S32 DB_PARCEL_MEDIA_URL_LEN = 255;
const S32 DB_PARCEL_MUSIC_URL_SIZE = 256;
// date time that is easily human readable
const S32 DB_DATETIME_STR_LEN = 35;
const S32 DB_DATETIME_BUF_SIZE = 36;
// date time that isn't easily human readable
const S32 DB_TERSE_DATETIME_STR_LEN = 15;
const S32 DB_TERSE_DATETIME_BUF_SIZE = 16;
// indra.simulator constants
const S32 DB_SIM_NAME_STR_LEN = 35;
const S32 DB_SIM_NAME_BUF_SIZE = 36;
const S32 DB_HOST_NAME_STR_LEN = 100;
const S32 DB_HOST_NAME_BUF_SIZE = 101;
const S32 DB_ESTATE_NAME_STR_LEN = 63;
const S32 DB_ESTATE_NAME_BUF_SIZE = DB_ESTATE_NAME_STR_LEN + 1;
// user_note.note
const S32 DB_USER_NOTE_LEN = 1023;
const S32 DB_USER_NOTE_SIZE = 1024;
// pick.name
const S32 DB_PICK_NAME_LEN = 63;
const S32 DB_PICK_NAME_SIZE = 64;
// pick.desc
const S32 DB_PICK_DESC_LEN = 1023;
const S32 DB_PICK_DESC_SIZE = 1024;
#endif // LL_LLDBSTRINGS_H
+170
View File
@@ -0,0 +1,170 @@
/**
* @file lldispatcher.cpp
* @brief Implementation of the dispatcher object.
*
* $LicenseInfo:firstyear=2004&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 "lldispatcher.h"
#include <algorithm>
#include <iterator>
#include "llstl.h"
#include "message.h"
///----------------------------------------------------------------------------
/// Class lldispatcher
///----------------------------------------------------------------------------
LLDispatcher::LLDispatcher()
{
}
LLDispatcher::~LLDispatcher()
{
}
bool LLDispatcher::isHandlerPresent(const key_t& name) const
{
if(mHandlers.find(name) != mHandlers.end())
{
return true;
}
return false;
}
void LLDispatcher::copyAllHandlerNames(keys_t& names) const
{
// copy the names onto the vector we are given
std::transform(
mHandlers.begin(),
mHandlers.end(),
std::back_insert_iterator<keys_t>(names),
[](const dispatch_map_t::value_type& pair) { return pair.first; });
}
bool LLDispatcher::dispatch(
const key_t& name,
const LLUUID& invoice,
const sparam_t& strings) const
{
dispatch_map_t::const_iterator it = mHandlers.find(name);
if(it != mHandlers.end())
{
LLDispatchHandler* func = (*it).second;
return (*func)(this, name, invoice, strings);
}
LL_WARNS() << "Unable to find handler for Generic message: " << name << LL_ENDL;
return false;
}
LLDispatchHandler* LLDispatcher::addHandler(
const key_t& name, LLDispatchHandler* func)
{
dispatch_map_t::iterator it = mHandlers.find(name);
LLDispatchHandler* old_handler = NULL;
if(it != mHandlers.end())
{
old_handler = (*it).second;
mHandlers.erase(it);
}
if(func)
{
// only non-null handlers so that we don't have to worry about
// it later.
mHandlers.insert(dispatch_map_t::value_type(name, func));
}
return old_handler;
}
// static
bool LLDispatcher::unpackMessage(
LLMessageSystem* msg,
LLDispatcher::key_t& method,
LLUUID& invoice,
LLDispatcher::sparam_t& parameters)
{
char buf[MAX_STRING]; /*Flawfinder: ignore*/
msg->getStringFast(_PREHASH_MethodData, _PREHASH_Method, method);
msg->getUUIDFast(_PREHASH_MethodData, _PREHASH_Invoice, invoice);
S32 size;
S32 count = msg->getNumberOfBlocksFast(_PREHASH_ParamList);
for (S32 i = 0; i < count; ++i)
{
// we treat the SParam as binary data (since it might be an
// LLUUID in compressed form which may have embedded \0's,)
size = msg->getSizeFast(_PREHASH_ParamList, i, _PREHASH_Parameter);
if (size >= 0)
{
msg->getBinaryDataFast(
_PREHASH_ParamList, _PREHASH_Parameter,
buf, size, i, MAX_STRING - 1);
// If the last byte of the data is 0x0, this is either a normally
// packed string, or a binary packed UUID (which for these messages
// are packed with a 17th byte 0x0). Unpack into a std::string
// without the trailing \0, so "abc\0" becomes std::string("abc", 3)
// which matches const char* "abc".
if (size > 0
&& buf[size - 1] == 0x0)
{
// special char*/size constructor because UUIDs may have embedded
// 0x0 bytes.
std::string binary_data(buf, size - 1);
parameters.push_back(binary_data);
}
else
{
// This is either a NULL string, or a string that was packed
// incorrectly as binary data, without the usual trailing '\0'.
std::string string_data(buf, size);
parameters.push_back(string_data);
}
}
}
return true;
}
// static
bool LLDispatcher::unpackLargeMessage(
LLMessageSystem* msg,
LLDispatcher::key_t& method,
LLUUID& invoice,
LLDispatcher::sparam_t& parameters)
{
msg->getStringFast(_PREHASH_MethodData, _PREHASH_Method, method);
msg->getUUIDFast(_PREHASH_MethodData, _PREHASH_Invoice, invoice);
S32 count = msg->getNumberOfBlocksFast(_PREHASH_ParamList);
for (S32 i = 0; i < count; ++i)
{
// This method treats all Parameter List params as strings and unpacks
// them regardless of length. If there is binary data it is the callers
// responsibility to decode it.
std::string param;
msg->getStringFast(_PREHASH_ParamList, _PREHASH_Parameter, param, i);
parameters.push_back(param);
}
return true;
}
+119
View File
@@ -0,0 +1,119 @@
/**
* @file lldispatcher.h
* @brief LLDispatcher class header file.
*
* $LicenseInfo:firstyear=2004&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_LLDISPATCHER_H
#define LL_LLDISPATCHER_H
#include <map>
#include <vector>
#include <string>
class LLDispatcher;
class LLMessageSystem;
class LLUUID;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLDispatchHandler
//
// Abstract base class for handling dispatches. Derive your own
// classes, construct them, and add them to the dispatcher you want to
// use.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLDispatchHandler
{
public:
typedef std::vector<std::string> sparam_t;
//typedef std::vector<S32> iparam_t;
LLDispatchHandler() {}
virtual ~LLDispatchHandler() {}
virtual bool operator()(
const LLDispatcher* dispatcher,
const std::string& key,
const LLUUID& invoice,
const sparam_t& string) = 0;
//const iparam_t& integers) = 0;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLDispatcher
//
// Basic utility class that handles dispatching keyed operations to
// function objects implemented as LLDispatchHandler derivations.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLDispatcher
{
public:
typedef std::string key_t;
typedef std::vector<std::string> keys_t;
typedef std::vector<std::string> sparam_t;
//typedef std::vector<S32> iparam_t;
// construct a dispatcher.
LLDispatcher();
virtual ~LLDispatcher();
// Returns if they keyed handler exists in this dispatcher.
bool isHandlerPresent(const key_t& name) const;
// copy all known keys onto keys_t structure
void copyAllHandlerNames(keys_t& names) const;
// Call this method with the name of the request that has come
// in. If the handler is present, it is called with the params and
// returns the return value from
bool dispatch(
const key_t& name,
const LLUUID& invoice,
const sparam_t& strings) const;
//const iparam_t& itegers) const;
// Add a handler. If one with the same key already exists, its
// pointer is returned, otherwise returns NULL. This object does
// not do memory management of the LLDispatchHandler, and relies
// on the caller to delete the object if necessary.
LLDispatchHandler* addHandler(const key_t& name, LLDispatchHandler* func);
// Helper method to unpack the dispatcher message bus
// format. Returns true on success.
static bool unpackMessage(
LLMessageSystem* msg,
key_t& method,
LLUUID& invoice,
sparam_t& parameters);
static bool unpackLargeMessage(
LLMessageSystem* msg,
key_t& method,
LLUUID& invoice,
sparam_t& parameters);
protected:
typedef std::map<key_t, LLDispatchHandler*> dispatch_map_t;
dispatch_map_t mHandlers;
};
#endif // LL_LLDISPATCHER_H
+36
View File
@@ -0,0 +1,36 @@
/**
* @file lleventflags.h
* @brief Flags for events.
*
* $LicenseInfo:firstyear=2004&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_LLEVENTFLAGS_H
#define LL_LLEVENTFLAGS_H
const U32 EVENT_FLAG_NONE = 0x0000;
// set for mature events
const U32 EVENT_FLAG_MATURE = 0x0001;
const U32 EVENT_FLAG_ADULT = 0x0002;
#endif
File diff suppressed because it is too large Load Diff
+184
View File
@@ -0,0 +1,184 @@
/**
* @file llexperiencecache.h
* @brief Caches information relating to experience keys
*
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2012, 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_LLEXPERIENCECACHE_H
#define LL_LLEXPERIENCECACHE_H
#include "linden_common.h"
#include "llsingleton.h"
#include "llframetimer.h"
#include "llsd.h"
#include "llcorehttputil.h"
#include <boost/signals2.hpp>
#include <boost/function.hpp>
class LLSD;
class LLUUID;
class LLExperienceCache: public LLSingleton < LLExperienceCache >
{
LLSINGLETON(LLExperienceCache);
public:
typedef boost::function<std::string(const std::string &)> CapabilityQuery_t;
typedef boost::function<void(const LLSD &)> ExperienceGetFn_t;
void setCapabilityQuery(CapabilityQuery_t queryfn);
void cleanup();
//-------------------------------------------
// Cache methods
void erase(const LLUUID& key);
bool fetch(const LLUUID& key, bool refresh = false);
void insert(const LLSD& experience_data);
const LLSD& get(const LLUUID& key);
void get(const LLUUID& key, ExperienceGetFn_t slot); // If name information is in cache, callback will be called immediately.
bool isRequestPending(const LLUUID& public_key);
//-------------------------------------------
void fetchAssociatedExperience(const LLUUID& objectId, const LLUUID& itemId, ExperienceGetFn_t fn);
void fetchAssociatedExperience(const LLUUID& objectId, const LLUUID& itemId, std::string url, ExperienceGetFn_t fn);
void findExperienceByName(const std::string text, int page, ExperienceGetFn_t fn);
void getGroupExperiences(const LLUUID &groupId, ExperienceGetFn_t fn);
// the Get/Set Region Experiences take a CapabilityQuery to get the capability since
// the region being queried may not be the region that the agent is standing on.
void getRegionExperiences(CapabilityQuery_t regioncaps, ExperienceGetFn_t fn);
void setRegionExperiences(CapabilityQuery_t regioncaps, const LLSD &experiences, ExperienceGetFn_t fn);
void getExperiencePermission(const LLUUID &experienceId, ExperienceGetFn_t fn);
void setExperiencePermission(const LLUUID &experienceId, const std::string &permission, ExperienceGetFn_t fn);
void forgetExperiencePermission(const LLUUID &experienceId, ExperienceGetFn_t fn);
void getExperienceAdmin(const LLUUID &experienceId, ExperienceGetFn_t fn);
void updateExperience(LLSD updateData, ExperienceGetFn_t fn);
//-------------------------------------------
static const std::string NAME; // "name"
static const std::string EXPERIENCE_ID; // "public_id"
static const std::string AGENT_ID; // "agent_id"
static const std::string GROUP_ID; // "group_id"
static const std::string PROPERTIES; // "properties"
static const std::string EXPIRES; // "expiration"
static const std::string DESCRIPTION; // "description"
static const std::string QUOTA; // "quota"
static const std::string MATURITY; // "maturity"
static const std::string METADATA; // "extended_metadata"
static const std::string SLURL; // "slurl"
static const std::string MISSING; // "DoesNotExist"
// should be in sync with experience-api/experiences/models.py
static const int PROPERTY_INVALID; // 1 << 0
static const int PROPERTY_PRIVILEGED; // 1 << 3
static const int PROPERTY_GRID; // 1 << 4
static const int PROPERTY_PRIVATE; // 1 << 5
static const int PROPERTY_DISABLED; // 1 << 6
static const int PROPERTY_SUSPENDED; // 1 << 7
private:
virtual ~LLExperienceCache();
virtual void initSingleton() override;
typedef boost::function<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &, LLCore::HttpRequest::ptr_t, std::string)> permissionInvoker_fn;
// Callback types for get()
typedef boost::signals2::signal < void(const LLSD &) > callback_signal_t;
typedef std::shared_ptr<callback_signal_t> signal_ptr;
// May have multiple callbacks for a single ID, which are
// represented as multiple slots bound to the signal.
// Avoid copying signals via pointers.
typedef std::map<LLUUID, signal_ptr> signal_map_t;
typedef std::map<LLUUID, LLSD> cache_t;
typedef std::set<LLUUID> RequestQueue_t;
typedef std::map<LLUUID, F64> PendingQueue_t;
//--------------------------------------------
static const std::string PRIVATE_KEY; // "private_id"
// default values
static const F64 DEFAULT_EXPIRATION; // 600.0
static const S32 DEFAULT_QUOTA; // 128 this is megabytes
static const int SEARCH_PAGE_SIZE;
//--------------------------------------------
void processExperience(const LLUUID& public_key, const LLSD& experience);
//--------------------------------------------
cache_t mCache;
signal_map_t mSignalMap;
RequestQueue_t mRequestQueue;
PendingQueue_t mPendingQueue;
LLFrameTimer mEraseExpiredTimer; // Periodically clean out expired entries from the cache
CapabilityQuery_t mCapability;
std::string mCacheFileName;
static bool sShutdown; // control for coroutines, they exist out of LLExperienceCache's scope, so they need a static control
void idleCoro();
void eraseExpired();
void requestExperiencesCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &, std::string, RequestQueue_t);
void requestExperiences();
void fetchAssociatedExperienceCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &, LLUUID, LLUUID, std::string, ExperienceGetFn_t);
void findExperienceByNameCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &, std::string, int, ExperienceGetFn_t);
void getGroupExperiencesCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &, LLUUID , ExperienceGetFn_t);
void regionExperiencesCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter, CapabilityQuery_t regioncaps, bool update, LLSD experiences, ExperienceGetFn_t fn);
void experiencePermissionCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter, permissionInvoker_fn invokerfn, std::string url, ExperienceGetFn_t fn);
void getExperienceAdminCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter, LLUUID experienceId, ExperienceGetFn_t fn);
void updateExperienceCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter, LLSD updateData, ExperienceGetFn_t fn);
void bootstrap(const LLSD& legacyKeys, int initialExpiration);
void exportFile(std::ostream& ostr) const;
void importFile(std::istream& istr);
//
const cache_t& getCached();
// maps an experience private key to the experience id
LLUUID getExperienceId(const LLUUID& private_key, bool null_if_not_found=false);
//=====================================================================
inline friend std::ostream &operator << (std::ostream &os, const LLExperienceCache &cache)
{
cache.exportFile(os);
return os;
}
inline friend std::istream &operator >> (std::istream &is, LLExperienceCache &cache)
{
cache.importFile(is);
return is;
}
};
#endif // LL_LLEXPERIENCECACHE_H
+63
View File
@@ -0,0 +1,63 @@
/**
* @file llextendedstatus.h
* @date August 2007
* @brief extended status codes for curl/resident asset storage and delivery
*
* $LicenseInfo:firstyear=2007&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_LLEXTENDEDSTATUS_H
#define LL_LLEXTENDEDSTATUS_H
enum class LLExtStat: uint32_t
{
// Status provider groups - Top bits indicate which status type it is
// Zero is common status code (next section)
CURL_RESULT = 1UL<<30, // serviced by curl - use 1L if we really implement the below
RES_RESULT = 2UL<<30, // serviced by resident copy
CACHE_RESULT = 3UL<<30, // serviced by cache
// Common Status Codes
//
NONE = 0x00000, // No extra info here - sorry!
NULL_UUID = 0x10001, // null asset ID
NO_UPSTREAM = 0x10002, // attempt to upload without a valid upstream method/provider
REQUEST_DROPPED = 0x10003, // request was dropped unserviced
NONEXISTENT_FILE= 0x10004, // trying to upload a file that doesn't exist
BLOCKED_FILE = 0x10005, // trying to upload a file that we can't open
// curl status codes:
//
// Mask off CURL_RESULT for original result and
// see: libraries/include/curl/curl.h
// Memory-Resident status codes:
// None at present
// CACHE status codes:
CACHE_CACHED = CACHE_RESULT | 0x0001,
CACHE_CORRUPT = CACHE_RESULT | 0x0002,
};
#endif // LL_LLEXTENDEDSTATUS_H
+61
View File
@@ -0,0 +1,61 @@
/**
* @file llfollowcamparams.h
* @brief Follow camera parameters.
*
* $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_FOLLOWCAM_PARAMS_H
#define LL_FOLLOWCAM_PARAMS_H
//Ventrella Follow Cam Script Stuff
enum EFollowCamAttributes {
FOLLOWCAM_PITCH = 0,
FOLLOWCAM_FOCUS_OFFSET,
FOLLOWCAM_FOCUS_OFFSET_X, //this HAS to come after FOLLOWCAM_FOCUS_OFFSET in this list
FOLLOWCAM_FOCUS_OFFSET_Y,
FOLLOWCAM_FOCUS_OFFSET_Z,
FOLLOWCAM_POSITION_LAG,
FOLLOWCAM_FOCUS_LAG,
FOLLOWCAM_DISTANCE,
FOLLOWCAM_BEHINDNESS_ANGLE,
FOLLOWCAM_BEHINDNESS_LAG,
FOLLOWCAM_POSITION_THRESHOLD,
FOLLOWCAM_FOCUS_THRESHOLD,
FOLLOWCAM_ACTIVE,
FOLLOWCAM_POSITION,
FOLLOWCAM_POSITION_X, //this HAS to come after FOLLOWCAM_POSITION in this list
FOLLOWCAM_POSITION_Y,
FOLLOWCAM_POSITION_Z,
FOLLOWCAM_FOCUS,
FOLLOWCAM_FOCUS_X, //this HAS to come after FOLLOWCAM_FOCUS in this list
FOLLOWCAM_FOCUS_Y,
FOLLOWCAM_FOCUS_Z,
FOLLOWCAM_POSITION_LOCKED,
FOLLOWCAM_FOCUS_LOCKED,
NUM_FOLLOWCAM_ATTRIBUTES
};
//end Ventrella
#endif //FOLLOWCAM_PARAMS_H
@@ -0,0 +1,72 @@
/**
* @file llgenericstreamingmessage.cpp
* @brief Generic Streaming Message helpers. Shared between viewer and simulator.
*
* $LicenseInfo:firstyear=2023&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2023, 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 "llgenericstreamingmessage.h"
#include "message.h"
void LLGenericStreamingMessage::send(LLMessageSystem* msg)
{
#if 0 // viewer cannot send GenericStreamingMessage
msg->newMessageFast(_PREHASH_GenericStreamingMessage);
if (mData.size() < 1024 * 7)
{ // disable warning about big messages unless we're sending a REALLY big message
msg->tempDisableWarnAboutBigMessage();
}
else
{
LL_WARNS("Messaging") << "Attempted to send too large GenericStreamingMessage, dropping." << LL_ENDL;
return;
}
msg->nextBlockFast(_PREHASH_MethodData);
msg->addU16Fast(_PREHASH_Method, mMethod);
msg->nextBlockFast(_PREHASH_DataBlock);
msg->addStringFast(_PREHASH_Data, mData.c_str());
#endif
}
void LLGenericStreamingMessage::unpack(LLMessageSystem* msg)
{
U16* m = (U16*)&mMethod; // squirrely pass enum as U16 by reference
msg->getU16Fast(_PREHASH_MethodData, _PREHASH_Method, *m);
constexpr int MAX_SIZE = 7 * 1024;
char buffer[MAX_SIZE];
// NOTE: don't use getStringFast to avoid 1200 byte truncation
U32 size = msg->getSizeFast(_PREHASH_DataBlock, _PREHASH_Data);
msg->getBinaryDataFast(_PREHASH_DataBlock, _PREHASH_Data, buffer, size, 0, MAX_SIZE);
mData.assign(buffer, size);
}
@@ -0,0 +1,50 @@
/**
* @file llgenericstreamingmessage.h
* @brief Generic Streaming Message helpers. Shared between viewer and simulator.
*
* $LicenseInfo:firstyear=2023&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2023, 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$
*/
#pragma once
#include <string>
#include "stdtypes.h"
class LLMessageSystem;
class LLGenericStreamingMessage
{
public:
enum Method : U16
{
METHOD_GLTF_MATERIAL_OVERRIDE = 0x4175,
METHOD_UNKNOWN = 0xFFFF,
};
void send(LLMessageSystem* msg);
void unpack(LLMessageSystem* msg);
Method mMethod = METHOD_UNKNOWN;
std::string mData;
};
+175
View File
@@ -0,0 +1,175 @@
/**
* @file llhost.cpp
* @brief Encapsulates an IP address and a port.
*
* $LicenseInfo:firstyear=2000&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 "llhost.h"
#include "llerror.h"
#if LL_WINDOWS
#include <llwin32headers.h>
#else
#include <netdb.h>
#include <netinet/in.h> // ntonl()
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#endif
LLHost::LLHost(const std::string& ip_and_port)
{
std::string::size_type colon_index = ip_and_port.find(":");
if (colon_index == std::string::npos)
{
mIP = ip_string_to_u32(ip_and_port.c_str());
mPort = 0;
}
else
{
std::string ip_str(ip_and_port, 0, colon_index);
std::string port_str(ip_and_port, colon_index+1);
mIP = ip_string_to_u32(ip_str.c_str());
mPort = atol(port_str.c_str());
}
}
std::string LLHost::getString() const
{
return llformat("%s:%u", u32_to_ip_string(mIP), mPort);
}
std::string LLHost::getIPandPort() const
{
return getString();
}
std::string LLHost::getIPString() const
{
return std::string( u32_to_ip_string( mIP ) );
}
std::string LLHost::getHostName() const
{
hostent* he;
if (INVALID_HOST_IP_ADDRESS == mIP)
{
LL_WARNS() << "LLHost::getHostName() : Invalid IP address" << LL_ENDL;
return std::string();
}
he = gethostbyaddr((char *)&mIP, sizeof(mIP), AF_INET);
if (!he)
{
#if LL_WINDOWS
LL_WARNS() << "LLHost::getHostName() : Couldn't find host name for address " << mIP << ", Error: "
<< WSAGetLastError() << LL_ENDL;
#else
LL_WARNS() << "LLHost::getHostName() : Couldn't find host name for address " << mIP << ", Error: "
<< h_errno << LL_ENDL;
#endif
return std::string();
}
else
{
return ll_safe_string(he->h_name);
}
}
bool LLHost::setHostByName(const std::string& hostname)
{
hostent *he;
std::string local_name(hostname);
#if LL_WINDOWS
// We may need an equivalent for Linux, but not sure - djs
LLStringUtil::toUpper(local_name);
#endif
he = gethostbyname(local_name.c_str());
if(!he)
{
U32 ip_address = ip_string_to_u32(hostname.c_str());
he = gethostbyaddr((char *)&ip_address, sizeof(ip_address), AF_INET);
}
if (he)
{
mIP = *(U32 *)he->h_addr_list[0];
return true;
}
else
{
setAddress(local_name);
// In windows, h_errno is a macro for WSAGetLastError(), so store value here
S32 error_number = h_errno;
switch(error_number)
{
case TRY_AGAIN: // XXX how to handle this case?
LL_WARNS() << "LLHost::setAddress(): try again" << LL_ENDL;
break;
case HOST_NOT_FOUND:
case NO_ADDRESS: // NO_DATA
LL_WARNS() << "LLHost::setAddress(): host not found" << LL_ENDL;
break;
case NO_RECOVERY:
LL_WARNS() << "LLHost::setAddress(): unrecoverable error" << LL_ENDL;
break;
default:
LL_WARNS() << "LLHost::setAddress(): unknown error - " << error_number << LL_ENDL;
break;
}
return false;
}
}
LLHost& LLHost::operator=(const LLHost &rhs)
{
if (this != &rhs)
{
set(rhs.getAddress(), rhs.getPort());
}
return *this;
}
std::ostream& operator<< (std::ostream& os, const LLHost &hh)
{
os << u32_to_ip_string(hh.mIP) << ":" << hh.mPort ;
return os;
}
//std::istream& operator>> (std::istream& is, LLHost &rh)
//{
// is >> rh.mIP;
// is >> rh.mPort;
// return is;
//}
+154
View File
@@ -0,0 +1,154 @@
/**
* @file llhost.h
* @brief a LLHost uniquely defines a host (Simulator, Proxy or other)
* across the network
*
* $LicenseInfo:firstyear=2000&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_LLHOST_H
#define LL_LLHOST_H
#include <iostream>
#include <string>
#include "net.h"
const U32 INVALID_PORT = 0;
const U32 INVALID_HOST_IP_ADDRESS = 0x0;
class LLHost {
protected:
U32 mPort;
U32 mIP;
std::string mUntrustedSimCap;
public:
// CREATORS
LLHost()
: mPort(INVALID_PORT),
mIP(INVALID_HOST_IP_ADDRESS)
{ } // STL's hash_map expect this T()
LLHost( U32 ipv4_addr, U32 port )
: mPort( port )
{
mIP = ipv4_addr;
}
LLHost( const std::string& ipv4_addr, U32 port )
: mPort( port )
{
mIP = ip_string_to_u32(ipv4_addr.c_str());
}
explicit LLHost(const U64 ip_port)
{
U32 ip = (U32)(ip_port >> 32);
U32 port = (U32)(ip_port & (U64)0xFFFFFFFF);
mIP = ip;
mPort = port;
}
explicit LLHost(const std::string& ip_and_port);
~LLHost()
{ }
// MANIPULATORS
void set( U32 ip, U32 port ) { mIP = ip; mPort = port; }
void set( const std::string& ipstr, U32 port ) { mIP = ip_string_to_u32(ipstr.c_str()); mPort = port; }
void setAddress( const std::string& ipstr ) { mIP = ip_string_to_u32(ipstr.c_str()); }
void setAddress( U32 ip ) { mIP = ip; }
void setPort( U32 port ) { mPort = port; }
bool setHostByName(const std::string& hname);
LLHost& operator=(const LLHost &rhs);
void invalidate() { mIP = INVALID_HOST_IP_ADDRESS; mPort = INVALID_PORT;};
// READERS
U32 getAddress() const { return mIP; }
U32 getPort() const { return mPort; }
bool isOk() const { return (mIP != INVALID_HOST_IP_ADDRESS) && (mPort != INVALID_PORT); }
bool isInvalid() { return (mIP == INVALID_HOST_IP_ADDRESS) || (mPort == INVALID_PORT); }
size_t hash() const { return (mIP << 16) | (mPort & 0xffff); }
std::string getString() const;
std::string getIPString() const;
std::string getHostName() const;
std::string getIPandPort() const;
std::string getUntrustedSimulatorCap() const { return mUntrustedSimCap; }
void setUntrustedSimulatorCap(const std::string &capurl) { mUntrustedSimCap = capurl; }
friend std::ostream& operator<< (std::ostream& os, const LLHost &hh);
// This operator is not well defined. does it expect a
// "192.168.1.1:80" notation or "int int" format? Phoenix 2007-05-18
//friend std::istream& operator>> (std::istream& is, LLHost &hh);
friend bool operator==( const LLHost &lhs, const LLHost &rhs );
friend bool operator!=( const LLHost &lhs, const LLHost &rhs );
friend bool operator<(const LLHost &lhs, const LLHost &rhs);
};
// Function Object required for STL templates using LLHost as key
class LLHostHash
{
public:
size_t operator() (const LLHost &hh) const { return hh.hash(); }
};
inline bool operator==( const LLHost &lhs, const LLHost &rhs )
{
return (lhs.mIP == rhs.mIP) && (lhs.mPort == rhs.mPort);
}
inline bool operator!=( const LLHost &lhs, const LLHost &rhs )
{
return (lhs.mIP != rhs.mIP) || (lhs.mPort != rhs.mPort);
}
inline bool operator<(const LLHost &lhs, const LLHost &rhs)
{
if (lhs.mIP < rhs.mIP)
{
return true;
}
if (lhs.mIP > rhs.mIP)
{
return false;
}
if (lhs.mPort < rhs.mPort)
{
return true;
}
else
{
return false;
}
}
#endif // LL_LLHOST_H
+513
View File
@@ -0,0 +1,513 @@
/**
* @file llhttpnode.cpp
* @brief Implementation of classes for generic HTTP/LSL/REST handling.
*
* $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
* 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 "llhttpnode.h"
#include <boost/tokenizer.hpp>
#include "llstl.h"
#include "llhttpconstants.h"
#include "llexception.h"
const std::string CONTEXT_HEADERS("headers");
const std::string CONTEXT_PATH("path");
const std::string CONTEXT_QUERY_STRING("query-string");
const std::string CONTEXT_REQUEST("request");
const std::string CONTEXT_RESPONSE("response");
const std::string CONTEXT_VERB("verb");
const std::string CONTEXT_WILDCARD("wildcard");
/**
* LLHTTPNode
*/
class LLHTTPNode::Impl
{
public:
typedef std::map<std::string, LLHTTPNode*> ChildMap;
ChildMap mNamedChildren;
LLHTTPNode* mWildcardChild;
std::string mWildcardName;
std::string mWildcardKey;
LLHTTPNode* mParentNode;
Impl() : mWildcardChild(NULL), mParentNode(NULL) { }
LLHTTPNode* findNamedChild(const std::string& name) const;
};
LLHTTPNode* LLHTTPNode::Impl::findNamedChild(const std::string& name) const
{
LLHTTPNode* child = get_ptr_in_map(mNamedChildren, name);
if (!child && ((name[0] == '*') || (name == mWildcardName)))
{
child = mWildcardChild;
}
return child;
}
LLHTTPNode::LLHTTPNode()
: impl(* new Impl)
{
}
// virtual
LLHTTPNode::~LLHTTPNode()
{
std::for_each(impl.mNamedChildren.begin(), impl.mNamedChildren.end(), DeletePairedPointer());
impl.mNamedChildren.clear();
delete impl.mWildcardChild;
delete &impl;
}
namespace {
struct NotImplemented: public LLException
{
NotImplemented(): LLException("LLHTTPNode::NotImplemented") {}
};
}
// virtual
LLSD LLHTTPNode::simpleGet() const
{
LLTHROW(NotImplemented());
}
// virtual
LLSD LLHTTPNode::simplePut(const LLSD& input) const
{
LLTHROW(NotImplemented());
}
// virtual
LLSD LLHTTPNode::simplePost(const LLSD& input) const
{
LLTHROW(NotImplemented());
}
// virtual
void LLHTTPNode::get(LLHTTPNode::ResponsePtr response, const LLSD& context) const
{
LL_PROFILE_ZONE_SCOPED;
try
{
response->result(simpleGet());
}
catch (NotImplemented&)
{
response->methodNotAllowed();
}
}
// virtual
void LLHTTPNode::put(LLHTTPNode::ResponsePtr response, const LLSD& context, const LLSD& input) const
{
LL_PROFILE_ZONE_SCOPED;
try
{
response->result(simplePut(input));
}
catch (NotImplemented&)
{
response->methodNotAllowed();
}
}
// virtual
void LLHTTPNode::post(LLHTTPNode::ResponsePtr response, const LLSD& context, const LLSD& input) const
{
LL_PROFILE_ZONE_SCOPED;
try
{
response->result(simplePost(input));
}
catch (NotImplemented&)
{
response->methodNotAllowed();
}
}
// virtual
void LLHTTPNode::del(LLHTTPNode::ResponsePtr response, const LLSD& context) const
{
LL_PROFILE_ZONE_SCOPED;
try
{
response->result(simpleDel(context));
}
catch (NotImplemented&)
{
response->methodNotAllowed();
}
}
// virtual
LLSD LLHTTPNode::simpleDel(const LLSD&) const
{
LLTHROW(NotImplemented());
}
// virtual
void LLHTTPNode::options(ResponsePtr response, const LLSD& context) const
{
//LL_INFOS() << "options context: " << context << LL_ENDL;
LL_DEBUGS("LLHTTPNode") << "context: " << context << LL_ENDL;
// default implementation constructs an url to the documentation.
// *TODO: Check for 'Host' header instead of 'host' header?
std::string host(
context[CONTEXT_REQUEST][CONTEXT_HEADERS][HTTP_IN_HEADER_HOST].asString());
if(host.empty())
{
response->status(HTTP_BAD_REQUEST, "Bad Request -- need Host header");
return;
}
std::ostringstream ostr;
ostr << "http://" << host << "/web/server/api";
ostr << context[CONTEXT_REQUEST][CONTEXT_PATH].asString();
static const std::string DOC_HEADER("X-Documentation-URL");
response->addHeader(DOC_HEADER, ostr.str());
response->status(HTTP_OK, "OK");
}
// virtual
LLHTTPNode* LLHTTPNode::getChild(const std::string& name, LLSD& context) const
{
LLHTTPNode* namedChild = get_ptr_in_map(impl.mNamedChildren, name);
if (namedChild)
{
return namedChild;
}
if (impl.mWildcardChild
&& impl.mWildcardChild->validate(name, context))
{
context[CONTEXT_REQUEST][CONTEXT_WILDCARD][impl.mWildcardKey] = name;
return impl.mWildcardChild;
}
return NULL;
}
// virtual
bool LLHTTPNode::handles(const LLSD& remainder, LLSD& context) const
{
return remainder.size() == 0;
}
// virtual
bool LLHTTPNode::validate(const std::string& name, LLSD& context) const
{
return false;
}
const LLHTTPNode* LLHTTPNode::traverse(
const std::string& path, LLSD& context) const
{
typedef boost::tokenizer< boost::char_separator<char> > tokenizer;
boost::char_separator<char> sep("/", "", boost::drop_empty_tokens);
tokenizer tokens(path, sep);
tokenizer::iterator iter = tokens.begin();
tokenizer::iterator end = tokens.end();
const LLHTTPNode* node = this;
for(; iter != end; ++iter)
{
LLHTTPNode* child = node->getChild(*iter, context);
if(!child)
{
LL_DEBUGS() << "LLHTTPNode::traverse: Couldn't find '" << *iter << "'" << LL_ENDL;
break;
}
LL_DEBUGS() << "LLHTTPNode::traverse: Found '" << *iter << "'" << LL_ENDL;
node = child;
}
LLSD& remainder = context[CONTEXT_REQUEST]["remainder"];
for(; iter != end; ++iter)
{
remainder.append(*iter);
}
return node->handles(remainder, context) ? node : NULL;
}
void LLHTTPNode::addNode(const std::string& path, LLHTTPNode* nodeToAdd)
{
typedef boost::tokenizer< boost::char_separator<char> > tokenizer;
boost::char_separator<char> sep("/", "", boost::drop_empty_tokens);
tokenizer tokens(path, sep);
tokenizer::iterator iter = tokens.begin();
tokenizer::iterator end = tokens.end();
LLHTTPNode* node = this;
for(; iter != end; ++iter)
{
LLHTTPNode* child = node->impl.findNamedChild(*iter);
if (!child) { break; }
node = child;
}
if (iter == end)
{
LL_WARNS() << "LLHTTPNode::addNode: already a node that handles "
<< path << LL_ENDL;
return;
}
while (true)
{
std::string pathPart = *iter;
++iter;
bool lastOne = iter == end;
LLHTTPNode* nextNode = lastOne ? nodeToAdd : new LLHTTPNode();
switch (pathPart[0])
{
case '<':
// *NOTE: This should really validate that it is of
// the proper form: <wildcardkey> so that the substr()
// generates the correct key name.
node->impl.mWildcardChild = nextNode;
node->impl.mWildcardName = pathPart;
if(node->impl.mWildcardKey.empty())
{
node->impl.mWildcardKey = pathPart.substr(
1,
pathPart.size() - 2);
}
break;
case '*':
node->impl.mWildcardChild = nextNode;
if(node->impl.mWildcardName.empty())
{
node->impl.mWildcardName = pathPart;
}
break;
default:
node->impl.mNamedChildren[pathPart] = nextNode;
}
nextNode->impl.mParentNode = node;
if (lastOne) break;
node = nextNode;
}
}
static void append_node_paths(LLSD& result,
const std::string& name, const LLHTTPNode* node)
{
result.append(name);
LLSD paths = node->allNodePaths();
LLSD::array_const_iterator i = paths.beginArray();
LLSD::array_const_iterator end = paths.endArray();
for (; i != end; ++i)
{
result.append(name + "/" + (*i).asString());
}
}
LLSD LLHTTPNode::allNodePaths() const
{
LLSD result;
Impl::ChildMap::const_iterator i = impl.mNamedChildren.begin();
Impl::ChildMap::const_iterator end = impl.mNamedChildren.end();
for (; i != end; ++i)
{
append_node_paths(result, i->first, i->second);
}
if (impl.mWildcardChild)
{
append_node_paths(result, impl.mWildcardName, impl.mWildcardChild);
}
return result;
}
const LLHTTPNode* LLHTTPNode::rootNode() const
{
const LLHTTPNode* node = this;
while (true)
{
const LLHTTPNode* next = node->impl.mParentNode;
if (!next)
{
return node;
}
node = next;
}
}
const LLHTTPNode* LLHTTPNode::findNode(const std::string& name) const
{
return impl.findNamedChild(name);
}
LLHTTPNode::Response::~Response()
{
}
void LLHTTPNode::Response::statusUnknownError(S32 code)
{
status(code, "Unknown Error");
}
void LLHTTPNode::Response::notFound(const std::string& message)
{
status(HTTP_NOT_FOUND, message);
}
void LLHTTPNode::Response::notFound()
{
status(HTTP_NOT_FOUND, "Not Found");
}
void LLHTTPNode::Response::methodNotAllowed()
{
status(HTTP_METHOD_NOT_ALLOWED, "Method Not Allowed");
}
void LLHTTPNode::Response::addHeader(
const std::string& name,
const std::string& value)
{
mHeaders[name] = value;
}
void LLHTTPNode::describe(Description& desc) const
{
desc.shortInfo("unknown service (missing describe() method)");
}
const LLChainIOFactory* LLHTTPNode::getProtocolHandler() const
{
return NULL;
}
namespace
{
typedef std::map<std::string, LLHTTPRegistrar::NodeFactory*> FactoryMap;
FactoryMap& factoryMap()
{
static FactoryMap theMap;
return theMap;
}
}
LLHTTPRegistrar::NodeFactory::~NodeFactory() { }
void LLHTTPRegistrar::registerFactory(
const std::string& path, NodeFactory& factory)
{
factoryMap()[path] = &factory;
}
void LLHTTPRegistrar::buildAllServices(LLHTTPNode& root)
{
const FactoryMap& map = factoryMap();
FactoryMap::const_iterator i = map.begin();
FactoryMap::const_iterator end = map.end();
for (; i != end; ++i)
{
LL_DEBUGS("AppInit") << "LLHTTPRegistrar::buildAllServices adding node for path "
<< i->first << LL_ENDL;
root.addNode(i->first, i->second->build());
}
}
LLPointer<LLSimpleResponse> LLSimpleResponse::create()
{
return new LLSimpleResponse();
}
LLSimpleResponse::~LLSimpleResponse()
{
}
void LLSimpleResponse::result(const LLSD& result)
{
status(HTTP_OK, "OK");
}
void LLSimpleResponse::extendedResult(S32 code, const std::string& body, const LLSD& headers)
{
status(code,body);
}
void LLSimpleResponse::extendedResult(S32 code, const LLSD& r, const LLSD& headers)
{
status(code,"(LLSD)");
}
void LLSimpleResponse::status(S32 code, const std::string& message)
{
mCode = code;
mMessage = message;
}
void LLSimpleResponse::print(std::ostream& out) const
{
out << mCode << " " << mMessage;
}
std::ostream& operator<<(std::ostream& out, const LLSimpleResponse& resp)
{
resp.print(out);
return out;
}
+407
View File
@@ -0,0 +1,407 @@
/**
* @file llhttpnode.h
* @brief Declaration of classes for generic HTTP/LSL/REST handling.
*
* $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
* 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_LLHTTPNODE_H
#define LL_LLHTTPNODE_H
#include "llpointer.h"
#include "llrefcount.h"
#include "llsd.h"
// common strings use for populating the context. basically 'request',
// 'wildcard', and 'headers'.
extern const std::string CONTEXT_HEADERS;
extern const std::string CONTEXT_PATH;
extern const std::string CONTEXT_QUERY_STRING;
extern const std::string CONTEXT_REQUEST;
extern const std::string CONTEXT_RESPONSE;
extern const std::string CONTEXT_VERB;
extern const std::string CONTEXT_WILDCARD;
class LLChainIOFactory;
/**
* These classes represent the HTTP framework: The URL tree, and the LLSD
* REST interface that such nodes implement.
*
* To implement a service, in most cases, subclass LLHTTPNode, implement
* get() or post(), and create a global instance of LLHTTPRegistration<>.
* This can all be done in a .cpp file, with no publically declared parts.
*
* To implement a server see lliohttpserver.h
* @see LLHTTPWireServer
*/
/**
* @class LLHTTPNode
* @brief Base class which handles url traversal, response routing
* and support for standard LLSD services
*
* Users of the HTTP responder will typically derive a class from this
* one, implement the get(), put() and/or post() methods, and then
* use LLHTTPRegistration to insert it into the URL tree.
*
* The default implementation handles servicing the request and creating
* the pipe fittings needed to read the headers, manage them, convert
* to and from LLSD, etc.
*/
class LLHTTPNode
{
protected:
LOG_CLASS(LLHTTPNode);
public:
LLHTTPNode();
virtual ~LLHTTPNode();
/** @name Responses
Most subclasses override one or more of these methods to provide
the service. By default, the rest of the LLHTTPNode architecture
will handle requests, create the needed LLIOPump, parse the input
to LLSD, and format the LLSD result to the output.
The default implementation of each of these is to call
response->methodNotAllowed(); The "simple" versions can be
overridden instead in those cases where the service can return
an immediately computed response.
*/
//@{
public:
virtual LLSD simpleGet() const;
virtual LLSD simplePut(const LLSD& input) const;
virtual LLSD simplePost(const LLSD& input) const;
virtual LLSD simpleDel(const LLSD& context) const;
/**
* @brief Abstract Base Class declaring Response interface.
*/
class Response : public LLRefCount
{
protected:
virtual ~Response();
public:
/**
* @brief Return the LLSD content and a 200 OK.
*/
virtual void result(const LLSD&) = 0;
/**
* @brief return status code and message with headers.
*/
virtual void extendedResult(S32 code, const std::string& message, const LLSD& headers = LLSD()) = 0;
/**
* @brief return status code and LLSD result with headers.
*/
virtual void extendedResult(S32 code, const LLSD& result, const LLSD& headers = LLSD()) = 0;
/**
* @brief return status code and reason string on http header,
* but do not return a payload.
*/
virtual void status(S32 code, const std::string& message) = 0;
/**
* @brief Return no body, just status code and 'UNKNOWN ERROR'.
*/
virtual void statusUnknownError(S32 code);
virtual void notFound(const std::string& message);
virtual void notFound();
virtual void methodNotAllowed();
/**
* @brief Add a name: value http header.
*
* No effort is made to ensure the response is a valid http
* header.
* The headers are stored as a map of header name : value.
* Though HTTP allows the same header name to be transmitted
* more than once, this implementation only stores a header
* name once.
* @param name The name of the header, eg, "Content-Encoding"
* @param value The value of the header, eg, "gzip"
*/
virtual void addHeader(const std::string& name, const std::string& value);
protected:
/**
* @brief Headers to be sent back with the HTTP response.
*
* Protected class membership since derived classes are
* expected to use it and there is no use case yet for other
* uses. If such a use case arises, I suggest making a
* headers() public method, and moving this member data into
* private.
*/
LLSD mHeaders;
};
typedef LLPointer<Response> ResponsePtr;
virtual void get(ResponsePtr, const LLSD& context) const;
virtual void put(
ResponsePtr,
const LLSD& context,
const LLSD& input) const;
virtual void post(
ResponsePtr,
const LLSD& context,
const LLSD& input) const;
virtual void del(ResponsePtr, const LLSD& context) const;
virtual void options(ResponsePtr, const LLSD& context) const;
//@}
/** @name URL traversal
The tree is traversed by calling getChild() with successive
path components, on successive results. When getChild() returns
null, or there are no more components, the last child responds to
the request.
The default behavior is generally correct, though wildcard nodes
will want to implement validate().
*/
//@{
public:
virtual LLHTTPNode* getChild(const std::string& name, LLSD& context) const;
/**< returns a child node, if any, at the given name
default looks at children and wildcard child (see below)
*/
virtual bool handles(const LLSD& remainder, LLSD& context) const;
/**< return true if this node can service the remaining components;
default returns true if there are no remaining components
*/
virtual bool validate(const std::string& name, LLSD& context) const;
/**< called only on wildcard nodes, to check if they will handle
the name; default is false; overrides will want to check
name, and return true if the name will construct to a valid url.
For convenience, the <code>getChild()</code> method above will
automatically insert the name in
context[CONTEXT_REQUEST][CONTEXT_WILDCARD][key] if this method returns true.
For example, the node "agent/<agent_id>/detail" will set
context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["agent_id"] eqaul to the value
found during traversal.
*/
const LLHTTPNode* traverse(const std::string& path, LLSD& context) const;
/**< find a node, if any, that can service this path
set up context[CONTEXT_REQUEST] information
*/
//@}
/** @name Child Nodes
The standard node can have any number of child nodes under
fixed names, and optionally one "wildcard" node that can
handle all other names.
Usually, child nodes are add through LLHTTPRegistration, not
by calling this interface directly.
The added node will be now owned by the parent node.
*/
//@{
virtual void addNode(const std::string& path, LLHTTPNode* nodeToAdd);
LLSD allNodePaths() const;
///< Returns an arrary of node paths at and under this node
const LLHTTPNode* rootNode() const;
const LLHTTPNode* findNode(const std::string& name) const;
enum EHTTPNodeContentType
{
CONTENT_TYPE_LLSD,
CONTENT_TYPE_TEXT
};
virtual EHTTPNodeContentType getContentType() const { return CONTENT_TYPE_LLSD; }
//@}
/* @name Description system
The Description object contains information about a service.
All subclasses of LLHTTPNode should override describe() and use
the methods of the Description class to set the various properties.
*/
//@{
class Description
{
public:
void shortInfo(const std::string& s){ mInfo["description"] = s; }
void longInfo(const std::string& s) { mInfo["details"] = s; }
// Call this method when the service supports the specified verb.
void getAPI() { mInfo["api"].append("GET"); }
void putAPI() { mInfo["api"].append("PUT"); }
void postAPI() { mInfo["api"].append("POST"); }
void delAPI() { mInfo["api"].append("DELETE"); }
void input(const std::string& s) { mInfo["input"] = s; }
void output(const std::string& s) { mInfo["output"] = s; }
void source(const char* f, int l) { mInfo["__file__"] = f;
mInfo["__line__"] = l; }
LLSD getInfo() const { return mInfo; }
private:
LLSD mInfo;
};
virtual void describe(Description&) const;
//@}
virtual const LLChainIOFactory* getProtocolHandler() const;
/**< Return a factory object for handling wire protocols.
* The base class returns NULL, as it doesn't know about
* wire protocols at all. This is okay for most nodes
* as LLIOHTTPServer is smart enough to use a default
* wire protocol for HTTP for such nodes. Specialized
* subclasses that handle things like XML-RPC will want
* to implement this. (See LLXMLSDRPCServerFactory.)
*/
private:
class Impl;
Impl& impl;
};
class LLSimpleResponse : public LLHTTPNode::Response
{
public:
static LLPointer<LLSimpleResponse> create();
void result(const LLSD& result);
void extendedResult(S32 code, const std::string& body, const LLSD& headers);
void extendedResult(S32 code, const LLSD& result, const LLSD& headers);
void status(S32 code, const std::string& message);
void print(std::ostream& out) const;
S32 mCode;
std::string mMessage;
protected:
~LLSimpleResponse();
private:
LLSimpleResponse() : mCode(0) {} // Must be accessed through LLPointer.
};
std::ostream& operator<<(std::ostream& out, const LLSimpleResponse& resp);
/**
* @name Automatic LLHTTPNode registration
*
* To register a node type at a particular url path, construct a global instance
* of LLHTTPRegistration:
*
* LLHTTPRegistration<LLMyNodeType> gHTTPServiceAlphaBeta("/alpha/beta");
*
* (Note the naming convention carefully.) This object must be global and not
* static. However, it needn't be declared in your .h file. It can exist
* solely in the .cpp file. The same is true of your subclass of LLHTTPNode:
* it can be declared and defined wholly within the .cpp file.
*
* When constructing a web server, use LLHTTPRegistrar to add all the registered
* nodes to the url tree:
*
* LLHTTPRegistrar::buidlAllServices(mRootNode);
*/
//@{
class LLHTTPRegistrar
{
public:
class NodeFactory
{
public:
virtual ~NodeFactory();
virtual LLHTTPNode* build() const = 0;
};
static void buildAllServices(LLHTTPNode& root);
static void registerFactory(const std::string& path, NodeFactory& factory);
///< construct an LLHTTPRegistration below to call this
};
template < class NodeType >
class LLHTTPRegistration
{
public:
LLHTTPRegistration(const std::string& path)
{
LLHTTPRegistrar::registerFactory(path, mFactory);
}
private:
class ThisNodeFactory : public LLHTTPRegistrar::NodeFactory
{
public:
virtual LLHTTPNode* build() const { return new NodeType; }
};
ThisNodeFactory mFactory;
};
template < class NodeType>
class LLHTTPParamRegistration
{
public:
LLHTTPParamRegistration(const std::string& path, LLSD params) :
mFactory(params)
{
LLHTTPRegistrar::registerFactory(path, mFactory);
}
private:
class ThisNodeFactory : public LLHTTPRegistrar::NodeFactory
{
public:
ThisNodeFactory(LLSD params) : mParams(params) {}
virtual LLHTTPNode* build() const { return new NodeType(mParams); }
private:
LLSD mParams;
};
ThisNodeFactory mFactory;
};
//@}
#endif // LL_LLHTTPNODE_H
+52
View File
@@ -0,0 +1,52 @@
/**
* @file llhttpnodeadapter.h
* @brief Declaration of llhttpnode adapter classes
*
* $LicenseInfo:firstyear=2009&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_HTTP_NODE_ADAPTER_H
#define LL_HTTP_NODE_ADAPTER_H
#include "llhttpnode.h"
template<typename T>
class LLHTTPNodeAdapter : public LLHTTPNode
{
public:
virtual bool validate(const std::string& name, LLSD& context) const
{
T node;
return node.validate(name, context);
}
virtual void post(LLHTTPNode::ResponsePtr response,
const LLSD& context,
const LLSD& input) const
{
T node;
return node.post(response, context, input);
}
};
#endif // LL_HTTP_NODE_ADAPTER_H
+77
View File
@@ -0,0 +1,77 @@
/**
* @file llhttpsdhandler.h
* @brief Public-facing declarations for the HttpHandler class
*
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2012, 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 "llhttpconstants.h"
#include "llhttpsdhandler.h"
#include "httpresponse.h"
#include "httpheaders.h"
#include "llsd.h"
#include "llsdserialize.h"
#include "bufferstream.h"
#include "llcorehttputil.h"
//========================================================================
LLHttpSDHandler::LLHttpSDHandler()
{
}
void LLHttpSDHandler::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response)
{
LLCore::HttpStatus status = response->getStatus();
if (!status)
{
this->onFailure(response, status);
}
else
{
LLSD resplsd;
const bool emit_parse_errors = false;
bool parsed = !((response->getBodySize() == 0) ||
!LLCoreHttpUtil::responseToLLSD(response, emit_parse_errors, resplsd));
if (!parsed)
{
// Only emit a warning if we failed to parse when 'content-type' == 'application/llsd+xml'
LLCore::HttpHeaders::ptr_t headers(response->getHeaders());
const std::string *contentType = (headers) ? headers->find(HTTP_IN_HEADER_CONTENT_TYPE) : NULL;
if (contentType && (HTTP_CONTENT_LLSD_XML == *contentType))
{
std::string thebody = LLCoreHttpUtil::responseToString(response);
LL_WARNS() << "Failed to deserialize . " << response->getRequestURL() << " [status:" << response->getStatus().toString() << "] "
<< " body: " << thebody << LL_ENDL;
}
}
this->onSuccess(response, resplsd);
}
}
+55
View File
@@ -0,0 +1,55 @@
/**
* @file llhttpsdhandler.h
* @brief Public-facing declarations for the HttpHandler class
*
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2012, 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 _LLHTTPSDHANDLER_H_
#define _LLHTTPSDHANDLER_H_
#include "httpcommon.h"
#include "httphandler.h"
#include "lluri.h"
/// Handler class LLCore's HTTP library. Splitting with separate success and
/// failure routines and parsing the result body into LLSD on success. It
/// is intended to be subclassed for specific capability handling.
///
// *TODO: This class self deletes at the end of onCompleted method. This is
// less than ideal and should be revisited.
class LLHttpSDHandler : public LLCore::HttpHandler //,
// public std::enable_shared_from_this<LLHttpSDHandler>
{
public:
virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response);
protected:
LLHttpSDHandler();
virtual void onSuccess(LLCore::HttpResponse * response, const LLSD &content) = 0;
virtual void onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status) = 0;
};
#endif
+167
View File
@@ -0,0 +1,167 @@
/**
* @file llinstantmessage.cpp
* @author Phoenix
* @date 2005-08-29
* @brief Constants and functions used in IM.
*
* $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 "lldbstrings.h"
#include "llinstantmessage.h"
#include "llhost.h"
#include "lluuid.h"
#include "llsd.h"
#include "llsdserialize.h"
#include "llsdutil_math.h"
#include "llpointer.h"
#include "message.h"
#include "message.h"
const U8 IM_ONLINE = 0;
const U8 IM_OFFLINE = 1;
const char EMPTY_BINARY_BUCKET[] = "";
const S32 EMPTY_BINARY_BUCKET_SIZE = 1;
const U32 NO_TIMESTAMP = 0;
// <FS:CR> Aurora Sim
//const std::string SYSTEM_FROM("Second Life");
std::string SYSTEM_FROM("Second Life");
// </FS:CR> Aurora Sim
const std::string INTERACTIVE_SYSTEM_FROM("F387446C-37C4-45f2-A438-D99CBDBB563B");
const S32 IM_TTL = 1;
void pack_instant_message(
LLMessageSystem* msg,
const LLUUID& from_id,
bool from_group,
const LLUUID& session_id,
const LLUUID& to_id,
const std::string& name,
const std::string& message,
U8 offline,
EInstantMessage dialog,
const LLUUID& id,
U32 parent_estate_id,
const LLUUID& region_id,
const LLVector3& position,
U32 timestamp,
const U8* binary_bucket,
S32 binary_bucket_size)
{
LL_DEBUGS() << "pack_instant_message()" << LL_ENDL;
msg->newMessageFast(_PREHASH_ImprovedInstantMessage);
pack_instant_message_block(
msg,
from_id,
from_group,
session_id,
to_id,
name,
message,
offline,
dialog,
id,
parent_estate_id,
region_id,
position,
timestamp,
binary_bucket,
binary_bucket_size);
}
void pack_instant_message_block(
LLMessageSystem* msg,
const LLUUID& from_id,
bool from_group,
const LLUUID& session_id,
const LLUUID& to_id,
const std::string& name,
const std::string& message,
U8 offline,
EInstantMessage dialog,
const LLUUID& id,
U32 parent_estate_id,
const LLUUID& region_id,
const LLVector3& position,
U32 timestamp,
const U8* binary_bucket,
S32 binary_bucket_size)
{
msg->nextBlockFast(_PREHASH_AgentData);
msg->addUUIDFast(_PREHASH_AgentID, from_id);
msg->addUUIDFast(_PREHASH_SessionID, session_id);
msg->nextBlockFast(_PREHASH_MessageBlock);
msg->addBOOLFast(_PREHASH_FromGroup, from_group);
msg->addUUIDFast(_PREHASH_ToAgentID, to_id);
msg->addU32Fast(_PREHASH_ParentEstateID, parent_estate_id);
msg->addUUIDFast(_PREHASH_RegionID, region_id);
msg->addVector3Fast(_PREHASH_Position, position);
msg->addU8Fast(_PREHASH_Offline, offline);
msg->addU8Fast(_PREHASH_Dialog, (U8) dialog);
msg->addUUIDFast(_PREHASH_ID, id);
msg->addU32Fast(_PREHASH_Timestamp, timestamp);
msg->addStringFast(_PREHASH_FromAgentName, name);
S32 bytes_left = MTUBYTES;
if(!message.empty())
{
char buffer[MTUBYTES];
int num_written = snprintf(buffer, MTUBYTES, "%s", message.c_str()); /* Flawfinder: ignore */
// snprintf returns number of bytes that would have been written
// had the output not being truncated. In that case, it will
// return either -1 or value >= passed in size value . So a check needs to be added
// to detect truncation, and if there is any, only account for the
// actual number of bytes written..and not what could have been
// written.
if (num_written < 0 || num_written >= MTUBYTES)
{
num_written = MTUBYTES - 1;
LL_WARNS() << "pack_instant_message_block: message truncated: " << message << LL_ENDL;
}
bytes_left -= num_written;
bytes_left = llmax(0, bytes_left);
msg->addStringFast(_PREHASH_Message, buffer);
}
else
{
msg->addStringFast(_PREHASH_Message, NULL);
}
const U8* bb;
if(binary_bucket)
{
bb = binary_bucket;
binary_bucket_size = llmin(bytes_left, binary_bucket_size);
}
else
{
bb = (const U8*)EMPTY_BINARY_BUCKET;
binary_bucket_size = EMPTY_BINARY_BUCKET_SIZE;
}
msg->addBinaryDataFast(_PREHASH_BinaryBucket, bb, binary_bucket_size);
}
+221
View File
@@ -0,0 +1,221 @@
/**
* @file llinstantmessage.h
* @brief Constants and declarations used by instant messages.
*
* $LicenseInfo:firstyear=2002&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_LLINSTANTMESSAGE_H
#define LL_LLINSTANTMESSAGE_H
#include "llhost.h"
#include "lluuid.h"
#include "llsd.h"
#include "llrefcount.h"
#include "llpointer.h"
#include "v3math.h"
class LLMessageSystem;
// The ImprovedInstantMessage only supports 8 bits in the "Dialog"
// field, so don't go past the byte boundary
enum EInstantMessage
{
// default. ID is meaningless, nothing in the binary bucket.
IM_NOTHING_SPECIAL = 0,
// pops a messagebox with a single OK button
IM_MESSAGEBOX = 1,
// pops a countdown messagebox with a single OK button
// IM_MESSAGEBOX_COUNTDOWN = 2,
// You've been invited to join a group.
// ID is the group id.
// The binary bucket contains a null terminated string
// representation of the officer/member status and join cost for
// the invitee. (bug # 7672) The format is 1 byte for
// officer/member (O for officer, M for member), and as many bytes
// as necessary for cost.
IM_GROUP_INVITATION = 3,
// Inventory offer.
// ID is the transaction id
// Binary bucket is a list of inventory uuid and type.
IM_INVENTORY_OFFERED = 4,
IM_INVENTORY_ACCEPTED = 5,
IM_INVENTORY_DECLINED = 6,
// Group vote
// Name is name of person who called vote.
// ID is vote ID used for internal tracking
// TODO: _DEPRECATED suffix as part of vote removal - DEV-24856
IM_GROUP_VOTE = 7,
// Group message
// This means that the message is meant for everyone in the
// agent's group. This will result in a database query to find all
// participants and start an im session.
IM_GROUP_MESSAGE_DEPRECATED = 8,
// Task inventory offer.
// ID is the transaction id
// Binary bucket is a (mostly) complete packed inventory item
IM_TASK_INVENTORY_OFFERED = 9,
IM_TASK_INVENTORY_ACCEPTED = 10,
IM_TASK_INVENTORY_DECLINED = 11,
// Copied as pending, type LL_NOTHING_SPECIAL, for new users
// used by offline tools
IM_NEW_USER_DEFAULT = 12,
//
// session based messaging - the way that people usually actually
// communicate with each other.
//
// Invite users to a session.
IM_SESSION_INVITE = 13,
IM_SESSION_P2P_INVITE = 14,
// start a session with your gruop
IM_SESSION_GROUP_START = 15,
// start a session without a calling card (finder or objects)
IM_SESSION_CONFERENCE_START = 16,
// send a message to a session.
IM_SESSION_SEND = 17,
// leave a session
IM_SESSION_LEAVE = 18,
// an instant message from an object - for differentiation on the
// viewer, since you can't IM an object yet.
IM_FROM_TASK = 19,
// sent an IM to a do not disturb user, this is the auto response
IM_DO_NOT_DISTURB_AUTO_RESPONSE = 20,
// Shows the message in the console and chat history
IM_CONSOLE_AND_CHAT_HISTORY = 21,
// IM Types used for luring your friends
IM_LURE_USER = 22,
IM_LURE_ACCEPTED = 23,
IM_LURE_DECLINED = 24,
IM_GODLIKE_LURE_USER = 25,
IM_TELEPORT_REQUEST = 26,
// IM that notifie of a new group election.
// Name is name of person who called vote.
// ID is election ID used for internal tracking
IM_GROUP_ELECTION_DEPRECATED = 27,
// IM to tell the user to go to an URL. Put a text message in the
// message field, and put the url with a trailing \0 in the binary
// bucket.
IM_GOTO_URL = 28,
// a message generated by a script which we don't want to
// be sent through e-mail. Similar to IM_FROM_TASK, but
// it is shown as an alert on the viewer.
IM_FROM_TASK_AS_ALERT = 31,
// IM from group officer to all group members.
IM_GROUP_NOTICE = 32,
IM_GROUP_NOTICE_INVENTORY_ACCEPTED = 33,
IM_GROUP_NOTICE_INVENTORY_DECLINED = 34,
IM_GROUP_INVITATION_ACCEPT = 35,
IM_GROUP_INVITATION_DECLINE = 36,
IM_GROUP_NOTICE_REQUESTED = 37,
IM_FRIENDSHIP_OFFERED = 38,
IM_FRIENDSHIP_ACCEPTED = 39,
IM_FRIENDSHIP_DECLINED_DEPRECATED = 40,
IM_TYPING_START = 41,
IM_TYPING_STOP = 42,
IM_COUNT
};
extern const U8 IM_ONLINE;
extern const U8 IM_OFFLINE;
extern const char EMPTY_BINARY_BUCKET[];
extern const S32 EMPTY_BINARY_BUCKET_SIZE;
extern const U32 NO_TIMESTAMP;
// <FS:CR> Aurora Sim
//extern const std::string SYSTEM_FROM;
extern std::string SYSTEM_FROM;
// </FS:CR> Aurora Sim
extern const std::string INTERACTIVE_SYSTEM_FROM;
// Number of retry attempts on sending the im.
extern const S32 IM_TTL;
void pack_instant_message(
LLMessageSystem* msgsystem,
const LLUUID& from_id,
bool from_group,
const LLUUID& session_id,
const LLUUID& to_id,
const std::string& name,
const std::string& message,
U8 offline = IM_ONLINE,
EInstantMessage dialog = IM_NOTHING_SPECIAL,
const LLUUID& id = LLUUID::null,
U32 parent_estate_id = 0,
const LLUUID& region_id = LLUUID::null,
const LLVector3& position = LLVector3::zero,
U32 timestamp = NO_TIMESTAMP,
const U8* binary_bucket = (U8*)EMPTY_BINARY_BUCKET,
S32 binary_bucket_size = EMPTY_BINARY_BUCKET_SIZE);
void pack_instant_message_block(
LLMessageSystem* msgsystem,
const LLUUID& from_id,
bool from_group,
const LLUUID& session_id,
const LLUUID& to_id,
const std::string& name,
const std::string& message,
U8 offline = IM_ONLINE,
EInstantMessage dialog = IM_NOTHING_SPECIAL,
const LLUUID& id = LLUUID::null,
U32 parent_estate_id = 0,
const LLUUID& region_id = LLUUID::null,
const LLVector3& position = LLVector3::zero,
U32 timestamp = NO_TIMESTAMP,
const U8* binary_bucket = (U8*)EMPTY_BINARY_BUCKET,
S32 binary_bucket_size = EMPTY_BINARY_BUCKET_SIZE);
#endif // LL_LLINSTANTMESSAGE_H
+33
View File
@@ -0,0 +1,33 @@
/**
* @file llinvite.h
* @brief Constants used for inviting users to join groups.
*
* $LicenseInfo:firstyear=2002&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_LLINVITE_H
#define LL_LLINVITE_H
const S32 INVITE_LIST_STR_LEN = 324; // Would be larger, but we don't have much room in the CreateGroupRequest msg.
const S32 INVITE_LIST_BUF_SIZE = 325;
#endif // LL_LLINVITE_H
+114
View File
@@ -0,0 +1,114 @@
/**
* @file lliobuffer.cpp
* @author Phoenix
* @date 2005-05-04
* @brief Definition of buffer based implementations of IO Pipes.
*
* $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 "lliobuffer.h"
//
// LLIOBuffer
//
LLIOBuffer::LLIOBuffer() :
mBuffer(NULL),
mBufferSize(0L),
mReadHead(NULL),
mWriteHead(NULL)
{
}
LLIOBuffer::~LLIOBuffer()
{
if(mBuffer)
{
delete[] mBuffer;
}
}
U8* LLIOBuffer::data() const
{
return mBuffer;
}
S64 LLIOBuffer::size() const
{
return mBufferSize;
}
U8* LLIOBuffer::current() const
{
return mReadHead;
}
S64 LLIOBuffer::bytesLeft() const
{
return mWriteHead - mReadHead;
}
void LLIOBuffer::clear()
{
mReadHead = mBuffer;
mWriteHead = mBuffer;
}
LLIOPipe::EStatus LLIOBuffer::seek(LLIOBuffer::EHead head, S64 delta)
{
LLIOPipe::EStatus status = STATUS_ERROR;
switch(head)
{
case READ:
if(((delta >= 0) && ((mReadHead + delta) <= mWriteHead))
|| ((delta < 0) && ((mReadHead + delta) >= mBuffer)))
{
mReadHead += delta;
status = STATUS_OK;
}
break;
case WRITE:
if(((delta >= 0) && ((mWriteHead + delta) < (mBuffer + mBufferSize)))
|| ((delta < 0) && ((mWriteHead + delta) > mReadHead)))
{
mWriteHead += delta;
status = STATUS_OK;
}
default:
break;
}
return status;
}
// virtual
LLIOPipe::EStatus LLIOBuffer::process_impl(
const LLChannelDescriptors& channels,
buffer_ptr_t& buffer,
bool& eos,
LLSD& context,
LLPumpIO* pump)
{
// no-op (I think)
LL_WARNS() << "You are using an LLIOBuffer which is deprecated." << LL_ENDL;
return STATUS_OK;
}
+135
View File
@@ -0,0 +1,135 @@
/**
* @file lliobuffer.h
* @author Phoenix
* @date 2005-05-04
* @brief Declaration of buffers for use in IO Pipes.
*
* $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_LLIOBUFFER_H
#define LL_LLIOBUFFER_H
#include "lliopipe.h"
/**
* @class LLIOBuffer
* @brief This class is an io class that represents an automtically
* resizing io buffer.
* @see LLIOPipe
*
* This class is currently impelemented quick and dirty, but should be
* correct. This class should be extended to have a more flexible
* (and capped) memory allocation and usage scheme. Eventually, I
* would like to have the ability to share this buffer between
* different objects.
*/
class LLIOBuffer : public LLIOPipe
{
public:
LLIOBuffer();
virtual ~LLIOBuffer();
/**
* @brief Return a raw pointer to the current data set.
*
* The pointer returned can be used for reading or even adjustment
* if you are a bit crazy up to size() bytes into memory.
* @return A potentially NULL pointer to the raw buffer data
*/
U8* data() const;
/**
* @brief Return the size of the buffer
*/
S64 size() const;
/**
* @brief Return a raw pointer to the current read position in the data.
*
* The pointer returned can be used for reading or even adjustment
* if you are a bit crazy up to bytesLeft() bytes into memory.
* @return A potentially NULL pointer to the buffer data starting
* at the read point
*/
U8* current() const;
/**
* @brief Return the number of unprocessed bytes in buffer.
*/
S64 bytesLeft() const;
/**
* @brief Move the buffer offsets back to the beginning.
*
* This method effectively clears what has been stored here,
* without mucking around with memory allocation.
*/
void clear();
/**
* @brief Enumeration passed into the seek function
*
* The READ head is used for where to start processing data for
* the next link in the chain, while the WRITE head specifies
* where new data processed from the previous link in the chain
* will be written.
*/
enum EHead
{
READ,
WRITE
};
/**
* @brief Seek to a place in the buffer
*
* @param head The READ or WRITE head.
* @param delta The offset from the current position to seek.
* @return The status of the operation. status >= if head moved.
*/
EStatus seek(EHead head, S64 delta);
public:
/* @name LLIOPipe virtual implementations
*/
//@{
protected:
/**
* @brief Process the data in buffer
*/
virtual EStatus process_impl(
const LLChannelDescriptors& channels,
buffer_ptr_t& buffer,
bool& eos,
LLSD& context,
LLPumpIO* pump);
//@}
protected:
U8* mBuffer;
S64 mBufferSize;
U8* mReadHead;
U8* mWriteHead;
};
#endif // LL_LLIOBUFFER_H
File diff suppressed because it is too large Load Diff
+127
View File
@@ -0,0 +1,127 @@
/**
* @file lliohttpserver.h
* @brief Declaration of function for creating an HTTP wire server
* @see LLIOServerSocket, LLPumpIO
*
* $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_LLIOHTTPSERVER_H
#define LL_LLIOHTTPSERVER_H
#include "llchainio.h"
#include "llhttpnode.h"
class LLPumpIO;
class LLIOHTTPServer
{
public:
typedef void (*timing_callback_t)(const char* hashed_name, F32 time, void* data);
static LLHTTPNode& create(apr_pool_t* pool, LLPumpIO& pump, U16 port);
/**< Creates an HTTP wire server on the pump for the given TCP port.
*
* Returns the root node of the new server. Add LLHTTPNode instances
* to this root.
*
* Nodes that return NULL for getProtocolHandler(), will use the
* default handler that interprets HTTP on the wire and converts
* it into calls to get(), put(), post(), del() with appropriate
* LLSD arguments and results.
*
* To have nodes that implement some other wire protocol (XML-RPC
* for example), use the helper templates below.
*/
static void createPipe(LLPumpIO::chain_t& chain,
const LLHTTPNode& root, const LLSD& ctx);
/**< Create a pipe on the chain that handles HTTP requests.
* The requests are served by the node tree given at root.
*
* This is primarily useful for unit testing.
*/
static void setTimingCallback(timing_callback_t callback, void* data);
/**< Register a callback function that will be called every time
* a GET, PUT, POST, or DELETE is handled.
*
* This is used to time the LLHTTPNode handler code, which often hits
* the database or does other, slow operations. JC
*/
};
/* @name Helper Templates
*
* These templates make it easy to create nodes that use thier own protocol
* handlers rather than the default. Typically, you subclass LLIOPipe to
* implement the protocol, and then add a node using the templates:
*
* rootNode->addNode("thing", new LLHTTPNodeForPipe<LLThingPipe>);
*
* The templates are:
*
* LLChainIOFactoryForPipe
* - a simple factory that builds instances of a pipe
*
* LLHTTPNodeForFacotry
* - a HTTP node that uses a factory as the protocol handler
*
* LLHTTPNodeForPipe
* - a HTTP node that uses a simple factory based on a pipe
*/
//@{
template<class Pipe>
class LLChainIOFactoryForPipe : public LLChainIOFactory
{
public:
virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const
{
chain.push_back(LLIOPipe::ptr_t(new Pipe));
return true;
}
};
template<class Factory>
class LLHTTPNodeForFactory : public LLHTTPNode
{
public:
const LLChainIOFactory* getProtocolHandler() const
{ return &mProtocolHandler; }
private:
Factory mProtocolHandler;
};
//@}
template<class Pipe>
class LLHTTPNodeForPipe : public LLHTTPNodeForFactory<
LLChainIOFactoryForPipe<Pipe> >
{
};
#endif // LL_LLIOHTTPSERVER_H
+120
View File
@@ -0,0 +1,120 @@
/**
* @file lliopipe.cpp
* @author Phoenix
* @date 2004-11-19
* @brief Implementation of the LLIOPipe class
*
* $LicenseInfo:firstyear=2004&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 "lliopipe.h"
#include "llpumpio.h"
static const std::string STATUS_SUCCESS_NAMES[LLIOPipe::STATUS_SUCCESS_COUNT] =
{
std::string("STATUS_OK"),
std::string("STATUS_STOP"),
std::string("STATUS_DONE"),
std::string("STATUS_BREAK"),
std::string("STATUS_NEED_PROCESS"),
};
static const std::string STATUS_ERROR_NAMES[LLIOPipe::STATUS_ERROR_COUNT] =
{
std::string("STATUS_ERROR"),
std::string("STATUS_NOT_IMPLEMENTED"),
std::string("STATUS_PRECONDITION_NOT_MET"),
std::string("STATUS_NO_CONNECTION"),
std::string("STATUS_LOST_CONNECTION"),
std::string("STATUS_EXPIRED"),
};
#ifdef LL_DEBUG_PUMPS
// Debugging schmutz for deadlock
const char *gPumpFile = "";
S32 gPumpLine = 0;
void pump_debug(const char *file, S32 line)
{
gPumpFile = file;
gPumpLine = line;
}
#endif /* LL_DEBUG_PUMPS */
/**
* LLIOPipe
*/
LLIOPipe::LLIOPipe() :
mReferenceCount(0)
{
}
LLIOPipe::~LLIOPipe()
{
//LL_DEBUGS() << "destroying LLIOPipe" << LL_ENDL;
}
//virtual
bool LLIOPipe::isValid()
{
return true ;
}
// static
std::string LLIOPipe::lookupStatusString(EStatus status)
{
if((status >= 0) && (status < STATUS_SUCCESS_COUNT))
{
return STATUS_SUCCESS_NAMES[status];
}
else
{
S32 error_code = ((S32)status * -1) - 1;
if(error_code < STATUS_ERROR_COUNT)
{
return STATUS_ERROR_NAMES[error_code];
}
}
std::string rv;
return rv;
}
LLIOPipe::EStatus LLIOPipe::process(
const LLChannelDescriptors& channels,
buffer_ptr_t& buffer,
bool& eos,
LLSD& context,
LLPumpIO* pump)
{
return process_impl(channels, buffer, eos, context, pump);
}
// virtual
LLIOPipe::EStatus LLIOPipe::handleError(
LLIOPipe::EStatus status,
LLPumpIO* pump)
{
// by default, the error is not handled.
return status;
}
+267
View File
@@ -0,0 +1,267 @@
/**
* @file lliopipe.h
* @author Phoenix
* @date 2004-11-18
* @brief Declaration of base IO class
*
* $LicenseInfo:firstyear=2004&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_LLIOPIPE_H
#define LL_LLIOPIPE_H
#include <boost/intrusive_ptr.hpp>
#include "llwin32headers.h"
#include "apr_poll.h"
#include "llsd.h"
class LLIOPipe;
class LLPumpIO;
class LLBufferArray;
class LLChannelDescriptors;
// Debugging schmutz for deadlocks
//#define LL_DEBUG_PUMPS
#ifdef LL_DEBUG_PUMPS
void pump_debug(const char *file, S32 line);
#define PUMP_DEBUG pump_debug(__FILE__, __LINE__);
#define END_PUMP_DEBUG pump_debug("none", 0);
#else /* LL_DEBUG_PUMPS */
#define PUMP_DEBUG
#define END_PUMP_DEBUG
#endif
/**
* intrusive pointer support
*/
void intrusive_ptr_add_ref(LLIOPipe* p);
void intrusive_ptr_release(LLIOPipe* p);
/**
* @class LLIOPipe
* @brief This class is an abstract base class for data processing units
* @see LLPumpIO
*
* The LLIOPipe is a base class for implementing the basic non-blocking
* processing of data subsystem in our system.
*
* Implementations of this class should behave like a stateful or
* stateless signal processor. Each call to <code>process()</code>
* hands the pipe implementation a buffer and a set of channels in the
* buffer to process, and the pipe returns the status of the
* operation. This is an abstract base class and developer created
* concrete implementations provide block or stream based processing
* of data to implement a particular protocol.
*/
class LLIOPipe
{
public:
/**
* @brief I have decided that IO objects should have a reference
* count. In general, you can pass bald LLIOPipe pointers around
* as you need, but if you need to maintain a reference to one,
* you need to hold a ptr_t.
*/
typedef boost::intrusive_ptr<LLIOPipe> ptr_t;
/**
* @brief Scattered memory container.
*/
typedef std::shared_ptr<LLBufferArray> buffer_ptr_t;
/**
* @brief Enumeration for IO return codes
*
* A status code a positive integer value is considered a success,
* but may indicate special handling for future calls, for
* example, issuing a STATUS_STOP to an LLIOSocketReader instance
* will tell the instance to stop reading the socket. A status
* code with a negative value means that a problem has been
* encountered which will require further action on the caller or
* a developer to correct. Some mechanisms, such as the LLPumpIO
* may depend on this definition of success and failure.
*/
enum EStatus
{
// Processing occurred normally, future calls will be accepted.
STATUS_OK = 0,
// Processing occured normally, but stop unsolicited calls to
// process.
STATUS_STOP = 1,
// This pipe is done with the processing. Future calls to
// process will be accepted as long as new data is available.
STATUS_DONE = 2,
// This pipe is requesting that it become the head in a process.
STATUS_BREAK = 3,
// This pipe is requesting that it become the head in a process.
STATUS_NEED_PROCESS = 4,
// Keep track of the highest number of success codes here.
STATUS_SUCCESS_COUNT = 5,
// A generic error code.
STATUS_ERROR = -1,
// This method has not yet been implemented. This usually
// indicates the programmer working on the pipe is not yet
// done.
STATUS_NOT_IMPLEMENTED = -2,
// This indicates that a pipe precondition was not met. For
// example, many pipes require an element to appear after them
// in a chain (ie, mNext is not null) and will return this in
// response to method calls. To recover from this, it will
// require the caller to adjust the pipe state or may require
// a dev to adjust the code to satisfy the preconditions.
STATUS_PRECONDITION_NOT_MET = -3,
// This means we could not connect to a remote host.
STATUS_NO_CONNECTION = -4,
// The connection was lost.
STATUS_LOST_CONNECTION = -5,
// The totoal process time has exceeded the timeout.
STATUS_EXPIRED = -6,
// Keep track of the count of codes here.
STATUS_ERROR_COUNT = 6,
};
/**
* @brief Helper function to check status.
*
* When writing code to check status codes, if you do not
* specifically check a particular value, use this method for
* checking an error condition.
* @param status The status to check.
* @return Returns true if the code indicates an error occurred.
*/
inline static bool isError(EStatus status)
{
return ((S32)status < 0);
}
/**
* @brief Helper function to check status.
*
* When writing code to check status codes, if you do not
* specifically check a particular value, use this method for
* checking an error condition.
* @param status The status to check.
* @return Returns true if the code indicates no error was generated.
*/
inline static bool isSuccess(EStatus status)
{
return ((S32)status >= 0);
}
/**
* @brief Helper function to turn status into a string.
*
* @param status The status to check.
* @return Returns the name of the status code or empty string on failure.
*/
static std::string lookupStatusString(EStatus status);
/**
* @brief Process the data in buffer.
*
* @param data The data processed
* @param eos True if this function call is the last because end of stream.
* @param pump The pump which is calling process. May be NULL.
* @param context Shared meta-data for the process.
* @return Returns a status code from the operation.
*/
EStatus process(
const LLChannelDescriptors& channels,
buffer_ptr_t& buffer,
bool& eos,
LLSD& context,
LLPumpIO* pump);
/**
* @brief Give this pipe a chance to handle a generated error
*
* If this pipe is in a chain being processed by a pump, and one
* of the pipes generates an error, the pump will rewind through
* the chain to see if any of the links can handle the error. For
* example, if a connection is refused in a socket connection, the
* socket client can try to find a new destination host. Return an
* error code if this pipe does not handle the error passed in.
* @param status The status code for the error
* @param pump The pump which was calling process before the error
* was generated.
* @return Returns a status code from the operation. Returns an
* error code if the error passed in was not handled. Returns
* STATUS_OK to indicate the error has been handled.
*/
virtual EStatus handleError(EStatus status, LLPumpIO* pump);
/**
* @brief Base Destructor - do not call <code>delete</code> directly.
*/
virtual ~LLIOPipe();
virtual bool isValid() ;
protected:
/**
* @brief Base Constructor.
*/
LLIOPipe();
/**
* @brief Process the data in buffer
*/
virtual EStatus process_impl(
const LLChannelDescriptors& channels,
buffer_ptr_t& buffer,
bool& eos,
LLSD& context,
LLPumpIO* pump) = 0;
private:
friend void intrusive_ptr_add_ref(LLIOPipe* p);
friend void intrusive_ptr_release(LLIOPipe* p);
U32 mReferenceCount;
};
inline void intrusive_ptr_add_ref(LLIOPipe* p)
{
++p->mReferenceCount;
}
inline void intrusive_ptr_release(LLIOPipe* p)
{
if(p && 0 == --p->mReferenceCount)
{
delete p;
}
}
#endif // LL_LLIOPIPE_H
+708
View File
@@ -0,0 +1,708 @@
/**
* @file lliosocket.cpp
* @author Phoenix
* @date 2005-07-31
* @brief Sockets declarations for use with the io pipes
*
* $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 "lliosocket.h"
#include "llapr.h"
#include "llbuffer.h"
#include "llfasttimer.h"
#include "llhost.h"
#include "llpumpio.h"
//
// constants
//
const std::string CONTEXT_REMOTE_HOST("remote-host");
const std::string CONTEXT_REMOTE_PORT("remote-port");
static const S32 LL_DEFAULT_LISTEN_BACKLOG = 10;
static const S32 LL_SEND_BUFFER_SIZE = 40000;
static const S32 LL_RECV_BUFFER_SIZE = 40000;
//static const U16 LL_PORT_DISCOVERY_RANGE_MIN = 13000;
//static const U16 LL_PORT_DISCOVERY_RANGE_MAX = 13050;
//
// local methods
//
bool is_addr_in_use(apr_status_t status)
{
#if LL_WINDOWS
return (WSAEADDRINUSE == APR_TO_OS_ERROR(status));
#else
return (EADDRINUSE == APR_TO_OS_ERROR(status));
#endif
}
#if ! LL_WINDOWS
// Define this to see the actual file descriptors being tossed around.
#define LL_DEBUG_SOCKET_FILE_DESCRIPTORS 1
#if LL_DEBUG_SOCKET_FILE_DESCRIPTORS
#include "apr_portable.h"
#endif
#endif
// Quick function
void ll_debug_socket(const char* msg, apr_socket_t* apr_sock)
{
#if LL_DEBUG_SOCKET_FILE_DESCRIPTORS
if(!apr_sock)
{
LL_DEBUGS("Socket") << "Socket -- " << (msg?msg:"") << ": no socket." << LL_ENDL;
return;
}
// *TODO: Why doesn't this work?
//apr_os_sock_t os_sock;
int os_sock;
if(APR_SUCCESS == apr_os_sock_get(&os_sock, apr_sock))
{
LL_DEBUGS("Socket") << "Socket -- " << (msg?msg:"") << " on fd " << os_sock
<< " at " << apr_sock << LL_ENDL;
}
else
{
LL_DEBUGS("Socket") << "Socket -- " << (msg?msg:"") << " no fd "
<< " at " << apr_sock << LL_ENDL;
}
#endif
}
///
/// LLSocket
///
// static
LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port, const char *hostname)
{
LLSocket::ptr_t rv;
apr_socket_t* socket = NULL;
apr_pool_t* new_pool = NULL;
apr_status_t status = APR_EGENERAL;
// create a pool for the socket
status = apr_pool_create(&new_pool, pool);
if(ll_apr_warn_status(status))
{
if(new_pool) apr_pool_destroy(new_pool);
return rv;
}
if(STREAM_TCP == type)
{
status = apr_socket_create(
&socket,
APR_INET,
SOCK_STREAM,
APR_PROTO_TCP,
new_pool);
}
else if(DATAGRAM_UDP == type)
{
status = apr_socket_create(
&socket,
APR_INET,
SOCK_DGRAM,
APR_PROTO_UDP,
new_pool);
}
else
{
if(new_pool) apr_pool_destroy(new_pool);
return rv;
}
if(ll_apr_warn_status(status))
{
if(new_pool) apr_pool_destroy(new_pool);
return rv;
}
// At this point, the new LLSocket instance takes ownership of new_pool,
// which is why no early return below this call explicitly destroys it: it
// is instead cleaned up by ~LLSocket().
rv = ptr_t(new LLSocket(socket, new_pool));
if(port > 0)
{
apr_sockaddr_t* sa = NULL;
status = apr_sockaddr_info_get(
&sa,
hostname,
APR_UNSPEC,
port,
0,
new_pool);
if(ll_apr_warn_status(status))
{
rv.reset();
return rv;
}
// This allows us to reuse the address on quick down/up. This
// is unlikely to create problems.
ll_apr_warn_status(apr_socket_opt_set(socket, APR_SO_REUSEADDR, 1));
status = apr_socket_bind(socket, sa);
if(ll_apr_warn_status(status))
{
rv.reset();
return rv;
}
LL_DEBUGS() << "Bound " << ((DATAGRAM_UDP == type) ? "udp" : "tcp")
<< " socket to port: " << sa->port << LL_ENDL;
if(STREAM_TCP == type)
{
// If it's a stream based socket, we need to tell the OS
// to keep a queue of incoming connections for ACCEPT.
LL_DEBUGS() << "Setting listen state for socket." << LL_ENDL;
status = apr_socket_listen(
socket,
LL_DEFAULT_LISTEN_BACKLOG);
if(ll_apr_warn_status(status))
{
rv.reset();
return rv;
}
}
}
else // port <= 0
{
// we need to indicate that we have an ephemeral port if the
// previous calls were successful. It will
port = PORT_EPHEMERAL;
}
rv->mPort = port;
rv->setNonBlocking();
return rv;
}
// static
LLSocket::ptr_t LLSocket::create(apr_socket_t* socket, apr_pool_t* pool)
{
LLSocket::ptr_t rv;
if(!socket)
{
return rv;
}
rv = ptr_t(new LLSocket(socket, pool));
rv->mPort = PORT_EPHEMERAL;
rv->setNonBlocking();
return rv;
}
bool LLSocket::blockingConnect(const LLHost& host)
{
// <FS:ND> Prevent log spam
if( !host.isOk() )
return false;
// </FS:ND>
if(!mSocket) return false;
apr_sockaddr_t* sa = NULL;
std::string ip_address;
ip_address = host.getIPString();
if(ll_apr_warn_status(apr_sockaddr_info_get(
&sa,
ip_address.c_str(),
APR_UNSPEC,
host.getPort(),
0,
mPool)))
{
return false;
}
setBlocking(1000);
ll_debug_socket("Blocking connect", mSocket);
if(ll_apr_warn_status(apr_socket_connect(mSocket, sa))) return false;
setNonBlocking();
return true;
}
LLSocket::LLSocket(apr_socket_t* socket, apr_pool_t* pool) :
mSocket(socket),
mPool(pool),
mPort(PORT_INVALID)
{
ll_debug_socket("Constructing wholely formed socket", mSocket);
}
LLSocket::~LLSocket()
{
// *FIX: clean up memory we are holding.
if(mSocket)
{
ll_debug_socket("Destroying socket", mSocket);
apr_socket_close(mSocket);
mSocket = NULL;
}
if(mPool)
{
apr_pool_destroy(mPool);
mPool = NULL;
}
}
// See http://dev.ariel-networks.com/apr/apr-tutorial/html/apr-tutorial-13.html#ss13.4
// for an explanation of how to get non-blocking sockets and timeouts with
// consistent behavior across platforms.
void LLSocket::setBlocking(S32 timeout)
{
// set up the socket options
ll_apr_warn_status(apr_socket_timeout_set(mSocket, timeout)); // Sets both receive and send timeout SO_RCVTIMEO, SO_SNDTIMEO
ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_NONBLOCK, 0));
ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_SNDBUF, LL_SEND_BUFFER_SIZE));
ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_RCVBUF, LL_RECV_BUFFER_SIZE));
}
void LLSocket::setNonBlocking()
{
// set up the socket options
ll_apr_warn_status(apr_socket_timeout_set(mSocket, 0));
ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_NONBLOCK, 1));
ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_SNDBUF, LL_SEND_BUFFER_SIZE));
ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_RCVBUF, LL_RECV_BUFFER_SIZE));
}
///
/// LLIOSocketReader
///
LLIOSocketReader::LLIOSocketReader(LLSocket::ptr_t socket) :
mSource(socket),
mInitialized(false)
{
}
LLIOSocketReader::~LLIOSocketReader()
{
//LL_DEBUGS() << "Destroying LLIOSocketReader" << LL_ENDL;
}
// virtual
LLIOPipe::EStatus LLIOSocketReader::process_impl(
const LLChannelDescriptors& channels,
buffer_ptr_t& buffer,
bool& eos,
LLSD& context,
LLPumpIO* pump)
{
LL_PROFILE_ZONE_SCOPED;
PUMP_DEBUG;
if(!mSource) return STATUS_PRECONDITION_NOT_MET;
if(!mInitialized)
{
PUMP_DEBUG;
// Since the read will not block, it's ok to initialize and
// attempt to read off the descriptor immediately.
mInitialized = true;
if(pump)
{
PUMP_DEBUG;
LL_DEBUGS() << "Initializing poll descriptor for LLIOSocketReader."
<< LL_ENDL;
apr_pollfd_t poll_fd;
poll_fd.p = NULL;
poll_fd.desc_type = APR_POLL_SOCKET;
poll_fd.reqevents = APR_POLLIN;
poll_fd.rtnevents = 0x0;
poll_fd.desc.s = mSource->getSocket();
poll_fd.client_data = NULL;
pump->setConditional(this, &poll_fd);
}
}
//if(!buffer)
//{
// buffer = new LLBufferArray;
//}
PUMP_DEBUG;
const apr_size_t READ_BUFFER_SIZE = 1024;
char read_buf[READ_BUFFER_SIZE]; /*Flawfinder: ignore*/
apr_size_t len;
apr_status_t status = APR_SUCCESS;
do
{
PUMP_DEBUG;
len = READ_BUFFER_SIZE;
status = apr_socket_recv(mSource->getSocket(), read_buf, &len);
buffer->append(channels.out(), (U8*)read_buf, static_cast<S32>(len));
} while((APR_SUCCESS == status) && (READ_BUFFER_SIZE == len));
LL_DEBUGS() << "socket read status: " << status << LL_ENDL;
LLIOPipe::EStatus rv = STATUS_OK;
PUMP_DEBUG;
// *FIX: Also need to check for broken pipe
if(APR_STATUS_IS_EOF(status))
{
// *FIX: Should we shut down the socket read?
if(pump)
{
pump->setConditional(this, NULL);
}
rv = STATUS_DONE;
eos = true;
}
else if(APR_STATUS_IS_EAGAIN(status))
{
/*Commented out by Aura 9-9-8 for DEV-19961.
// everything is fine, but we can terminate this process pump.
rv = STATUS_BREAK;
*/
}
else
{
if(ll_apr_warn_status(status))
{
rv = STATUS_ERROR;
}
}
PUMP_DEBUG;
return rv;
}
///
/// LLIOSocketWriter
///
LLIOSocketWriter::LLIOSocketWriter(LLSocket::ptr_t socket) :
mDestination(socket),
mLastWritten(NULL),
mInitialized(false)
{
}
LLIOSocketWriter::~LLIOSocketWriter()
{
//LL_DEBUGS() << "Destroying LLIOSocketWriter" << LL_ENDL;
}
// virtual
LLIOPipe::EStatus LLIOSocketWriter::process_impl(
const LLChannelDescriptors& channels,
buffer_ptr_t& buffer,
bool& eos,
LLSD& context,
LLPumpIO* pump)
{
LL_PROFILE_ZONE_SCOPED;
PUMP_DEBUG;
if(!mDestination) return STATUS_PRECONDITION_NOT_MET;
if(!mInitialized)
{
PUMP_DEBUG;
// Since the write will not block, it's ok to initialize and
// attempt to write immediately.
mInitialized = true;
if(pump)
{
PUMP_DEBUG;
LL_DEBUGS() << "Initializing poll descriptor for LLIOSocketWriter."
<< LL_ENDL;
apr_pollfd_t poll_fd;
poll_fd.p = NULL;
poll_fd.desc_type = APR_POLL_SOCKET;
poll_fd.reqevents = APR_POLLOUT;
poll_fd.rtnevents = 0x0;
poll_fd.desc.s = mDestination->getSocket();
poll_fd.client_data = NULL;
pump->setConditional(this, &poll_fd);
}
}
PUMP_DEBUG;
// *FIX: Some sort of writev implementation would be much more
// efficient - not only because writev() is better, but also
// because we won't have to do as much work to find the start
// address.
buffer->lock();
LLBufferArray::segment_iterator_t it;
LLBufferArray::segment_iterator_t end = buffer->endSegment();
LLSegment segment;
it = buffer->constructSegmentAfter(mLastWritten, segment);
/*
if(NULL == mLastWritten)
{
it = buffer->beginSegment();
segment = (*it);
}
else
{
it = buffer->getSegment(mLastWritten);
segment = (*it);
S32 size = segment.size();
U8* data = segment.data();
if((data + size) == mLastWritten)
{
++it;
segment = (*it);
}
else
{
// *FIX: check the math on this one
segment = LLSegment(
(*it).getChannelMask(),
mLastWritten + 1,
size - (mLastWritten - data));
}
}
*/
PUMP_DEBUG;
apr_size_t len;
bool done = false;
apr_status_t status = APR_SUCCESS;
while(it != end)
{
PUMP_DEBUG;
if((*it).isOnChannel(channels.in()))
{
PUMP_DEBUG;
len = (apr_size_t)segment.size();
status = apr_socket_send(
mDestination->getSocket(),
(const char*)segment.data(),
&len);
// We sometimes get a 'non-blocking socket operation could not be
// completed immediately' error from apr_socket_send. In this
// case we break and the data will be sent the next time the chain
// is pumped.
if(APR_STATUS_IS_EAGAIN(status))
{
ll_apr_warn_status(status);
break;
}
mLastWritten = segment.data() + len - 1;
PUMP_DEBUG;
if((S32)len < segment.size())
{
break;
}
}
++it;
if(it != end)
{
segment = (*it);
}
else
{
done = true;
}
}
buffer->unlock();
PUMP_DEBUG;
if(done && eos)
{
return STATUS_DONE;
}
return STATUS_OK;
}
///
/// LLIOServerSocket
///
LLIOServerSocket::LLIOServerSocket(
apr_pool_t* pool,
LLIOServerSocket::socket_t listener,
factory_t factory) :
mPool(pool),
mListenSocket(listener),
mReactor(factory),
mInitialized(false),
mResponseTimeout(DEFAULT_CHAIN_EXPIRY_SECS)
{
}
LLIOServerSocket::~LLIOServerSocket()
{
//LL_DEBUGS() << "Destroying LLIOServerSocket" << LL_ENDL;
}
void LLIOServerSocket::setResponseTimeout(F32 timeout_secs)
{
mResponseTimeout = timeout_secs;
}
// virtual
LLIOPipe::EStatus LLIOServerSocket::process_impl(
const LLChannelDescriptors& channels,
buffer_ptr_t& buffer,
bool& eos,
LLSD& context,
LLPumpIO* pump)
{
LL_PROFILE_ZONE_SCOPED;
PUMP_DEBUG;
if(!pump)
{
LL_WARNS() << "Need a pump for server socket." << LL_ENDL;
return STATUS_ERROR;
}
if(!mInitialized)
{
PUMP_DEBUG;
// This segment sets up the pump so that we do not call
// process again until we have an incoming read, aka connect()
// from a remote host.
LL_DEBUGS() << "Initializing poll descriptor for LLIOServerSocket."
<< LL_ENDL;
apr_pollfd_t poll_fd;
poll_fd.p = NULL;
poll_fd.desc_type = APR_POLL_SOCKET;
poll_fd.reqevents = APR_POLLIN;
poll_fd.rtnevents = 0x0;
poll_fd.desc.s = mListenSocket->getSocket();
poll_fd.client_data = NULL;
pump->setConditional(this, &poll_fd);
mInitialized = true;
return STATUS_OK;
}
// we are initialized, and told to process, so we must have a
// socket waiting for a connection.
LL_DEBUGS() << "accepting socket" << LL_ENDL;
PUMP_DEBUG;
apr_pool_t* new_pool = NULL;
apr_status_t status = apr_pool_create(&new_pool, mPool);
if(ll_apr_warn_status(status))
{
if(new_pool)
{
apr_pool_destroy(new_pool);
}
return STATUS_ERROR;
}
apr_socket_t* socket = NULL;
status = apr_socket_accept(
&socket,
mListenSocket->getSocket(),
new_pool);
LLSocket::ptr_t llsocket(LLSocket::create(socket, new_pool));
//EStatus rv = STATUS_ERROR;
if(llsocket)
{
PUMP_DEBUG;
apr_sockaddr_t* remote_addr;
apr_socket_addr_get(&remote_addr, APR_REMOTE, socket);
char* remote_host_string;
apr_sockaddr_ip_get(&remote_host_string, remote_addr);
LLSD context;
context[CONTEXT_REMOTE_HOST] = remote_host_string;
context[CONTEXT_REMOTE_PORT] = remote_addr->port;
LLPumpIO::chain_t chain;
chain.push_back(LLIOPipe::ptr_t(new LLIOSocketReader(llsocket)));
if(mReactor->build(chain, context))
{
chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(llsocket)));
pump->addChain(chain, mResponseTimeout);
status = STATUS_OK;
}
else
{
LL_WARNS() << "Unable to build reactor to socket." << LL_ENDL;
}
}
else
{
LL_WARNS() << "Unable to create linden socket." << LL_ENDL;
}
PUMP_DEBUG;
// This needs to always return success, lest it get removed from
// the pump.
return STATUS_OK;
}
#if 0
LLIODataSocket::LLIODataSocket(
U16 suggested_port,
U16 start_discovery_port,
apr_pool_t* pool) :
mSocket(NULL)
{
if(!pool || (PORT_INVALID == suggested_port)) return;
if(ll_apr_warn_status(apr_socket_create(&mSocket, APR_INET, SOCK_DGRAM, APR_PROTO_UDP, pool))) return;
apr_sockaddr_t* sa = NULL;
if(ll_apr_warn_status(apr_sockaddr_info_get(&sa, APR_ANYADDR, APR_UNSPEC, suggested_port, 0, pool))) return;
apr_status_t status = apr_socket_bind(mSocket, sa);
if((start_discovery_port > 0) && is_addr_in_use(status))
{
const U16 MAX_ATTEMPT_PORTS = 50;
for(U16 attempt_port = start_discovery_port;
attempt_port < (start_discovery_port + MAX_ATTEMPT_PORTS);
++attempt_port)
{
sa->port = attempt_port;
sa->sa.sin.sin_port = htons(attempt_port);
status = apr_socket_bind(mSocket, sa);
if(APR_SUCCESS == status) break;
if(is_addr_in_use(status)) continue;
(void)ll_apr_warn_status(status);
}
}
if(ll_apr_warn_status(status)) return;
if(sa->port)
{
LL_DEBUGS() << "Bound datagram socket to port: " << sa->port << LL_ENDL;
mPort = sa->port;
}
else
{
mPort = LLIOSocket::PORT_EPHEMERAL;
}
// set up the socket options options
ll_apr_warn_status(apr_socket_timeout_set(mSocket, 0));
ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_SNDBUF, LL_SEND_BUFFER_SIZE));
ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_RCVBUF, LL_RECV_BUFFER_SIZE));
}
LLIODataSocket::~LLIODataSocket()
{
}
#endif
+386
View File
@@ -0,0 +1,386 @@
/**
* @file lliosocket.h
* @author Phoenix
* @date 2005-07-31
* @brief Declaration of files used for handling sockets and associated pipes
*
* $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_LLIOSOCKET_H
#define LL_LLIOSOCKET_H
/**
* The socket interface provided here is a simple wraper around apr
* sockets, with a pipe source and sink to read and write off of the
* socket. Every socket only performs non-blocking operations except
* the server socket which only performs blocking operations when an
* OS poll indicates it will not block.
*/
#include "lliopipe.h"
#include "llwin32headers.h"
#include "apr_pools.h"
#include "apr_network_io.h"
#include "llchainio.h"
extern const std::string CONTEXT_REMOTE_HOST;
extern const std::string CONTEXT_REMOTE_PORT;
class LLHost;
/**
* @class LLSocket
* @brief Implementation of a wrapper around a socket.
*
* An instance of this class represents a single socket over it's
* entire life - from uninitialized, to connected, to a listening
* socket depending on it's purpose. This class simplifies our access
* into the socket interface by only providing stream/tcp and
* datagram/udp sockets - the only types we are interested in, since
* those are the only properly supported by all of our platforms.
*/
class LLSocket
{
public:
/**
* @brief Reference counted shared pointers to sockets.
*/
typedef std::shared_ptr<LLSocket> ptr_t;
/**
* @brief Type of socket to create.
*/
enum EType
{
STREAM_TCP,
DATAGRAM_UDP,
};
/**
* @brief Anonymous enumeration to help identify ports
*/
enum
{
PORT_INVALID = (U16)-1,
PORT_EPHEMERAL = 0,
};
/**
* @brief Create a socket.
*
* This is the call you would use if you intend to create a listen
* socket. If you intend the socket to be known to external
* clients without prior port notification, do not use
* PORT_EPHEMERAL.
* @param pool The apr pool to use. A child pool will be created
* and associated with the socket.
* @param type The type of socket to create
* @param port The port for the socket
* @param hostname e.g. APR_ANYADDR to listen openly, or "127.0.0.1"
* @return A valid socket shared pointer if the call worked.
*/
static ptr_t create(
apr_pool_t* pool,
EType type,
U16 port = PORT_EPHEMERAL,
const char *hostname = APR_ANYADDR);
/**
* @brief Create a LLSocket when you already have an apr socket.
*
* This method assumes an ephemeral port. This is typically used
* by calls which spawn a socket such as a call to
* <code>accept()</code> as in the server socket. This call should
* not fail if you have a valid apr socket.
* Because of the nature of how accept() works, you are expected
* to create a new pool for the socket, use that pool for the
* accept, and pass it in here where it will be bound with the
* socket and destroyed at the same time.
* @param socket The apr socket to use
* @param pool The pool used to create the socket. *NOTE: The pool
* passed in will be DESTROYED.
* @return A valid socket shared pointer if the call worked.
*/
static ptr_t create(apr_socket_t* socket, apr_pool_t* pool);
/**
* @brief Perform a blocking connect to a host. Do not use in production.
*
* @param host The host to connect this socket to.
* @return Returns true if the connect was successful.
*/
bool blockingConnect(const LLHost& host);
/**
* @brief Get the type of socket
*/
//EType getType() const { return mType; }
/**
* @brief Get the port.
*
* This will return PORT_EPHEMERAL if bind was never called.
* @return Returns the port associated with this socket.
*/
U16 getPort() const { return mPort; }
/**
* @brief Get the apr socket implementation.
*
* @return Returns the raw apr socket.
*/
apr_socket_t* getSocket() const { return mSocket; }
/**
* @brief Set default socket options, with SO_NONBLOCK = 0 and a timeout in us.
* @param timeout Number of microseconds to wait on this socket. Any
* negative number means block-forever. TIMEOUT OF 0 IS NON-PORTABLE.
*/
void setBlocking(S32 timeout);
/**
* @brief Set default socket options, with SO_NONBLOCK = 1 and timeout = 0.
*/
void setNonBlocking();
protected:
/**
* @brief Protected constructor since should only make sockets
* with one of the two <code>create()</code> calls.
*/
LLSocket(apr_socket_t* socket, apr_pool_t* pool);
public:
/**
* @brief Do not call this directly.
*/
~LLSocket();
protected:
// The apr socket.
apr_socket_t* mSocket;
// our memory pool
apr_pool_t* mPool;
// The port if we know it.
U16 mPort;
//EType mType;
};
/**
* @class LLIOSocketReader
* @brief An LLIOPipe implementation which reads from a socket.
* @see LLIOPipe
*
* An instance of a socket reader wraps around an LLSocket and
* performs non-blocking reads and passes it to the next pipe in the
* chain.
*/
class LLIOSocketReader : public LLIOPipe
{
public:
LLIOSocketReader(LLSocket::ptr_t socket);
~LLIOSocketReader();
protected:
/* @name LLIOPipe virtual implementations
*/
//@{
/**
* @brief Process the data coming in the socket.
*
* Since the socket and next pipe must exist for process to make
* any sense, this method will return STATUS_PRECONDITION_NOT_MET
* unless if they are not known.
* If a STATUS_STOP returned by the next link in the chain, this
* reader will turn of the socket polling.
* @param buffer Pointer to a buffer which needs processing. Probably NULL.
* @param bytes Number of bytes to in buffer to process. Probably 0.
* @param eos True if this function is the last. Almost always false.
* @param read Number of bytes actually processed.
* @param pump The pump which is calling process. May be NULL.
* @param context A data structure to pass structured data
* @return STATUS_OK unless the preconditions are not met.
*/
virtual EStatus process_impl(
const LLChannelDescriptors& channels,
buffer_ptr_t& buffer,
bool& eos,
LLSD& context,
LLPumpIO* pump);
//@}
protected:
LLSocket::ptr_t mSource;
std::vector<U8> mBuffer;
bool mInitialized;
};
/**
* @class LLIOSocketWriter
* @brief An LLIOPipe implementation which writes to a socket
* @see LLIOPipe
*
* An instance of a socket writer wraps around an LLSocket and
* performs non-blocking writes of the data passed in.
*/
class LLIOSocketWriter : public LLIOPipe
{
public:
LLIOSocketWriter(LLSocket::ptr_t socket);
~LLIOSocketWriter();
protected:
/* @name LLIOPipe virtual implementations
*/
//@{
/**
* @brief Write the data in buffer to the socket.
*
* Since the socket pipe must exist for process to make any sense,
* this method will return STATUS_PRECONDITION_NOT_MET if it is
* not known.
* @param buffer Pointer to a buffer which needs processing.
* @param bytes Number of bytes to in buffer to process.
* @param eos True if this function is the last.
* @param read Number of bytes actually processed.
* @param pump The pump which is calling process. May be NULL.
* @param context A data structure to pass structured data
* @return A return code for the write.
*/
virtual EStatus process_impl(
const LLChannelDescriptors& channels,
buffer_ptr_t& buffer,
bool& eos,
LLSD& context,
LLPumpIO* pump);
//@}
protected:
LLSocket::ptr_t mDestination;
U8* mLastWritten;
bool mInitialized;
};
/**
* @class LLIOServerSocket
* @brief An IOPipe implementation which listens and spawns connected
* sockets.
* @see LLIOPipe, LLChainIOFactory
*
* Each server socket instance coordinates with a pump to ensure it
* only processes waiting connections. It uses the provided socket,
* and assumes it is correctly initialized. When the connection is
* established, the server will call the chain factory to build a
* chain, and attach a socket reader and the front and a socket writer
* at the end. It is up to the chain factory to create something which
* correctly handles the established connection using the reader as a
* source, and the writer as the final sink.
* The newly added chain timeout is in DEFAULT_CHAIN_EXPIRY_SECS unless
* adjusted with a call to setResponseTimeout().
*/
class LLIOServerSocket : public LLIOPipe
{
public:
typedef LLSocket::ptr_t socket_t;
typedef std::shared_ptr<LLChainIOFactory> factory_t;
LLIOServerSocket(apr_pool_t* pool, socket_t listener, factory_t reactor);
virtual ~LLIOServerSocket();
/**
* @brief Set the timeout for the generated chains.
*
* This value is passed directly to the LLPumpIO::addChain()
* method. The default on construction is set to
* DEFAULT_CHAIN_EXPIRY_SECS which is a reasonable value for most
* applications based on this library. Avoid passing in
* NEVER_CHAIN_EXPIRY_SECS unless you have another method of
* harvesting chains.
* @param timeout_secs The seconds before timeout for the response chain.
*/
void setResponseTimeout(F32 timeout_secs);
/* @name LLIOPipe virtual implementations
*/
//@{
protected:
/**
* @brief Process the data in buffer
*/
virtual EStatus process_impl(
const LLChannelDescriptors& channels,
buffer_ptr_t& buffer,
bool& eos,
LLSD& context,
LLPumpIO* pump);
//@}
protected:
apr_pool_t* mPool;
socket_t mListenSocket;
factory_t mReactor;
bool mInitialized;
F32 mResponseTimeout;
};
#if 0
/**
* @class LLIODataSocket
* @brief BRIEF_DESC
*
* THOROUGH_DESCRIPTION
*/
class LLIODataSocket : public LLIOSocket
{
public:
/**
* @brief Construct a datagram socket.
*
* If you pass in LLIOSocket::PORT_EPHEMERAL as the suggested
* port, The socket will not be in a 'listen' mode, but can still
* read data sent back to it's port. When suggested_port is not
* ephemeral or invalid and bind fails, the port discovery
* algorithm will search through a limited set of ports to
* try to find an open port. If that process fails, getPort() will
* return LLIOSocket::PORT_INVALID
* @param suggested_port The port you would like to bind. Use
* LLIOSocket::PORT_EPHEMERAL for an unspecified port.
* @param start_discovery_port The start range for
* @param pool The pool to use for allocation.
*/
LLIODataSocket(
U16 suggested_port,
U16 start_discovery_port,
apr_pool_t* pool);
virtual ~LLIODataSocket();
protected:
private:
apr_socket_t* mSocket;
};
#endif
#endif // LL_LLIOSOCKET_H
+98
View File
@@ -0,0 +1,98 @@
/**
* @file llioutil.cpp
* @author Phoenix
* @date 2005-10-05
* @brief Utility functionality for the io pipes.
*
* $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 "llioutil.h"
#include "llfasttimer.h"
/**
* LLIOFlush
*/
LLIOPipe::EStatus LLIOFlush::process_impl(
const LLChannelDescriptors& channels,
buffer_ptr_t& buffer,
bool& eos,
LLSD& context,
LLPumpIO* pump)
{
eos = true;
return STATUS_OK;
}
/**
* @class LLIOSleep
*/
LLIOPipe::EStatus LLIOSleep::process_impl(
const LLChannelDescriptors& channels,
buffer_ptr_t& buffer,
bool& eos,
LLSD& context,
LLPumpIO* pump)
{
LL_PROFILE_ZONE_SCOPED;
if(mSeconds > 0.0)
{
if(pump) pump->sleepChain(mSeconds);
mSeconds = 0.0;
return STATUS_BREAK;
}
return STATUS_DONE;
}
/**
* @class LLIOAddChain
*/
LLIOPipe::EStatus LLIOAddChain::process_impl(
const LLChannelDescriptors& channels,
buffer_ptr_t& buffer,
bool& eos,
LLSD& context,
LLPumpIO* pump)
{
LL_PROFILE_ZONE_SCOPED;
pump->addChain(mChain, mTimeout);
return STATUS_DONE;
}
/**
* LLChangeChannel
*/
LLChangeChannel::LLChangeChannel(S32 is, S32 becomes) :
mIs(is),
mBecomes(becomes)
{
}
void LLChangeChannel::operator()(LLSegment& segment)
{
if(segment.isOnChannel(mIs))
{
segment.setChannel(mBecomes);
}
}
+172
View File
@@ -0,0 +1,172 @@
/**
* @file llioutil.h
* @author Phoenix
* @date 2005-10-05
* @brief Helper classes for dealing with IOPipes
*
* $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_LLIOUTIL_H
#define LL_LLIOUTIL_H
#include "llbuffer.h"
#include "lliopipe.h"
#include "llpumpio.h"
/**
* @class LLIOFlush
* @brief This class is used as a mini chain head which drains the buffer.
* @see LLIOPipe
*
* An instance of this class acts as a useful chain head when all data
* is known, and you simply want to get the chain moving.
*/
class LLIOFlush : public LLIOPipe
{
public:
LLIOFlush() {}
virtual ~LLIOFlush() {}
protected:
/* @name LLIOPipe virtual implementations
*/
//@{
/**
* @brief Process the data in buffer
*/
EStatus process_impl(
const LLChannelDescriptors& channels,
buffer_ptr_t& buffer,
bool& eos,
LLSD& context,
LLPumpIO* pump);
//@}
protected:
};
/**
* @class LLIOSleep
* @brief This is a simple helper class which will hold a chain and
* process it later using pump mechanisms
* @see LLIOPipe
*/
class LLIOSleep : public LLIOPipe
{
public:
LLIOSleep(F64 sleep_seconds) : mSeconds(sleep_seconds) {}
virtual ~LLIOSleep() {}
protected:
/* @name LLIOPipe virtual implementations
*/
//@{
/**
* @brief Process the data in buffer
*/
EStatus process_impl(
const LLChannelDescriptors& channels,
buffer_ptr_t& buffer,
bool& eos,
LLSD& context,
LLPumpIO* pump);
//@}
protected:
F64 mSeconds;
};
/**
* @class LLIOAddChain
* @brief Simple pipe that just adds a chain to a pump.
* @see LLIOPipe
*/
class LLIOAddChain : public LLIOPipe
{
public:
LLIOAddChain(const LLPumpIO::chain_t& chain, F32 timeout) :
mChain(chain),
mTimeout(timeout)
{}
virtual ~LLIOAddChain() {}
protected:
/* @name LLIOPipe virtual implementations
*/
//@{
/**
* @brief Process the data in buffer
*/
EStatus process_impl(
const LLChannelDescriptors& channels,
buffer_ptr_t& buffer,
bool& eos,
LLSD& context,
LLPumpIO* pump);
//@}
protected:
LLPumpIO::chain_t mChain;
F32 mTimeout;
};
/**
* @class LLChangeChannel
* @brief This class changes the channel of segments in the buffer
* @see LLBufferArray
*
* This class is useful for iterating over the segments in a buffer
* array and changing each channel that matches to a different
* channel.
* Example:
* <code>
* set_in_to_out(LLChannelDescriptors channels, LLBufferArray* buf)
* {
* std::for_each(
* buf->beginSegment(),
* buf->endSegment(),
* LLChangeChannel(channels.in(), channels.out()));
* }
* </code>
*/
class LLChangeChannel
{
public:
/**
* @brief Constructor for iterating over a segment range to change channel.
*
* @param is The channel to match when looking at a segment.
* @param becomes The channel to set the segment when a match is found.
*/
LLChangeChannel(S32 is, S32 becomes);
/**
* @brief Do the work of changing the channel
*/
void operator()(LLSegment& segment);
protected:
S32 mIs;
S32 mBecomes;
};
#endif // LL_LLIOUTIL_H
+55
View File
@@ -0,0 +1,55 @@
/**
* @file llloginflags.h
* @brief Login flag constants.
*
* $LicenseInfo:firstyear=2003&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_LLLOGINFLAGS_H
#define LL_LLLOGINFLAGS_H
// Is this your first login to Second Life?
const U32 LOGIN_FLAG_FIRST_LOGIN = (1 << 0);
// Is this a trial account?
const U32 LOGIN_FLAG_TRIAL = (1 << 1);
// Stipend paid since last login?
const U32 LOGIN_FLAG_STIPEND_SINCE_LOGIN = (1 << 2);
// Is your account enabled?
const U32 LOGIN_FLAG_ENABLED = (1 << 3);
// Is the Pacific Time zone (aka the server time zone)
// currently observing daylight savings time?
const U32 LOGIN_FLAG_PACIFIC_DAYLIGHT_TIME = (1 << 4);
// Does the avatar have wearables or not
const U32 LOGIN_FLAG_GENDERED = (1 << 5);
// Kick flags
const U32 LOGIN_KICK_OK = 0x0;
const U32 LOGIN_KICK_NO_AGENT = (1 << 0);
const U32 LOGIN_KICK_SESSION_MISMATCH = (1 << 1);
const U32 LOGIN_KICK_NO_SIMULATOR = (1 << 2);
#endif
+395
View File
@@ -0,0 +1,395 @@
/**
* @file llmail.cpp
* @brief smtp helper functions.
*
* $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 "llmail.h"
#include "llwin32headers.h"
#include <string>
#include <sstream>
#include "apr_pools.h"
#include "apr_network_io.h"
#include "llapr.h"
#include "llbase32.h" // IM-to-email address
#include "llblowfishcipher.h"
#include "llerror.h"
#include "llhost.h"
#include "llsd.h"
#include "llstring.h"
#include "lluuid.h"
#include "net.h"
//
// constants
//
const size_t LL_MAX_KNOWN_GOOD_MAIL_SIZE = 4096;
static bool gMailEnabled = true;
static apr_pool_t* gMailPool;
static apr_sockaddr_t* gSockAddr;
static apr_socket_t* gMailSocket;
bool connect_smtp();
void disconnect_smtp();
//#if LL_WINDOWS
//SOCKADDR_IN gMailDstAddr, gMailSrcAddr, gMailLclAddr;
//#else
//struct sockaddr_in gMailDstAddr, gMailSrcAddr, gMailLclAddr;
//#endif
// Define this for a super-spammy mail mode.
//#define LL_LOG_ENTIRE_MAIL_MESSAGE_ON_SEND 1
bool connect_smtp()
{
// Prepare an soket to talk smtp
apr_status_t status;
status = apr_socket_create(
&gMailSocket,
gSockAddr->sa.sin.sin_family,
SOCK_STREAM,
APR_PROTO_TCP,
gMailPool);
if(ll_apr_warn_status(status)) return false;
status = apr_socket_connect(gMailSocket, gSockAddr);
if(ll_apr_warn_status(status))
{
status = apr_socket_close(gMailSocket);
ll_apr_warn_status(status);
return false;
}
return true;
}
void disconnect_smtp()
{
if(gMailSocket)
{
apr_status_t status = apr_socket_close(gMailSocket);
ll_apr_warn_status(status);
gMailSocket = NULL;
}
}
// Returns true on success.
// message should NOT be SMTP escaped.
// static
bool LLMail::send(
const char* from_name,
const char* from_address,
const char* to_name,
const char* to_address,
const char* subject,
const char* message,
const LLSD& headers)
{
std::string header = buildSMTPTransaction(
from_name,
from_address,
to_name,
to_address,
subject,
headers);
if(header.empty())
{
return false;
}
std::string message_str;
if(message)
{
message_str = message;
}
bool rv = send(header, message_str, to_address, from_address);
if(rv) return true;
return false;
}
// static
void LLMail::init(const std::string& hostname, apr_pool_t* pool)
{
gMailSocket = NULL;
if(hostname.empty() || !pool)
{
gMailPool = NULL;
gSockAddr = NULL;
}
else
{
gMailPool = pool;
// 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.
apr_status_t status = apr_sockaddr_info_get(
&gSockAddr,
hostname.c_str(),
APR_UNSPEC,
25,
APR_IPV4_ADDR_OK,
gMailPool);
ll_apr_warn_status(status);
}
}
// static
void LLMail::enable(bool mail_enabled)
{
gMailEnabled = mail_enabled;
}
// Test a subject line for RFC2822 compliance.
static bool valid_subject_chars(const char *subject)
{
for (; *subject != '\0'; subject++)
{
unsigned char c = *subject;
if (c == '\xa' || c == '\xd' || c > '\x7f')
{
return false;
}
}
return true;
}
// static
std::string LLMail::buildSMTPTransaction(
const char* from_name,
const char* from_address,
const char* to_name,
const char* to_address,
const char* subject,
const LLSD& headers)
{
if(!from_address || !to_address)
{
LL_INFOS() << "send_mail build_smtp_transaction reject: missing to and/or"
<< " from address." << LL_ENDL;
return std::string();
}
if(!valid_subject_chars(subject))
{
LL_INFOS() << "send_mail build_smtp_transaction reject: bad subject header: "
<< "to=<" << to_address
<< ">, from=<" << from_address << ">"
<< LL_ENDL;
return std::string();
}
std::ostringstream from_fmt;
if(from_name && from_name[0])
{
// "My Name" <myaddress@example.com>
from_fmt << "\"" << from_name << "\" <" << from_address << ">";
}
else
{
// <myaddress@example.com>
from_fmt << "<" << from_address << ">";
}
std::ostringstream to_fmt;
if(to_name && to_name[0])
{
to_fmt << "\"" << to_name << "\" <" << to_address << ">";
}
else
{
to_fmt << "<" << to_address << ">";
}
std::ostringstream header;
header
<< "HELO lindenlab.com\r\n"
<< "MAIL FROM:<" << from_address << ">\r\n"
<< "RCPT TO:<" << to_address << ">\r\n"
<< "DATA\r\n"
<< "From: " << from_fmt.str() << "\r\n"
<< "To: " << to_fmt.str() << "\r\n"
<< "Subject: " << subject << "\r\n";
if(headers.isMap())
{
LLSD::map_const_iterator iter = headers.beginMap();
LLSD::map_const_iterator end = headers.endMap();
for(; iter != end; ++iter)
{
header << (*iter).first << ": " << ((*iter).second).asString()
<< "\r\n";
}
}
header << "\r\n";
return header.str();
}
// static
bool LLMail::send(
const std::string& header,
const std::string& raw_message,
const char* from_address,
const char* to_address)
{
if(!from_address || !to_address)
{
LL_INFOS() << "send_mail reject: missing to and/or from address."
<< LL_ENDL;
return false;
}
// remove any "." SMTP commands to prevent injection (DEV-35777)
// we don't need to worry about "\r\n.\r\n" because of the
// "\n" --> "\n\n" conversion going into rfc2822_msg below
std::string message = raw_message;
std::string bad_string = "\n.\n";
std::string good_string = "\n..\n";
while (1)
{
auto index = message.find(bad_string);
if (index == std::string::npos) break;
message.replace(index, bad_string.size(), good_string);
}
// convert all "\n" into "\r\n"
std::ostringstream rfc2822_msg;
for(U32 i = 0; i < message.size(); ++i)
{
switch(message[i])
{
case '\0':
break;
case '\n':
// *NOTE: this is kinda busted if we're fed \r\n
rfc2822_msg << "\r\n";
break;
default:
rfc2822_msg << message[i];
break;
}
}
if(!gMailEnabled)
{
LL_INFOS() << "send_mail reject: mail system is disabled: to=<"
<< to_address << ">, from=<" << from_address
<< ">" << LL_ENDL;
// Any future interface to SMTP should return this as an
// error. --mark
return true;
}
if(!gSockAddr)
{
LL_WARNS() << "send_mail reject: mail system not initialized: to=<"
<< to_address << ">, from=<" << from_address
<< ">" << LL_ENDL;
return false;
}
if(!connect_smtp())
{
LL_WARNS() << "send_mail reject: SMTP connect failure: to=<"
<< to_address << ">, from=<" << from_address
<< ">" << LL_ENDL;
return false;
}
std::ostringstream smtp_fmt;
smtp_fmt << header << rfc2822_msg.str() << "\r\n" << ".\r\n" << "QUIT\r\n";
std::string smtp_transaction = smtp_fmt.str();
size_t original_size = smtp_transaction.size();
apr_size_t send_size = original_size;
apr_status_t status = apr_socket_send(
gMailSocket,
smtp_transaction.c_str(),
(apr_size_t*)&send_size);
disconnect_smtp();
if(ll_apr_warn_status(status))
{
LL_WARNS() << "send_mail socket failure: unable to write "
<< "to=<" << to_address
<< ">, from=<" << from_address << ">"
<< ", bytes=" << original_size
<< ", sent=" << send_size << LL_ENDL;
return false;
}
if(send_size >= LL_MAX_KNOWN_GOOD_MAIL_SIZE)
{
LL_WARNS() << "send_mail message has been shown to fail in testing "
<< "when sending messages larger than " << LL_MAX_KNOWN_GOOD_MAIL_SIZE
<< " bytes. The next log about success is potentially a lie." << LL_ENDL;
}
LL_DEBUGS() << "send_mail success: "
<< "to=<" << to_address
<< ">, from=<" << from_address << ">"
<< ", bytes=" << original_size
<< ", sent=" << send_size << LL_ENDL;
#if LL_LOG_ENTIRE_MAIL_MESSAGE_ON_SEND
LL_INFOS() << rfc2822_msg.str() << LL_ENDL;
#endif
return true;
}
// static
std::string LLMail::encryptIMEmailAddress(const LLUUID& from_agent_id,
const LLUUID& to_agent_id,
U32 time,
const U8* secret,
size_t secret_size)
{
#if LL_WINDOWS
return "blowfish-not-supported-on-windows";
#else
size_t data_size = 4 + UUID_BYTES + UUID_BYTES;
// Convert input data into a binary blob
std::vector<U8> data;
data.resize(data_size);
// *NOTE: This may suffer from endian issues. Could be htolememcpy.
memcpy(&data[0], &time, 4);
memcpy(&data[4], &from_agent_id.mData[0], UUID_BYTES);
memcpy(&data[4 + UUID_BYTES], &to_agent_id.mData[0], UUID_BYTES);
// Encrypt the blob
LLBlowfishCipher cipher(secret, secret_size);
size_t encrypted_size = cipher.requiredEncryptionSpace(data.size());
U8* encrypted = new U8[encrypted_size];
cipher.encrypt(&data[0], data_size, encrypted, encrypted_size);
std::string address = LLBase32::encode(encrypted, encrypted_size);
// Make it more pretty for humans.
LLStringUtil::toLower(address);
delete [] encrypted;
return address;
#endif
}
+130
View File
@@ -0,0 +1,130 @@
/**
* @file llmail.h
* @brief smtp helper functions.
*
* $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$
*/
#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, apr_pool_t* pool);
// Allow all email transmission to be disabled/enabled.
static void enable(bool mail_enabled);
/**
* @brief send an email
* @param from_name The name of the email sender
* @param from_address The email address for the sender
* @param to_name The name of the email recipient
* @param to_address The email recipient address
* @param subject The subject of the email
* @param headers optional X-Foo headers in an llsd map.
* @return Returns true if the call succeeds, false otherwise.
*
* Results in:
* From: "from_name" <from_address>
* To: "to_name" <to_address>
* Subject: subject
*
* message
*/
static bool send(
const char* from_name,
const char* from_address,
const char* to_name,
const char* to_address,
const char* subject,
const char* message,
const LLSD& headers = LLSD());
/**
* @brief build the complete smtp transaction & header for use in an
* mail.
*
* @param from_name The name of the email sender
* @param from_address The email address for the sender
* @param to_name The name of the email recipient
* @param to_address The email recipient address
* @param subject The subject of the email
* @param headers optional X-Foo headers in an llsd map.
* @return Returns the complete SMTP transaction mail header.
*/
static std::string buildSMTPTransaction(
const char* from_name,
const char* from_address,
const char* to_name,
const char* to_address,
const char* subject,
const LLSD& headers = LLSD());
/**
* @brief send an email with header and body.
*
* @param header The email header. Use build_mail_header().
* @param message The unescaped email message.
* @param from_address Used for debugging
* @param to_address Used for debugging
* @return Returns true if the message could be sent.
*/
static bool send(
const std::string& header,
const std::string& message,
const char* from_address,
const char* to_address);
// IM-to-email sessions use a "session id" based on an encrypted
// combination of from agent_id, to agent_id, and timestamp. When
// a user replies to an email we use the from_id to determine the
// sender's name and the to_id to route the message. The address
// is encrypted to prevent users from building addresses to spoof
// IMs from other users. The timestamps allow the "sessions" to
// expire, in case one of the sessions is stolen/hijacked.
//
// indra/tools/mailglue is responsible for parsing the inbound mail.
//
// secret: binary blob passed to blowfish, max length 56 bytes
// secret_size: length of blob, in bytes
//
// Returns: "base64" encoded email local-part, with _ and - as the
// non-alphanumeric characters. This allows better compatibility
// with email systems than the default / and + extra chars. JC
static std::string encryptIMEmailAddress(
const LLUUID& from_agent_id,
const LLUUID& to_agent_id,
U32 time,
const U8* secret,
size_t secret_size);
};
extern const size_t LL_MAX_KNOWN_GOOD_MAIL_SIZE;
#endif
+36
View File
@@ -0,0 +1,36 @@
/**
* @file llmessagebuilder.cpp
* @brief LLMessageBuilder class implementation
*
* $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
* 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 "llmessagebuilder.h"
//virtual
LLMessageBuilder::~LLMessageBuilder()
{
// even abstract base classes need a concrete destructor
}
+101
View File
@@ -0,0 +1,101 @@
/**
* @file llmessagebuilder.h
* @brief Declaration of LLMessageBuilder class.
*
* $LicenseInfo:firstyear=2007&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_LLMESSAGEBUILDER_H
#define LL_LLMESSAGEBUILDER_H
#include <string>
#include "stdtypes.h"
class LLMsgData;
class LLQuaternion;
class LLSD;
class LLUUID;
class LLVector3;
class LLVector3d;
class LLVector4;
class LLMessageBuilder
{
public:
//CLASS_LOG_TYPE(LLMessageBuilder);
virtual ~LLMessageBuilder();
virtual void newMessage(const char* name) = 0;
virtual void nextBlock(const char* blockname) = 0;
virtual bool removeLastBlock() = 0; // TODO: babbage: remove this horror
/** All add* methods expect pointers to canonical strings. */
virtual void addBinaryData(
const char* varname,
const void* data,
S32 size) = 0;
virtual void addBOOL(const char* varname, bool b) = 0;
virtual void addS8(const char* varname, S8 s) = 0;
virtual void addU8(const char* varname, U8 u) = 0;
virtual void addS16(const char* varname, S16 i) = 0;
virtual void addU16(const char* varname, U16 i) = 0;
virtual void addF32(const char* varname, F32 f) = 0;
virtual void addS32(const char* varname, S32 s) = 0;
virtual void addU32(const char* varname, U32 u) = 0;
virtual void addU64(const char* varname, U64 lu) = 0;
virtual void addF64(const char* varname, F64 d) = 0;
virtual void addVector3(const char* varname, const LLVector3& vec) = 0;
virtual void addVector4(const char* varname, const LLVector4& vec) = 0;
virtual void addVector3d(const char* varname, const LLVector3d& vec) = 0;
virtual void addQuat(const char* varname, const LLQuaternion& quat) = 0;
virtual void addUUID(const char* varname, const LLUUID& uuid) = 0;
virtual void addIPAddr(const char* varname, const U32 ip) = 0;
virtual void addIPPort(const char* varname, const U16 port) = 0;
virtual void addString(const char* varname, const char* s) = 0;
virtual void addString(const char* varname, const std::string& s) = 0;
virtual bool isMessageFull(const char* blockname) const = 0;
virtual void compressMessage(U8*& buf_ptr, U32& buffer_length) = 0;
virtual S32 getMessageSize() = 0;
virtual bool isBuilt() const = 0;
virtual bool isClear() const = 0;
virtual U32 buildMessage(
U8* buffer,
U32 buffer_size,
U8 offset_to_data) = 0;
/**< Return built message size */
virtual void clearMessage() = 0;
// TODO: babbage: remove this horror
virtual void setBuilt(bool b) = 0;
virtual const char* getMessageName() const = 0;
virtual void copyFromMessageData(const LLMsgData& data) = 0;
virtual void copyFromLLSD(const LLSD& data) = 0;
};
#endif // LL_LLMESSAGEBUILDER_H
+304
View File
@@ -0,0 +1,304 @@
/**
* @file llmessageconfig.cpp
* @brief Live file handling for messaging
*
* $LicenseInfo:firstyear=2000&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 "llmessageconfig.h"
#include "llfile.h"
#include "lllivefile.h"
#include "llsd.h"
#include "llsdutil.h"
#include "llsdserialize.h"
#include "message.h"
static const char messageConfigFileName[] = "message.xml";
static const F32 messageConfigRefreshRate = 5.0; // seconds
static std::string sServerName = "";
static std::string sConfigDir = "";
static std::string sServerDefault;
static LLSD sMessages;
class LLMessageConfigFile : public LLLiveFile
{
public:
LLMessageConfigFile() :
LLLiveFile(filename(), messageConfigRefreshRate),
mMaxQueuedEvents(0)
{ }
static std::string filename();
LLSD mMessages;
std::string mServerDefault;
static LLMessageConfigFile& instance();
// return the singleton configuration file
/* virtual */ bool loadFile();
void loadServerDefaults(const LLSD& data);
void loadMaxQueuedEvents(const LLSD& data);
void loadMessages(const LLSD& data);
void loadCapBans(const LLSD& blacklist);
void loadMessageBans(const LLSD& blacklist);
bool isCapBanned(const std::string& cap_name) const;
public:
LLSD mCapBans;
S32 mMaxQueuedEvents;
private:
static const S32 DEFAULT_MAX_QUEUED_EVENTS = 100;
};
std::string LLMessageConfigFile::filename()
{
std::ostringstream ostr;
ostr << sConfigDir//gAppSimp->getOption("configdir").asString()
<< "/" << messageConfigFileName;
return ostr.str();
}
LLMessageConfigFile& LLMessageConfigFile::instance()
{
static LLMessageConfigFile the_file;
the_file.checkAndReload();
return the_file;
}
// virtual
bool LLMessageConfigFile::loadFile()
{
LLSD data;
{
llifstream file(filename().c_str());
if (file.is_open())
{
LL_DEBUGS("AppInit") << "Loading message.xml file at " << filename() << LL_ENDL;
LLSDSerialize::fromXML(data, file);
}
if (data.isUndefined())
{
LL_INFOS("AppInit") << "LLMessageConfigFile::loadFile: file missing,"
" ill-formed, or simply undefined; not changing the"
" file" << LL_ENDL;
return false;
}
}
loadServerDefaults(data);
loadMaxQueuedEvents(data);
loadMessages(data);
loadCapBans(data);
loadMessageBans(data);
return true;
}
void LLMessageConfigFile::loadServerDefaults(const LLSD& data)
{
mServerDefault = data["serverDefaults"][sServerName].asString();
}
void LLMessageConfigFile::loadMaxQueuedEvents(const LLSD& data)
{
if (data.has("maxQueuedEvents"))
{
mMaxQueuedEvents = data["maxQueuedEvents"].asInteger();
}
else
{
mMaxQueuedEvents = DEFAULT_MAX_QUEUED_EVENTS;
}
}
void LLMessageConfigFile::loadMessages(const LLSD& data)
{
mMessages = data["messages"];
#ifdef DEBUG
std::ostringstream out;
LLSDXMLFormatter *formatter = new LLSDXMLFormatter;
formatter->format(mMessages, out);
LL_INFOS() << "loading ... " << out.str()
<< " LLMessageConfigFile::loadMessages loaded "
<< mMessages.size() << " messages" << LL_ENDL;
#endif
}
void LLMessageConfigFile::loadCapBans(const LLSD& data)
{
LLSD bans = data["capBans"];
if (!bans.isMap())
{
LL_INFOS("AppInit") << "LLMessageConfigFile::loadCapBans: missing capBans section"
<< LL_ENDL;
return;
}
mCapBans = bans;
LL_DEBUGS("AppInit") << "LLMessageConfigFile::loadCapBans: "
<< bans.size() << " ban tests" << LL_ENDL;
}
void LLMessageConfigFile::loadMessageBans(const LLSD& data)
{
LLSD bans = data["messageBans"];
if (!bans.isMap())
{
LL_INFOS("AppInit") << "LLMessageConfigFile::loadMessageBans: missing messageBans section"
<< LL_ENDL;
return;
}
gMessageSystem->setMessageBans(bans["trusted"], bans["untrusted"]);
}
bool LLMessageConfigFile::isCapBanned(const std::string& cap_name) const
{
LL_DEBUGS() << "mCapBans is " << LLSDNotationStreamer(mCapBans) << LL_ENDL;
return mCapBans[cap_name];
}
//---------------------------------------------------------------
// LLMessageConfig
//---------------------------------------------------------------
//static
void LLMessageConfig::initClass(const std::string& server_name,
const std::string& config_dir)
{
sServerName = server_name;
sConfigDir = config_dir;
(void) LLMessageConfigFile::instance();
LL_DEBUGS("AppInit") << "LLMessageConfig::initClass config file "
<< config_dir << "/" << messageConfigFileName << LL_ENDL;
}
//static
void LLMessageConfig::useConfig(const LLSD& config)
{
LLMessageConfigFile &the_file = LLMessageConfigFile::instance();
the_file.loadServerDefaults(config);
the_file.loadMaxQueuedEvents(config);
the_file.loadMessages(config);
the_file.loadCapBans(config);
the_file.loadMessageBans(config);
}
//static
LLMessageConfig::Flavor LLMessageConfig::getServerDefaultFlavor()
{
LLMessageConfigFile& file = LLMessageConfigFile::instance();
if (file.mServerDefault == "llsd")
{
return LLSD_FLAVOR;
}
if (file.mServerDefault == "template")
{
return TEMPLATE_FLAVOR;
}
return NO_FLAVOR;
}
//static
S32 LLMessageConfig::getMaxQueuedEvents()
{
LLMessageConfigFile& file = LLMessageConfigFile::instance();
return file.mMaxQueuedEvents;
}
//static
LLMessageConfig::Flavor LLMessageConfig::getMessageFlavor(const std::string& msg_name)
{
LLMessageConfigFile& file = LLMessageConfigFile::instance();
LLSD config = file.mMessages[msg_name];
if (config["flavor"].asString() == "llsd")
{
return LLSD_FLAVOR;
}
if (config["flavor"].asString() == "template")
{
return TEMPLATE_FLAVOR;
}
return NO_FLAVOR;
}
//static
LLMessageConfig::SenderTrust LLMessageConfig::getSenderTrustedness(
const std::string& msg_name)
{
LLMessageConfigFile& file = LLMessageConfigFile::instance();
LLSD config = file.mMessages[msg_name];
if (config.has("trusted-sender"))
{
return config["trusted-sender"].asBoolean() ? TRUSTED : UNTRUSTED;
}
return NOT_SET;
}
//static
bool LLMessageConfig::isValidMessage(const std::string& msg_name)
{
if (sServerName.empty())
{
LL_ERRS() << "LLMessageConfig::initClass() not called" << LL_ENDL;
}
LLMessageConfigFile& file = LLMessageConfigFile::instance();
return file.mMessages.has(msg_name);
}
//static
bool LLMessageConfig::onlySendLatest(const std::string& msg_name)
{
LLMessageConfigFile& file = LLMessageConfigFile::instance();
LLSD config = file.mMessages[msg_name];
return config["only-send-latest"].asBoolean();
}
bool LLMessageConfig::isCapBanned(const std::string& cap_name)
{
return LLMessageConfigFile::instance().isCapBanned(cap_name);
}
// return the web-service path to use for a given
// message. This entry *should* match the entry
// in simulator.xml!
LLSD LLMessageConfig::getConfigForMessage(const std::string& msg_name)
{
if (sServerName.empty())
{
LL_ERRS() << "LLMessageConfig::isMessageTrusted(name) before"
<< " LLMessageConfig::initClass()" << LL_ENDL;
}
LLMessageConfigFile& file = LLMessageConfigFile::instance();
// LLSD for the CamelCase message name
LLSD config = file.mMessages[msg_name];
return config;
}
+56
View File
@@ -0,0 +1,56 @@
/**
* @file llmessageconfig.h
* @brief Live file handling for messaging
*
* $LicenseInfo:firstyear=2000&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_MESSAGECONFIG_H
#define LL_MESSAGECONFIG_H
#include <string>
#include "llsd.h"
class LLSD;
class LLMessageConfig
{
public:
enum Flavor { NO_FLAVOR=0, LLSD_FLAVOR=1, TEMPLATE_FLAVOR=2 };
enum SenderTrust { NOT_SET=0, UNTRUSTED=1, TRUSTED=2 };
static void initClass(const std::string& server_name,
const std::string& config_dir);
static void useConfig(const LLSD& config);
static Flavor getServerDefaultFlavor();
static S32 getMaxQueuedEvents();
// For individual messages
static Flavor getMessageFlavor(const std::string& msg_name);
static SenderTrust getSenderTrustedness(const std::string& msg_name);
static bool isValidMessage(const std::string& msg_name);
static bool onlySendLatest(const std::string& msg_name);
static bool isCapBanned(const std::string& cap_name);
static LLSD getConfigForMessage(const std::string& msg_name);
};
#endif // LL_MESSAGECONFIG_H
+62
View File
@@ -0,0 +1,62 @@
/**
* @file llmessagereader.cpp
* @brief LLMessageReader class implementation
*
* $LicenseInfo:firstyear=2007&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 "llmessagereader.h"
static bool sTimeDecodes = false;
static F32 sTimeDecodesSpamThreshold = 0.05f;
//virtual
LLMessageReader::~LLMessageReader()
{
// even abstract base classes need a concrete destructor
}
//static
void LLMessageReader::setTimeDecodes(bool b)
{
sTimeDecodes = b;
}
//static
void LLMessageReader::setTimeDecodesSpamThreshold(F32 seconds)
{
sTimeDecodesSpamThreshold = seconds;
}
//static
bool LLMessageReader::getTimeDecodes()
{
return sTimeDecodes;
}
//static
F32 LLMessageReader::getTimeDecodesSpamThreshold()
{
return sTimeDecodesSpamThreshold;
}
+94
View File
@@ -0,0 +1,94 @@
/**
* @file llmessagereader.h
* @brief Declaration of LLMessageReader class.
*
* $LicenseInfo:firstyear=2007&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_LLMESSAGEREADER_H
#define LL_LLMESSAGEREADER_H
#include "stdtypes.h"
class LLHost;
class LLMessageBuilder;
class LLMsgData;
class LLQuaternion;
class LLUUID;
class LLVector3;
class LLVector3d;
class LLVector4;
// Error return values for getSize() functions
const S32 LL_BLOCK_NOT_IN_MESSAGE = -1;
const S32 LL_VARIABLE_NOT_IN_BLOCK = -2;
const S32 LL_MESSAGE_ERROR = -3;
class LLMessageReader
{
public:
virtual ~LLMessageReader();
/** All get* methods expect pointers to canonical strings. */
virtual void getBinaryData(const char *blockname, const char *varname, void *datap, S32 size, S32 blocknum = 0, S32 max_size = S32_MAX) = 0;
virtual void getBOOL(const char *block, const char *var, bool &data, S32 blocknum = 0) = 0;
virtual void getS8(const char *block, const char *var, S8 &data, S32 blocknum = 0) = 0;
virtual void getU8(const char *block, const char *var, U8 &data, S32 blocknum = 0) = 0;
virtual void getS16(const char *block, const char *var, S16 &data, S32 blocknum = 0) = 0;
virtual void getU16(const char *block, const char *var, U16 &data, S32 blocknum = 0) = 0;
virtual void getS32(const char *block, const char *var, S32 &data, S32 blocknum = 0) = 0;
virtual void getF32(const char *block, const char *var, F32 &data, S32 blocknum = 0) = 0;
virtual void getU32(const char *block, const char *var, U32 &data, S32 blocknum = 0) = 0;
virtual void getU64(const char *block, const char *var, U64 &data, S32 blocknum = 0) = 0;
virtual void getF64(const char *block, const char *var, F64 &data, S32 blocknum = 0) = 0;
virtual void getVector3(const char *block, const char *var, LLVector3 &vec, S32 blocknum = 0) = 0;
virtual void getVector4(const char *block, const char *var, LLVector4 &vec, S32 blocknum = 0) = 0;
virtual void getVector3d(const char *block, const char *var, LLVector3d &vec, S32 blocknum = 0) = 0;
virtual void getQuat(const char *block, const char *var, LLQuaternion &q, S32 blocknum = 0) = 0;
virtual void getUUID(const char *block, const char *var, LLUUID &uuid, S32 blocknum = 0) = 0;
virtual void getIPAddr(const char *block, const char *var, U32 &ip, S32 blocknum = 0) = 0;
virtual void getIPPort(const char *block, const char *var, U16 &port, S32 blocknum = 0) = 0;
virtual void getString(const char *block, const char *var, S32 buffer_size, char *buffer, S32 blocknum = 0) = 0;
virtual void getString(const char *block, const char *var, std::string& outstr, S32 blocknum = 0) = 0;
virtual S32 getNumberOfBlocks(const char *blockname) = 0;
virtual S32 getSize(const char *blockname, const char *varname) = 0;
virtual S32 getSize(const char *blockname, S32 blocknum, const char *varname) = 0;
virtual void clearMessage() = 0;
/** Returns pointer to canonical (prehashed) string. */
virtual const char* getMessageName() const = 0;
virtual S32 getMessageSize() const = 0;
virtual void copyToBuilder(LLMessageBuilder&) const = 0;
static void setTimeDecodes(bool b);
static bool getTimeDecodes();
static void setTimeDecodesSpamThreshold(F32 seconds);
static F32 getTimeDecodesSpamThreshold();
};
#endif // LL_LLMESSAGEREADER_H
@@ -0,0 +1,44 @@
/**
* @file llmessagesenderinterface.h
* @brief
*
* $LicenseInfo:firstyear=2008&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_LLMESSAGESENDERINTERFACE_H
#define LL_LLMESSAGESENDERINTERFACE_H
#include "linden_common.h"
#include "llstoredmessage.h"
class LLHost;
class LLSD;
class LLMessageSenderInterface
{
public:
virtual ~LLMessageSenderInterface() {}
virtual S32 sendMessage(const LLHost& host, LLStoredMessagePtr message) = 0;
};
#endif // LL_LLMESSAGESENDERINTERFACE_H
+192
View File
@@ -0,0 +1,192 @@
/**
* @file llmessagetemplate.cpp
* @brief Implementation of message template classes.
*
* $LicenseInfo:firstyear=2007&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 "llmessagetemplate.h"
#include "message.h"
void LLMsgVarData::addData(const void *data, S32 size, EMsgVariableType type, S32 data_size)
{
mSize = size;
mDataSize = data_size;
if ( (type != MVT_VARIABLE) && (type != MVT_FIXED)
&& (mType != MVT_VARIABLE) && (mType != MVT_FIXED))
{
if (mType != type)
{
LL_WARNS() << "Type mismatch in LLMsgVarData::addData for " << mName
<< LL_ENDL;
}
}
if(size)
{
delete[] mData; // Delete it if it already exists
mData = new U8[size];
htolememcpy(mData, data, mType, size);
}
}
void LLMsgData::addDataFast(char *blockname, char *varname, const void *data, S32 size, EMsgVariableType type, S32 data_size)
{
// remember that if the blocknumber is > 0 then the number is appended to the name
char *namep = (char *)blockname;
LLMsgBlkData* block_data = mMemberBlocks[namep];
if (block_data->mBlockNumber)
{
namep += block_data->mBlockNumber;
block_data->addData(varname, data, size, type, data_size);
}
else
{
block_data->addData(varname, data, size, type, data_size);
}
}
// LLMessageVariable functions and friends
std::ostream& operator<<(std::ostream& s, LLMessageVariable &msg)
{
s << "\t\t" << msg.mName << " (";
switch (msg.mType)
{
case MVT_FIXED:
s << "Fixed, " << msg.mSize << " bytes total)\n";
break;
case MVT_VARIABLE:
s << "Variable, " << msg.mSize << " bytes of size info)\n";
break;
default:
s << "Unknown\n";
break;
}
return s;
}
// LLMessageBlock functions and friends
std::ostream& operator<<(std::ostream& s, LLMessageBlock &msg)
{
s << "\t" << msg.mName << " (";
switch (msg.mType)
{
case MBT_SINGLE:
s << "Fixed";
break;
case MBT_MULTIPLE:
s << "Multiple - " << msg.mNumber << " copies";
break;
case MBT_VARIABLE:
s << "Variable";
break;
default:
s << "Unknown";
break;
}
if (msg.mTotalSize != -1)
{
s << ", " << msg.mTotalSize << " bytes each, " << msg.mNumber*msg.mTotalSize << " bytes total)\n";
}
else
{
s << ")\n";
}
for (LLMessageBlock::message_variable_map_t::iterator iter = msg.mMemberVariables.begin();
iter != msg.mMemberVariables.end(); iter++)
{
LLMessageVariable& ci = *(*iter);
s << ci;
}
return s;
}
// LLMessageTemplate functions and friends
std::ostream& operator<<(std::ostream& s, LLMessageTemplate &msg)
{
switch (msg.mFrequency)
{
case MFT_HIGH:
s << "========================================\n" << "Message #" << msg.mMessageNumber << "\n" << msg.mName << " (";
s << "High";
break;
case MFT_MEDIUM:
s << "========================================\n" << "Message #";
s << (msg.mMessageNumber & 0xFF) << "\n" << msg.mName << " (";
s << "Medium";
break;
case MFT_LOW:
s << "========================================\n" << "Message #";
s << (msg.mMessageNumber & 0xFFFF) << "\n" << msg.mName << " (";
s << "Low";
break;
default:
s << "Unknown";
break;
}
if (msg.mTotalSize != -1)
{
s << ", " << msg.mTotalSize << " bytes total)\n";
}
else
{
s << ")\n";
}
for (LLMessageTemplate::message_block_map_t::iterator iter = msg.mMemberBlocks.begin();
iter != msg.mMemberBlocks.end(); iter++)
{
LLMessageBlock* ci = *iter;
s << *ci;
}
return s;
}
void LLMessageTemplate::banUdp()
{
static const char* deprecation[] = {
"NotDeprecated",
"Deprecated",
"UDPDeprecated",
"UDPBlackListed"
};
if (mDeprecation != MD_DEPRECATED)
{
LL_INFOS() << "Setting " << mName << " to UDPBlackListed was " << deprecation[mDeprecation] << LL_ENDL;
mDeprecation = MD_UDPBLACKLISTED;
}
else
{
LL_INFOS() << mName << " is already more deprecated than UDPBlackListed" << LL_ENDL;
}
}
+439
View File
@@ -0,0 +1,439 @@
/**
* @file llmessagetemplate.h
* @brief Declaration of the message template classes.
*
* $LicenseInfo:firstyear=2007&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_LLMESSAGETEMPLATE_H
#define LL_LLMESSAGETEMPLATE_H
#include "message.h" // TODO: babbage: Remove...
#include "llstl.h"
#include "llindexedvector.h"
#include "nd/ndexceptions.h" // <FS:ND/> For ndxran
class LLMsgVarData
{
public:
LLMsgVarData() : mName(NULL), mSize(-1), mDataSize(-1), mData(NULL), mType(MVT_U8)
{
}
LLMsgVarData(const char *name, EMsgVariableType type) : mSize(-1), mDataSize(-1), mData(NULL), mType(type)
{
mName = (char *)name;
}
~LLMsgVarData()
{
// copy constructor just copies the mData pointer, so only delete mData explicitly
}
void deleteData()
{
delete[] mData;
mData = NULL;
}
void addData(const void *indata, S32 size, EMsgVariableType type, S32 data_size = -1);
char *getName() const { return mName; }
S32 getSize() const { return mSize; }
void *getData() { return (void*)mData; }
const void *getData() const { return (const void*)mData; }
S32 getDataSize() const { return mDataSize; }
EMsgVariableType getType() const { return mType; }
protected:
char *mName;
S32 mSize;
S32 mDataSize;
U8 *mData;
EMsgVariableType mType;
};
class LLMsgBlkData
{
public:
LLMsgBlkData(const char *name, S32 blocknum) : mBlockNumber(blocknum), mTotalSize(-1)
{
mName = (char *)name;
}
~LLMsgBlkData()
{
for (msg_var_data_map_t::iterator iter = mMemberVarData.begin();
iter != mMemberVarData.end(); iter++)
{
iter->deleteData();
}
}
void addVariable(const char *name, EMsgVariableType type)
{
LLMsgVarData tmp(name,type);
mMemberVarData[name] = tmp;
}
void addData(char *name, const void *data, S32 size, EMsgVariableType type, S32 data_size = -1)
{
LLMsgVarData* temp = &mMemberVarData[name]; // creates a new entry if one doesn't exist
temp->addData(data, size, type, data_size);
}
S32 mBlockNumber;
typedef LLIndexedVector<LLMsgVarData, const char *, 8> msg_var_data_map_t;
msg_var_data_map_t mMemberVarData;
char *mName;
S32 mTotalSize;
};
class LLMsgData
{
public:
LLMsgData(const char *name) : mTotalSize(-1)
{
mName = (char *)name;
}
~LLMsgData()
{
for_each(mMemberBlocks.begin(), mMemberBlocks.end(), DeletePairedPointer());
mMemberBlocks.clear();
}
void addBlock(LLMsgBlkData *blockp)
{
mMemberBlocks[blockp->mName] = blockp;
}
void addDataFast(char *blockname, char *varname, const void *data, S32 size, EMsgVariableType type, S32 data_size = -1);
public:
typedef std::map<char*, LLMsgBlkData*> msg_blk_data_map_t;
msg_blk_data_map_t mMemberBlocks;
char *mName;
S32 mTotalSize;
};
// LLMessage* classes store the template of messages
class LLMessageVariable
{
public:
LLMessageVariable() : mName(NULL), mType(MVT_NULL), mSize(-1)
{
}
LLMessageVariable(char *name) : mType(MVT_NULL), mSize(-1)
{
mName = name;
}
LLMessageVariable(const char *name, const EMsgVariableType type, const S32 size) : mType(type), mSize(size)
{
mName = LLMessageStringTable::getInstance()->getString(name);
}
~LLMessageVariable() {}
friend std::ostream& operator<<(std::ostream& s, LLMessageVariable &msg);
EMsgVariableType getType() const { return mType; }
S32 getSize() const { return mSize; }
char *getName() const { return mName; }
protected:
char *mName;
EMsgVariableType mType;
S32 mSize;
};
typedef enum e_message_block_type
{
MBT_NULL,
MBT_SINGLE,
MBT_MULTIPLE,
MBT_VARIABLE,
MBT_EOF
} EMsgBlockType;
class LLMessageBlock
{
public:
LLMessageBlock(const char *name, EMsgBlockType type, S32 number = 1) : mType(type), mNumber(number), mTotalSize(0)
{
mName = LLMessageStringTable::getInstance()->getString(name);
}
~LLMessageBlock()
{
for_each(mMemberVariables.begin(), mMemberVariables.end(), DeletePointer());
}
void addVariable(char *name, const EMsgVariableType type, const S32 size)
{
LLMessageVariable** varp = &mMemberVariables[name];
if (*varp != NULL)
{
LL_ERRS() << name << " has already been used as a variable name!" << LL_ENDL;
}
*varp = new LLMessageVariable(name, type, size);
if (((*varp)->getType() != MVT_VARIABLE)
&&(mTotalSize != -1))
{
mTotalSize += (*varp)->getSize();
}
else
{
mTotalSize = -1;
}
}
EMsgVariableType getVariableType(char *name)
{
return (mMemberVariables[name])->getType();
}
S32 getVariableSize(char *name)
{
return (mMemberVariables[name])->getSize();
}
const LLMessageVariable* getVariable(char* name) const
{
message_variable_map_t::const_iterator iter = mMemberVariables.find(name);
return iter != mMemberVariables.end()? *iter : NULL;
}
friend std::ostream& operator<<(std::ostream& s, LLMessageBlock &msg);
typedef LLIndexedVector<LLMessageVariable*, const char *, 8> message_variable_map_t;
message_variable_map_t mMemberVariables;
char *mName;
EMsgBlockType mType;
S32 mNumber;
S32 mTotalSize;
};
enum EMsgFrequency
{
MFT_NULL = 0, // value is size of message number in bytes
MFT_HIGH = 1,
MFT_MEDIUM = 2,
MFT_LOW = 4
};
typedef enum e_message_trust
{
MT_TRUST,
MT_NOTRUST
} EMsgTrust;
enum EMsgEncoding
{
ME_UNENCODED,
ME_ZEROCODED
};
enum EMsgDeprecation
{
MD_NOTDEPRECATED,
MD_UDPDEPRECATED,
MD_UDPBLACKLISTED,
MD_DEPRECATED
};
class LLMessageTemplate
{
public:
LLMessageTemplate(const char *name, U32 message_number, EMsgFrequency freq)
:
//mMemberBlocks(),
mName(NULL),
mFrequency(freq),
mTrust(MT_NOTRUST),
mEncoding(ME_ZEROCODED),
mDeprecation(MD_NOTDEPRECATED),
mMessageNumber(message_number),
mTotalSize(0),
mReceiveCount(0),
mReceiveBytes(0),
mReceiveInvalid(0),
mDecodeTimeThisFrame(0.f),
mTotalDecoded(0),
mTotalDecodeTime(0.f),
mMaxDecodeTimePerMsg(0.f),
mBanFromTrusted(false),
mBanFromUntrusted(false),
mHandlerFunc(NULL),
mUserData(NULL)
{
mName = LLMessageStringTable::getInstance()->getString(name);
}
~LLMessageTemplate()
{
for_each(mMemberBlocks.begin(), mMemberBlocks.end(), DeletePointer());
}
void addBlock(LLMessageBlock *blockp)
{
LLMessageBlock** member_blockp = &mMemberBlocks[blockp->mName];
if (*member_blockp != NULL)
{
LL_ERRS() << "Block " << blockp->mName
<< "has already been used as a block name!" << LL_ENDL;
}
*member_blockp = blockp;
if ( (mTotalSize != -1)
&&(blockp->mTotalSize != -1)
&&( (blockp->mType == MBT_SINGLE)
||(blockp->mType == MBT_MULTIPLE)))
{
mTotalSize += blockp->mNumber*blockp->mTotalSize;
}
else
{
mTotalSize = -1;
}
}
LLMessageBlock *getBlock(char *name)
{
return mMemberBlocks[name];
}
// Trusted messages can only be recieved on trusted circuits.
void setTrust(EMsgTrust t)
{
mTrust = t;
}
EMsgTrust getTrust(void) const
{
return mTrust;
}
// controls for how the message should be encoded
void setEncoding(EMsgEncoding e)
{
mEncoding = e;
}
EMsgEncoding getEncoding() const
{
return mEncoding;
}
void setDeprecation(EMsgDeprecation d)
{
mDeprecation = d;
}
EMsgDeprecation getDeprecation() const
{
return mDeprecation;
}
void setHandlerFunc(void (*handler_func)(LLMessageSystem *msgsystem, void **user_data), void **user_data)
{
mHandlerFunc = handler_func;
mUserData = user_data;
}
bool callHandlerFunc(LLMessageSystem *msgsystem) const
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
if (mHandlerFunc)
{
// <FS:ND> Handle invalid packets by throwing an exception and a graceful continue
// mHandlerFunc(msgsystem, mUserData);
try
{
mHandlerFunc(msgsystem, mUserData);
}
catch( nd::exceptions::xran &ex )
{
LL_WARNS() << ex.what() << LL_ENDL;
}
// </FS:ND>
return true;
}
return false;
}
bool isUdpBanned() const
{
return mDeprecation == MD_UDPBLACKLISTED;
}
void banUdp();
bool isBanned(bool trustedSource) const
{
return trustedSource ? mBanFromTrusted : mBanFromUntrusted;
}
friend std::ostream& operator<<(std::ostream& s, LLMessageTemplate &msg);
const LLMessageBlock* getBlock(char* name) const
{
message_block_map_t::const_iterator iter = mMemberBlocks.find(name);
return iter != mMemberBlocks.end()? *iter : NULL;
}
public:
typedef LLIndexedVector<LLMessageBlock*, char*, 8> message_block_map_t;
message_block_map_t mMemberBlocks;
char *mName;
EMsgFrequency mFrequency;
EMsgTrust mTrust;
EMsgEncoding mEncoding;
EMsgDeprecation mDeprecation;
U32 mMessageNumber;
S32 mTotalSize;
U32 mReceiveCount; // how many of this template have been received since last reset
U32 mReceiveBytes; // How many bytes received
U32 mReceiveInvalid; // How many "invalid" packets
F32 mDecodeTimeThisFrame; // Total seconds spent decoding this frame
U32 mTotalDecoded; // Total messages successfully decoded
F32 mTotalDecodeTime; // Total time successfully decoding messages
F32 mMaxDecodeTimePerMsg;
bool mBanFromTrusted;
bool mBanFromUntrusted;
private:
// message handler function (this is set by each application)
void (*mHandlerFunc)(LLMessageSystem *msgsystem, void **user_data);
void **mUserData;
};
#endif // LL_LLMESSAGETEMPLATE_H
+761
View File
@@ -0,0 +1,761 @@
/**
* @file llmessagetemplateparser.cpp
* @brief LLMessageTemplateParser implementation
*
* $LicenseInfo:firstyear=2007&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 "llmessagetemplateparser.h"
#include <boost/tokenizer.hpp>
// What follows is a bunch of C functions to do validation.
// Lets support a small subset of regular expressions here
// Syntax is a string made up of:
// a - checks against alphanumeric ([A-Za-z0-9])
// c - checks against character ([A-Za-z])
// f - checks against first variable character ([A-Za-z_])
// v - checks against variable ([A-Za-z0-9_])
// s - checks against sign of integer ([-0-9])
// d - checks against integer digit ([0-9])
// * - repeat last check
// checks 'a'
bool b_return_alphanumeric_ok(char c)
{
if ( ( (c < 'A')
||(c > 'Z'))
&&( (c < 'a')
||(c > 'z'))
&&( (c < '0')
||(c > '9')))
{
return false;
}
return true;
}
// checks 'c'
bool b_return_character_ok(char c)
{
if ( ( (c < 'A')
||(c > 'Z'))
&&( (c < 'a')
||(c > 'z')))
{
return false;
}
return true;
}
// checks 'f'
bool b_return_first_variable_ok(char c)
{
if ( ( (c < 'A')
||(c > 'Z'))
&&( (c < 'a')
||(c > 'z'))
&&(c != '_'))
{
return false;
}
return true;
}
// checks 'v'
bool b_return_variable_ok(char c)
{
if ( ( (c < 'A')
||(c > 'Z'))
&&( (c < 'a')
||(c > 'z'))
&&( (c < '0')
||(c > '9'))
&&(c != '_'))
{
return false;
}
return true;
}
// checks 's'
bool b_return_signed_integer_ok(char c)
{
if ( ( (c < '0')
||(c > '9'))
&&(c != '-'))
{
return false;
}
return true;
}
// checks 'd'
bool b_return_integer_ok(char c)
{
if ( (c < '0')
||(c > '9'))
{
return false;
}
return true;
}
bool (*gParseCheckCharacters[])(char c) =
{
b_return_alphanumeric_ok,
b_return_character_ok,
b_return_first_variable_ok,
b_return_variable_ok,
b_return_signed_integer_ok,
b_return_integer_ok
};
S32 get_checker_number(char checker)
{
switch(checker)
{
case 'a':
return 0;
case 'c':
return 1;
case 'f':
return 2;
case 'v':
return 3;
case 's':
return 4;
case 'd':
return 5;
case '*':
return 9999;
default:
return -1;
}
}
// check token based on passed simplified regular expression
bool b_check_token(const char *token, const char *regexp)
{
S32 tptr, rptr = 0;
S32 current_checker, next_checker = 0;
current_checker = get_checker_number(regexp[rptr++]);
if (current_checker == -1)
{
LL_ERRS() << "Invalid regular expression value!" << LL_ENDL;
return false;
}
if (current_checker == 9999)
{
LL_ERRS() << "Regular expression can't start with *!" << LL_ENDL;
return false;
}
for (tptr = 0; token[tptr]; tptr++)
{
if (current_checker == -1)
{
LL_ERRS() << "Input exceeds regular expression!\nDid you forget a *?" << LL_ENDL;
return false;
}
if (!gParseCheckCharacters[current_checker](token[tptr]))
{
return false;
}
if (next_checker != 9999)
{
next_checker = get_checker_number(regexp[rptr++]);
if (next_checker != 9999)
{
current_checker = next_checker;
}
}
}
return true;
}
// C variable can be made up of upper or lower case letters, underscores, or numbers, but can't start with a number
bool b_variable_ok(const char *token)
{
if (!b_check_token(token, "fv*"))
{
LL_WARNS() << "Token '" << token << "' isn't a variable!" << LL_ENDL;
return false;
}
return true;
}
// An integer is made up of the digits 0-9 and may be preceded by a '-'
bool b_integer_ok(const char *token)
{
if (!b_check_token(token, "sd*"))
{
LL_WARNS() << "Token isn't an integer!" << LL_ENDL;
return false;
}
return true;
}
// An integer is made up of the digits 0-9
bool b_positive_integer_ok(const char *token)
{
if (!b_check_token(token, "d*"))
{
LL_WARNS() << "Token isn't an integer!" << LL_ENDL;
return false;
}
return true;
}
// Done with C functions, here's the tokenizer.
typedef boost::tokenizer< boost::char_separator<char> > tokenizer;
LLTemplateTokenizer::LLTemplateTokenizer(const std::string & contents) : mStarted(false), mTokens()
{
boost::char_separator<char> newline("\r\n", "", boost::keep_empty_tokens);
boost::char_separator<char> spaces(" \t");
U32 line_counter = 1;
tokenizer line_tokens(contents, newline);
for(tokenizer::iterator line_iter = line_tokens.begin();
line_iter != line_tokens.end();
++line_iter, ++line_counter)
{
tokenizer word_tokens(*line_iter, spaces);
for(tokenizer::iterator word_iter = word_tokens.begin();
word_iter != word_tokens.end();
++word_iter)
{
if((*word_iter)[0] == '/')
{
break; // skip to end of line on comments
}
positioned_token pt;// = new positioned_token();
pt.str = std::string(*word_iter);
pt.line = line_counter;
mTokens.push_back(pt);
}
}
mCurrent = mTokens.begin();
}
void LLTemplateTokenizer::inc()
{
if(atEOF())
{
error("trying to increment token of EOF");
}
else if(mStarted)
{
++mCurrent;
}
else
{
mStarted = true;
mCurrent = mTokens.begin();
}
}
void LLTemplateTokenizer::dec()
{
if(mCurrent == mTokens.begin())
{
if(mStarted)
{
mStarted = false;
}
else
{
error("trying to decrement past beginning of file");
}
}
else
{
mCurrent--;
}
}
std::string LLTemplateTokenizer::get() const
{
if(atEOF())
{
error("trying to get EOF");
}
return mCurrent->str;
}
U32 LLTemplateTokenizer::line() const
{
if(atEOF())
{
return 0;
}
return mCurrent->line;
}
bool LLTemplateTokenizer::atEOF() const
{
return mCurrent == mTokens.end();
}
std::string LLTemplateTokenizer::next()
{
inc();
return get();
}
bool LLTemplateTokenizer::want(const std::string & token)
{
if(atEOF()) return false;
inc();
if(atEOF()) return false;
if(get() != token)
{
dec(); // back up a step
return false;
}
return true;
}
bool LLTemplateTokenizer::wantEOF()
{
// see if the next token is EOF
if(atEOF()) return true;
inc();
if(!atEOF())
{
dec(); // back up a step
return false;
}
return true;
}
void LLTemplateTokenizer::error(std::string message) const
{
if(atEOF())
{
LL_ERRS() << "Unexpected end of file: " << message << LL_ENDL;
}
else
{
LL_ERRS() << "Problem parsing message template at line "
<< line() << ", with token '" << get() << "' : "
<< message << LL_ENDL;
}
}
// Done with tokenizer, next is the parser.
LLTemplateParser::LLTemplateParser(LLTemplateTokenizer & tokens):
mVersion(0.f),
mMessages()
{
// the version number should be the first thing in the file
if (tokens.want("version"))
{
// version number
std::string vers_string = tokens.next();
mVersion = (F32)atof(vers_string.c_str());
LL_INFOS() << "### Message template version " << mVersion << " ###" << LL_ENDL;
}
else
{
LL_ERRS() << "Version must be first in the message template, found "
<< tokens.next() << LL_ENDL;
}
while(LLMessageTemplate * templatep = parseMessage(tokens))
{
if (templatep->getDeprecation() != MD_DEPRECATED)
{
mMessages.push_back(templatep);
}
else
{
delete templatep;
}
}
if(!tokens.wantEOF())
{
LL_ERRS() << "Expected end of template or a message, instead found: "
<< tokens.next() << " at " << tokens.line() << LL_ENDL;
}
}
F32 LLTemplateParser::getVersion() const
{
return mVersion;
}
LLTemplateParser::message_iterator LLTemplateParser::getMessagesBegin() const
{
return mMessages.begin();
}
LLTemplateParser::message_iterator LLTemplateParser::getMessagesEnd() const
{
return mMessages.end();
}
// static
LLMessageTemplate * LLTemplateParser::parseMessage(LLTemplateTokenizer & tokens)
{
LLMessageTemplate *templatep = NULL;
if(!tokens.want("{"))
{
return NULL;
}
// name first
std::string template_name = tokens.next();
// is name a legit C variable name
if (!b_variable_ok(template_name.c_str()))
{
LL_ERRS() << "Not legit variable name: " << template_name << " at " << tokens.line() << LL_ENDL;
}
// ok, now get Frequency ("High", "Medium", or "Low")
EMsgFrequency frequency = MFT_LOW;
std::string freq_string = tokens.next();
if (freq_string == "High")
{
frequency = MFT_HIGH;
}
else if (freq_string == "Medium")
{
frequency = MFT_MEDIUM;
}
else if (freq_string == "Low" || freq_string == "Fixed")
{
frequency = MFT_LOW;
}
else
{
LL_ERRS() << "Expected frequency, got " << freq_string << " at " << tokens.line() << LL_ENDL;
}
// TODO more explicit checking here pls
U32 message_number = strtoul(tokens.next().c_str(),NULL,0);
switch (frequency) {
case MFT_HIGH:
break;
case MFT_MEDIUM:
message_number = (255 << 8) | message_number;
break;
case MFT_LOW:
message_number = (255 << 24) | (255 << 16) | message_number;
break;
default:
LL_ERRS() << "Unknown frequency enum: " << frequency << LL_ENDL;
}
templatep = new LLMessageTemplate(
template_name.c_str(),
message_number,
frequency);
// Now get trust ("Trusted", "NotTrusted")
std::string trust = tokens.next();
if (trust == "Trusted")
{
templatep->setTrust(MT_TRUST);
}
else if (trust == "NotTrusted")
{
templatep->setTrust(MT_NOTRUST);
}
else
{
LL_ERRS() << "Bad trust " << trust << " at " << tokens.line() << LL_ENDL;
}
// get encoding
std::string encoding = tokens.next();
if(encoding == "Unencoded")
{
templatep->setEncoding(ME_UNENCODED);
}
else if(encoding == "Zerocoded")
{
templatep->setEncoding(ME_ZEROCODED);
}
else
{
LL_ERRS() << "Bad encoding " << encoding << " at " << tokens.line() << LL_ENDL;
}
// get deprecation
if(tokens.want("Deprecated"))
{
templatep->setDeprecation(MD_DEPRECATED);
}
else if (tokens.want("UDPDeprecated"))
{
templatep->setDeprecation(MD_UDPDEPRECATED);
}
else if (tokens.want("UDPBlackListed"))
{
templatep->setDeprecation(MD_UDPBLACKLISTED);
}
else if (tokens.want("NotDeprecated"))
{
// this is the default value, but it can't hurt to set it twice
templatep->setDeprecation(MD_NOTDEPRECATED);
}
else {
// It's probably a brace, let's just start block processing
}
while(LLMessageBlock * blockp = parseBlock(tokens))
{
templatep->addBlock(blockp);
}
if(!tokens.want("}"))
{
LL_ERRS() << "Expecting closing } for message " << template_name
<< " at " << tokens.line() << LL_ENDL;
}
return templatep;
}
// static
LLMessageBlock * LLTemplateParser::parseBlock(LLTemplateTokenizer & tokens)
{
LLMessageBlock * blockp = NULL;
if(!tokens.want("{"))
{
return NULL;
}
// name first
std::string block_name = tokens.next();
// is name a legit C variable name
if (!b_variable_ok(block_name.c_str()))
{
LL_ERRS() << "not a legal block name: " << block_name
<< " at " << tokens.line() << LL_ENDL;
}
// now, block type ("Single", "Multiple", or "Variable")
std::string block_type = tokens.next();
// which one is it?
if (block_type == "Single")
{
// ok, we can create a block
blockp = new LLMessageBlock(block_name.c_str(), MBT_SINGLE);
}
else if (block_type == "Multiple")
{
// need to get the number of repeats
std::string repeats = tokens.next();
// is it a legal integer
if (!b_positive_integer_ok(repeats.c_str()))
{
LL_ERRS() << "not a legal integer for block multiple count: "
<< repeats << " at " << tokens.line() << LL_ENDL;
}
// ok, we can create a block
blockp = new LLMessageBlock(block_name.c_str(),
MBT_MULTIPLE,
atoi(repeats.c_str()));
}
else if (block_type == "Variable")
{
// ok, we can create a block
blockp = new LLMessageBlock(block_name.c_str(), MBT_VARIABLE);
}
else
{
LL_ERRS() << "bad block type: " << block_type
<< " at " << tokens.line() << LL_ENDL;
}
while(LLMessageVariable * varp = parseVariable(tokens))
{
blockp->addVariable(varp->getName(),
varp->getType(),
varp->getSize());
delete varp;
}
if(!tokens.want("}"))
{
LL_ERRS() << "Expecting closing } for block " << block_name
<< " at " << tokens.line() << LL_ENDL;
}
return blockp;
}
// static
LLMessageVariable * LLTemplateParser::parseVariable(LLTemplateTokenizer & tokens)
{
LLMessageVariable * varp = NULL;
if(!tokens.want("{"))
{
return NULL;
}
std::string var_name = tokens.next();
if (!b_variable_ok(var_name.c_str()))
{
LL_ERRS() << "Not a legit variable name: " << var_name
<< " at " << tokens.line() << LL_ENDL;
}
std::string var_type = tokens.next();
if (var_type == "U8")
{
varp = new LLMessageVariable(var_name.c_str(), MVT_U8, 1);
}
else if (var_type == "U16")
{
varp = new LLMessageVariable(var_name.c_str(), MVT_U16, 2);
}
else if (var_type == "U32")
{
varp = new LLMessageVariable(var_name.c_str(), MVT_U32, 4);
}
else if (var_type == "U64")
{
varp = new LLMessageVariable(var_name.c_str(), MVT_U64, 8);
}
else if (var_type == "S8")
{
varp = new LLMessageVariable(var_name.c_str(), MVT_S8, 1);
}
else if (var_type == "S16")
{
varp = new LLMessageVariable(var_name.c_str(), MVT_S16, 2);
}
else if (var_type == "S32")
{
varp = new LLMessageVariable(var_name.c_str(), MVT_S32, 4);
}
else if (var_type == "S64")
{
varp = new LLMessageVariable(var_name.c_str(), MVT_S64, 8);
}
else if (var_type == "F32")
{
varp = new LLMessageVariable(var_name.c_str(), MVT_F32, 4);
}
else if (var_type == "F64")
{
varp = new LLMessageVariable(var_name.c_str(), MVT_F64, 8);
}
else if (var_type == "LLVector3")
{
varp = new LLMessageVariable(var_name.c_str(), MVT_LLVector3, 12);
}
else if (var_type == "LLVector3d")
{
varp = new LLMessageVariable(var_name.c_str(), MVT_LLVector3d, 24);
}
else if (var_type == "LLVector4")
{
varp = new LLMessageVariable(var_name.c_str(), MVT_LLVector4, 16);
}
else if (var_type == "LLQuaternion")
{
varp = new LLMessageVariable(var_name.c_str(), MVT_LLQuaternion, 12);
}
else if (var_type == "LLUUID")
{
varp = new LLMessageVariable(var_name.c_str(), MVT_LLUUID, 16);
}
else if (var_type == "BOOL")
{
varp = new LLMessageVariable(var_name.c_str(), MVT_BOOL, 1);
}
else if (var_type == "IPADDR")
{
varp = new LLMessageVariable(var_name.c_str(), MVT_IP_ADDR, 4);
}
else if (var_type == "IPPORT")
{
varp = new LLMessageVariable(var_name.c_str(), MVT_IP_PORT, 2);
}
else if (var_type == "Fixed" || var_type == "Variable")
{
std::string variable_size = tokens.next();
if (!b_positive_integer_ok(variable_size.c_str()))
{
LL_ERRS() << "not a legal integer variable size: " << variable_size
<< " at " << tokens.line() << LL_ENDL;
}
EMsgVariableType type_enum;
if(var_type == "Variable")
{
type_enum = MVT_VARIABLE;
}
else if(var_type == "Fixed")
{
type_enum = MVT_FIXED;
}
else
{
type_enum = MVT_FIXED; // removes a warning
LL_ERRS() << "bad variable type: " << var_type
<< " at " << tokens.line() << LL_ENDL;
}
varp = new LLMessageVariable(
var_name.c_str(),
type_enum,
atoi(variable_size.c_str()));
}
else
{
LL_ERRS() << "bad variable type:" << var_type
<< " at " << tokens.line() << LL_ENDL;
}
if(!tokens.want("}"))
{
LL_ERRS() << "Expecting closing } for variable " << var_name
<< " at " << tokens.line() << LL_ENDL;
}
return varp;
}
+80
View File
@@ -0,0 +1,80 @@
/**
* @file llmessagetemplateparser.h
* @brief Classes to parse message template.
*
* $LicenseInfo:firstyear=2000&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_MESSAGETEMPLATEPARSER_H
#define LL_MESSAGETEMPLATEPARSER_H
#include <string>
#include "llmessagetemplate.h"
class LLTemplateTokenizer
{
public:
LLTemplateTokenizer(const std::string & contents);
U32 line() const;
bool atEOF() const;
std::string next();
bool want(const std::string & token);
bool wantEOF();
private:
void inc();
void dec();
std::string get() const;
void error(std::string message = "generic") const;
struct positioned_token
{
std::string str;
U32 line;
};
bool mStarted;
std::list<positioned_token> mTokens;
std::list<positioned_token>::const_iterator mCurrent;
};
class LLTemplateParser
{
public:
typedef std::list<LLMessageTemplate *>::const_iterator message_iterator;
static LLMessageTemplate * parseMessage(LLTemplateTokenizer & tokens);
static LLMessageBlock * parseBlock(LLTemplateTokenizer & tokens);
static LLMessageVariable * parseVariable(LLTemplateTokenizer & tokens);
LLTemplateParser(LLTemplateTokenizer & tokens);
message_iterator getMessagesBegin() const;
message_iterator getMessagesEnd() const;
F32 getVersion() const;
private:
F32 mVersion;
std::list<LLMessageTemplate *> mMessages;
};
#endif
+153
View File
@@ -0,0 +1,153 @@
/**
* @file llmessagethrottle.cpp
* @brief LLMessageThrottle class used for throttling messages.
*
* $LicenseInfo:firstyear=2004&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 "llhash.h"
#include "llmessagethrottle.h"
#include "llframetimer.h"
// This is used for the stl search_n function.
bool eq_message_throttle_entry(LLMessageThrottleEntry a, LLMessageThrottleEntry b)
{ return a.getHash() == b.getHash(); }
const U64 SEC_TO_USEC = 1000000;
// How long (in microseconds) each type of message stays in its throttle list.
const U64 MAX_MESSAGE_AGE[MTC_EOF] =
{
10 * SEC_TO_USEC, // MTC_VIEWER_ALERT
10 * SEC_TO_USEC // MTC_AGENT_ALERT
};
LLMessageThrottle::LLMessageThrottle()
{
}
LLMessageThrottle::~LLMessageThrottle()
{
}
void LLMessageThrottle::pruneEntries()
{
// Go through each message category, and prune entries older than max age.
S32 cat;
for (cat = 0; cat < MTC_EOF; cat++)
{
message_list_t* message_list = &(mMessageList[cat]);
// Use a reverse iterator, since entries on the back will be the oldest.
message_list_reverse_iterator_t r_iterator = message_list->rbegin();
message_list_reverse_iterator_t r_last = message_list->rend();
// Look for the first entry younger than the maximum age.
F32 max_age = (F32)MAX_MESSAGE_AGE[cat];
bool found = false;
while (r_iterator != r_last && !found)
{
if ( LLFrameTimer::getTotalTime() - (*r_iterator).getEntryTime() < max_age )
{
// We found a young enough entry.
found = true;
// Did we find at least one entry to remove?
if (r_iterator != message_list->rbegin())
{
// Yes, remove it.
message_list->erase(r_iterator.base(), message_list->end());
}
}
else
{
r_iterator++;
}
}
// If we didn't find any entries young enough to keep, remove them all.
if (!found)
{
message_list->clear();
}
}
}
bool LLMessageThrottle::addViewerAlert(const LLUUID& to, const std::string& mesg)
{
message_list_t* message_list = &(mMessageList[MTC_VIEWER_ALERT]);
// Concatenate from,to,mesg into one string.
std::ostringstream full_mesg;
full_mesg << to << mesg;
// Create an entry for this message.
size_t hash = llhash(full_mesg.str().c_str());
LLMessageThrottleEntry entry(hash, LLFrameTimer::getTotalTime());
// Check if this message is already in the list.
message_list_iterator_t found = std::search_n(message_list->begin(), message_list->end(),
1, entry, eq_message_throttle_entry);
if (found == message_list->end())
{
// This message was not found. Add it to the list.
message_list->push_front(entry);
return true;
}
else
{
// This message was already in the list.
return false;
}
}
bool LLMessageThrottle::addAgentAlert(const LLUUID& agent, const LLUUID& task, const std::string& mesg)
{
message_list_t* message_list = &(mMessageList[MTC_AGENT_ALERT]);
// Concatenate from,to,mesg into one string.
std::ostringstream full_mesg;
full_mesg << agent << task << mesg;
// Create an entry for this message.
size_t hash = llhash(full_mesg.str().c_str());
LLMessageThrottleEntry entry(hash, LLFrameTimer::getTotalTime());
// Check if this message is already in the list.
message_list_iterator_t found = std::search_n(message_list->begin(), message_list->end(),
1, entry, eq_message_throttle_entry);
if (found == message_list->end())
{
// This message was not found. Add it to the list.
message_list->push_front(entry);
return true;
}
else
{
// This message was already in the list.
return false;
}
}
+80
View File
@@ -0,0 +1,80 @@
/**
* @file llmessagethrottle.h
* @brief LLMessageThrottle class used for throttling messages.
*
* $LicenseInfo:firstyear=2004&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_LLMESSAGETHROTTLE_H
#define LL_LLMESSAGETHROTTLE_H
#include <deque>
#include "linden_common.h"
#include "lluuid.h"
typedef enum e_message_throttle_categories
{
MTC_VIEWER_ALERT,
MTC_AGENT_ALERT,
MTC_EOF
} EMessageThrottleCats;
class LLMessageThrottleEntry
{
public:
LLMessageThrottleEntry(const size_t hash, const U64 entry_time)
: mHash(hash), mEntryTime(entry_time) {}
size_t getHash() const { return mHash; }
U64 getEntryTime() const { return mEntryTime; }
protected:
size_t mHash;
U64 mEntryTime;
};
class LLMessageThrottle
{
public:
LLMessageThrottle();
~LLMessageThrottle();
bool addViewerAlert (const LLUUID& to, const std::string& mesg);
bool addAgentAlert (const LLUUID& agent, const LLUUID& task, const std::string& mesg);
void pruneEntries();
protected:
typedef std::deque<LLMessageThrottleEntry> message_list_t;
typedef std::deque<LLMessageThrottleEntry>::iterator message_list_iterator_t;
typedef std::deque<LLMessageThrottleEntry>::reverse_iterator message_list_reverse_iterator_t;
typedef std::deque<LLMessageThrottleEntry>::const_iterator message_list_const_iterator_t;
typedef std::deque<LLMessageThrottleEntry>::const_reverse_iterator message_list_const_reverse_iterator_t;
message_list_t mMessageList[MTC_EOF];
};
extern LLMessageThrottle gMessageThrottle;
#endif
+59
View File
@@ -0,0 +1,59 @@
/**
* @file llmsgvariabletype.h
* @brief Declaration of the EMsgVariableType enumeration.
*
* $LicenseInfo:firstyear=2007&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_LLMSGVARIABLETYPE_H
#define LL_LLMSGVARIABLETYPE_H
typedef enum e_message_variable_type
{
MVT_NULL,
MVT_FIXED,
MVT_VARIABLE,
MVT_U8,
MVT_U16,
MVT_U32,
MVT_U64,
MVT_S8,
MVT_S16,
MVT_S32,
MVT_S64,
MVT_F32,
MVT_F64,
MVT_LLVector3,
MVT_LLVector3d,
MVT_LLVector4,
MVT_LLQuaternion,
MVT_LLUUID,
MVT_BOOL,
MVT_IP_ADDR,
MVT_IP_PORT,
MVT_U16Vec3,
MVT_U16Quat,
MVT_S16Array,
MVT_EOL
} EMsgVariableType;
#endif // LL_LLMSGVARIABLETYPE_H
+976
View File
@@ -0,0 +1,976 @@
/**
* @file llnamevalue.cpp
* @brief class for defining name value pairs.
*
* $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$
*/
// Examples:
// AvatarCharacter STRING RW DSV male1
#include "linden_common.h"
#include "llnamevalue.h"
#include "u64.h"
#include "llstring.h"
#include "llstringtable.h"
// <FS:ND> Suppress warnings about the string fiddling
#if LL_LINUX
#pragma GCC diagnostic ignored "-Wstringop-truncation"
#endif
// </FS:ND>
// Anonymous enumeration to provide constants in this file.
// *NOTE: These values may be used in sscanf statements below as their
// value-1, so search for '2047' if you cange NV_BUFFER_LEN or '63' if
// you change U64_BUFFER_LEN.
enum
{
NV_BUFFER_LEN = 2048,
U64_BUFFER_LEN = 64
};
LLStringTable gNVNameTable(256);
char NameValueTypeStrings[NVT_EOF][NAME_VALUE_TYPE_STRING_LENGTH] = /*Flawfinder: Ignore*/
{
"NULL",
"STRING",
"F32",
"S32",
"VEC3",
"U32",
"CAMERA", // Deprecated, but leaving in case removing completely would cause problems
"ASSET",
"U64"
};
char NameValueClassStrings[NVC_EOF][NAME_VALUE_CLASS_STRING_LENGTH] = /*Flawfinder: Ignore*/
{
"NULL",
"R", // read only
"RW" // read write
};
char NameValueSendtoStrings[NVS_EOF][NAME_VALUE_SENDTO_STRING_LENGTH] = /*Flawfinder: Ignore*/
{
"NULL",
"S", // "Sim", formerly SIM
"DS", // "Data Sim" formerly SIM_SPACE
"SV", // "Sim Viewer" formerly SIM_VIEWER
"DSV" // "Data Sim Viewer", formerly SIM_SPACE_VIEWER
}; /*Flawfinder: Ignore*/
//
// Class
//
LLNameValue::LLNameValue()
{
baseInit();
}
void LLNameValue::baseInit()
{
mNVNameTable = &gNVNameTable;
mName = NULL;
mNameValueReference.string = NULL;
mType = NVT_NULL;
mStringType = NameValueTypeStrings[NVT_NULL];
mClass = NVC_NULL;
mStringClass = NameValueClassStrings[NVC_NULL];
mSendto = NVS_NULL;
mStringSendto = NameValueSendtoStrings[NVS_NULL];
}
void LLNameValue::init(const char *name, const char *data, const char *type, const char *nvclass, const char *nvsendto)
{
mNVNameTable = &gNVNameTable;
mName = mNVNameTable->addString(name);
// Nota Bene: Whatever global structure manages this should have these in the name table already!
mStringType = mNVNameTable->addString(type);
if (!strcmp(mStringType, "STRING"))
{
S32 string_length = (S32)strlen(data); /*Flawfinder: Ignore*/
mType = NVT_STRING;
delete[] mNameValueReference.string;
// two options here. . . data can either look like foo or "foo"
// WRONG! - this is a poorly implemented and incomplete escape
// mechanism. For example, using this scheme, there is no way
// to tell an intentional double quotes from a zero length
// string. This needs to excised. Phoenix
//if (strchr(data, '\"'))
//{
// string_length -= 2;
// mNameValueReference.string = new char[string_length + 1];;
// strncpy(mNameValueReference.string, data + 1, string_length);
//}
//else
//{
mNameValueReference.string = new char[string_length + 1];;
strncpy(mNameValueReference.string, data, string_length); /*Flawfinder: Ignore*/
//}
mNameValueReference.string[string_length] = 0;
}
else if (!strcmp(mStringType, "F32"))
{
mType = NVT_F32;
mNameValueReference.f32 = new F32((F32)atof(data));
}
else if (!strcmp(mStringType, "S32"))
{
mType = NVT_S32;
mNameValueReference.s32 = new S32(atoi(data));
}
else if (!strcmp(mStringType, "U64"))
{
mType = NVT_U64;
mNameValueReference.u64 = new U64(str_to_U64(ll_safe_string(data)));
}
else if (!strcmp(mStringType, "VEC3"))
{
mType = NVT_VEC3;
F32 t1, t2, t3;
// two options here. . . data can either look like 0, 1, 2 or <0, 1, 2>
if (strchr(data, '<'))
{
sscanf(data, "<%f, %f, %f>", &t1, &t2, &t3);
}
else
{
sscanf(data, "%f, %f, %f", &t1, &t2, &t3);
}
// finite checks
if (!llfinite(t1) || !llfinite(t2) || !llfinite(t3))
{
t1 = 0.f;
t2 = 0.f;
t3 = 0.f;
}
mNameValueReference.vec3 = new LLVector3(t1, t2, t3);
}
else if (!strcmp(mStringType, "U32"))
{
mType = NVT_U32;
mNameValueReference.u32 = new U32(atoi(data));
}
else if(!strcmp(mStringType, (const char*)NameValueTypeStrings[NVT_ASSET]))
{
// assets are treated like strings, except that the name has
// meaning to an LLAssetInfo object
S32 string_length = (S32)strlen(data); /*Flawfinder: Ignore*/
mType = NVT_ASSET;
// two options here. . . data can either look like foo or "foo"
// WRONG! - this is a poorly implemented and incomplete escape
// mechanism. For example, using this scheme, there is no way
// to tell an intentional double quotes from a zero length
// string. This needs to excised. Phoenix
//if (strchr(data, '\"'))
//{
// string_length -= 2;
// mNameValueReference.string = new char[string_length + 1];;
// strncpy(mNameValueReference.string, data + 1, string_length);
//}
//else
//{
mNameValueReference.string = new char[string_length + 1];;
strncpy(mNameValueReference.string, data, string_length); /*Flawfinder: Ignore*/
//}
mNameValueReference.string[string_length] = 0;
}
else
{
LL_WARNS() << "Unknown name value type string " << mStringType << " for " << mName << LL_ENDL;
mType = NVT_NULL;
}
// Nota Bene: Whatever global structure manages this should have these in the name table already!
if (!strcmp(nvclass, "R") ||
!strcmp(nvclass, "READ_ONLY")) // legacy
{
mClass = NVC_READ_ONLY;
mStringClass = mNVNameTable->addString("R");
}
else if (!strcmp(nvclass, "RW") ||
!strcmp(nvclass, "READ_WRITE")) // legacy
{
mClass = NVC_READ_WRITE;
mStringClass = mNVNameTable->addString("RW");
}
else
{
// assume it's bad
mClass = NVC_NULL;
mStringClass = mNVNameTable->addString(nvclass);
}
// Initialize the sendto variable
if (!strcmp(nvsendto, "S") ||
!strcmp(nvsendto, "SIM")) // legacy
{
mSendto = NVS_SIM;
mStringSendto = mNVNameTable->addString("S");
}
else if (!strcmp(nvsendto, "DS") ||
!strcmp(nvsendto, "SIM_SPACE")) // legacy
{
mSendto = NVS_DATA_SIM;
mStringSendto = mNVNameTable->addString("DS");
}
else if (!strcmp(nvsendto, "SV") ||
!strcmp(nvsendto, "SIM_VIEWER")) // legacy
{
mSendto = NVS_SIM_VIEWER;
mStringSendto = mNVNameTable->addString("SV");
}
else if (!strcmp(nvsendto, "DSV") ||
!strcmp(nvsendto, "SIM_SPACE_VIEWER")) // legacy
{
mSendto = NVS_DATA_SIM_VIEWER;
mStringSendto = mNVNameTable->addString("DSV");
}
else
{
LL_WARNS() << "LLNameValue::init() - unknown sendto field "
<< nvsendto << " for NV " << mName << LL_ENDL;
mSendto = NVS_NULL;
mStringSendto = mNVNameTable->addString("S");
}
}
LLNameValue::LLNameValue(const char *name, const char *data, const char *type, const char *nvclass)
{
baseInit();
// if not specified, send to simulator only
init(name, data, type, nvclass, "SIM");
}
LLNameValue::LLNameValue(const char *name, const char *data, const char *type, const char *nvclass, const char *nvsendto)
{
baseInit();
init(name, data, type, nvclass, nvsendto);
}
// Initialize without any initial data.
LLNameValue::LLNameValue(const char *name, const char *type, const char *nvclass)
{
baseInit();
mName = mNVNameTable->addString(name);
// Nota Bene: Whatever global structure manages this should have these in the name table already!
mStringType = mNVNameTable->addString(type);
if (!strcmp(mStringType, "STRING"))
{
mType = NVT_STRING;
mNameValueReference.string = NULL;
}
else if (!strcmp(mStringType, "F32"))
{
mType = NVT_F32;
mNameValueReference.f32 = NULL;
}
else if (!strcmp(mStringType, "S32"))
{
mType = NVT_S32;
mNameValueReference.s32 = NULL;
}
else if (!strcmp(mStringType, "VEC3"))
{
mType = NVT_VEC3;
mNameValueReference.vec3 = NULL;
}
else if (!strcmp(mStringType, "U32"))
{
mType = NVT_U32;
mNameValueReference.u32 = NULL;
}
else if (!strcmp(mStringType, "U64"))
{
mType = NVT_U64;
mNameValueReference.u64 = NULL;
}
else if(!strcmp(mStringType, (const char*)NameValueTypeStrings[NVT_ASSET]))
{
mType = NVT_ASSET;
mNameValueReference.string = NULL;
}
else
{
mType = NVT_NULL;
LL_INFOS() << "Unknown name-value type " << mStringType << LL_ENDL;
}
// Nota Bene: Whatever global structure manages this should have these in the name table already!
mStringClass = mNVNameTable->addString(nvclass);
if (!strcmp(mStringClass, "READ_ONLY"))
{
mClass = NVC_READ_ONLY;
}
else if (!strcmp(mStringClass, "READ_WRITE"))
{
mClass = NVC_READ_WRITE;
}
else
{
mClass = NVC_NULL;
}
// Initialize the sendto variable
mStringSendto = mNVNameTable->addString("SIM");
mSendto = NVS_SIM;
}
// data is in the format:
// "NameValueName Type Class Data"
LLNameValue::LLNameValue(const char *data)
{
baseInit();
static char name[NV_BUFFER_LEN]; /*Flawfinder: ignore*/
static char type[NV_BUFFER_LEN]; /*Flawfinder: ignore*/
static char nvclass[NV_BUFFER_LEN]; /*Flawfinder: ignore*/
static char nvsendto[NV_BUFFER_LEN]; /*Flawfinder: ignore*/
static char nvdata[NV_BUFFER_LEN]; /*Flawfinder: ignore*/
S32 i;
S32 character_count = 0;
S32 length = 0;
// go to first non-whitespace character
while (1)
{
if ( (*(data + character_count) == ' ')
||(*(data + character_count) == '\n')
||(*(data + character_count) == '\t')
||(*(data + character_count) == '\r'))
{
character_count++;
}
else
{
break;
}
}
// read in the name
sscanf((data + character_count), "%2047s", name); /*Flawfinder: ignore*/
// bump past it and add null terminator
length = (S32)strlen(name); /* Flawfinder: ignore */
name[length] = 0;
character_count += length;
// go to the next non-whitespace character
while (1)
{
if ( (*(data + character_count) == ' ')
||(*(data + character_count) == '\n')
||(*(data + character_count) == '\t')
||(*(data + character_count) == '\r'))
{
character_count++;
}
else
{
break;
}
}
// read in the type
sscanf((data + character_count), "%2047s", type); /*Flawfinder: ignore*/
// bump past it and add null terminator
length = (S32)strlen(type); /* Flawfinder: ignore */
type[length] = 0;
character_count += length;
// go to the next non-whitespace character
while (1)
{
if ( (*(data + character_count) == ' ')
||(*(data + character_count) == '\n')
||(*(data + character_count) == '\t')
||(*(data + character_count) == '\r'))
{
character_count++;
}
else
{
break;
}
}
// do we have a type argument?
for (i = NVC_READ_ONLY; i < NVC_EOF; i++)
{
if (!strncmp(NameValueClassStrings[i], data + character_count, strlen(NameValueClassStrings[i]))) /* Flawfinder: ignore */
{
break;
}
}
if (i != NVC_EOF)
{
// yes we do!
// read in the class
sscanf((data + character_count), "%2047s", nvclass); /*Flawfinder: ignore*/
// bump past it and add null terminator
length = (S32)strlen(nvclass); /* Flawfinder: ignore */
nvclass[length] = 0;
character_count += length;
// go to the next non-whitespace character
while (1)
{
if ( (*(data + character_count) == ' ')
||(*(data + character_count) == '\n')
||(*(data + character_count) == '\t')
||(*(data + character_count) == '\r'))
{
character_count++;
}
else
{
break;
}
}
}
else
{
// no type argument given, default to read-write
strncpy(nvclass, "READ_WRITE", sizeof(nvclass) -1); /* Flawfinder: ignore */
nvclass[sizeof(nvclass) -1] = '\0';
}
// Do we have a sendto argument?
for (i = NVS_SIM; i < NVS_EOF; i++)
{
if (!strncmp(NameValueSendtoStrings[i], data + character_count, strlen(NameValueSendtoStrings[i]))) /* Flawfinder: ignore */
{
break;
}
}
if (i != NVS_EOF)
{
// found a sendto argument
sscanf((data + character_count), "%2047s", nvsendto); /*Flawfinder: ignore*/
// add null terminator
length = (S32)strlen(nvsendto); /* Flawfinder: ignore */
nvsendto[length] = 0;
character_count += length;
// seek to next non-whitespace characer
while (1)
{
if ( (*(data + character_count) == ' ')
||(*(data + character_count) == '\n')
||(*(data + character_count) == '\t')
||(*(data + character_count) == '\r'))
{
character_count++;
}
else
{
break;
}
}
}
else
{
// no sendto argument given, default to sim only
strncpy(nvsendto, "SIM", sizeof(nvsendto) -1); /* Flawfinder: ignore */
nvsendto[sizeof(nvsendto) -1] ='\0';
}
// copy the rest character by character into data
length = 0;
while ( (*(nvdata + length++) = *(data + character_count++)) )
;
init(name, nvdata, type, nvclass, nvsendto);
}
LLNameValue::~LLNameValue()
{
mNVNameTable->removeString(mName);
mName = NULL;
switch(mType)
{
case NVT_STRING:
case NVT_ASSET:
delete [] mNameValueReference.string;
mNameValueReference.string = NULL;
break;
case NVT_F32:
delete mNameValueReference.f32;
mNameValueReference.string = NULL;
break;
case NVT_S32:
delete mNameValueReference.s32;
mNameValueReference.string = NULL;
break;
case NVT_VEC3:
delete mNameValueReference.vec3;
mNameValueReference.string = NULL;
break;
case NVT_U32:
delete mNameValueReference.u32;
mNameValueReference.u32 = NULL;
break;
case NVT_U64:
delete mNameValueReference.u64;
mNameValueReference.u64 = NULL;
break;
default:
break;
}
delete[] mNameValueReference.string;
mNameValueReference.string = NULL;
}
char *LLNameValue::getString()
{
if (mType == NVT_STRING)
{
return mNameValueReference.string;
}
else
{
LL_ERRS() << mName << " not a string!" << LL_ENDL;
return NULL;
}
}
const char *LLNameValue::getAsset() const
{
if (mType == NVT_ASSET)
{
return mNameValueReference.string;
}
else
{
LL_ERRS() << mName << " not an asset!" << LL_ENDL;
return NULL;
}
}
F32 *LLNameValue::getF32()
{
if (mType == NVT_F32)
{
return mNameValueReference.f32;
}
else
{
LL_ERRS() << mName << " not a F32!" << LL_ENDL;
return NULL;
}
}
S32 *LLNameValue::getS32()
{
if (mType == NVT_S32)
{
return mNameValueReference.s32;
}
else
{
LL_ERRS() << mName << " not a S32!" << LL_ENDL;
return NULL;
}
}
U32 *LLNameValue::getU32()
{
if (mType == NVT_U32)
{
return mNameValueReference.u32;
}
else
{
LL_ERRS() << mName << " not a U32!" << LL_ENDL;
return NULL;
}
}
U64 *LLNameValue::getU64()
{
if (mType == NVT_U64)
{
return mNameValueReference.u64;
}
else
{
LL_ERRS() << mName << " not a U64!" << LL_ENDL;
return NULL;
}
}
void LLNameValue::getVec3(LLVector3 &vec)
{
if (mType == NVT_VEC3)
{
vec = *mNameValueReference.vec3;
}
else
{
LL_ERRS() << mName << " not a Vec3!" << LL_ENDL;
}
}
LLVector3 *LLNameValue::getVec3()
{
if (mType == NVT_VEC3)
{
return (mNameValueReference.vec3);
}
else
{
LL_ERRS() << mName << " not a Vec3!" << LL_ENDL;
return NULL;
}
}
bool LLNameValue::sendToData() const
{
return (mSendto == NVS_DATA_SIM || mSendto == NVS_DATA_SIM_VIEWER);
}
bool LLNameValue::sendToViewer() const
{
return (mSendto == NVS_SIM_VIEWER || mSendto == NVS_DATA_SIM_VIEWER);
}
LLNameValue &LLNameValue::operator=(const LLNameValue &a)
{
if (mType != a.mType)
{
return *this;
}
if (mClass == NVC_READ_ONLY)
return *this;
switch(a.mType)
{
case NVT_STRING:
case NVT_ASSET:
if (mNameValueReference.string)
delete [] mNameValueReference.string;
mNameValueReference.string = new char [strlen(a.mNameValueReference.string) + 1]; /* Flawfinder: ignore */
if(mNameValueReference.string != NULL)
{
strcpy(mNameValueReference.string, a.mNameValueReference.string); /* Flawfinder: ignore */
}
break;
case NVT_F32:
*mNameValueReference.f32 = *a.mNameValueReference.f32;
break;
case NVT_S32:
*mNameValueReference.s32 = *a.mNameValueReference.s32;
break;
case NVT_VEC3:
*mNameValueReference.vec3 = *a.mNameValueReference.vec3;
break;
case NVT_U32:
*mNameValueReference.u32 = *a.mNameValueReference.u32;
break;
case NVT_U64:
*mNameValueReference.u64 = *a.mNameValueReference.u64;
break;
default:
LL_ERRS() << "Unknown Name value type " << (U32)a.mType << LL_ENDL;
break;
}
return *this;
}
void LLNameValue::setString(const char *a)
{
if (mClass == NVC_READ_ONLY)
return;
switch(mType)
{
case NVT_STRING:
if (a)
{
if (mNameValueReference.string)
{
delete [] mNameValueReference.string;
}
mNameValueReference.string = new char [strlen(a) + 1]; /* Flawfinder: ignore */
if(mNameValueReference.string != NULL)
{
strcpy(mNameValueReference.string, a); /* Flawfinder: ignore */
}
}
else
{
if (mNameValueReference.string)
delete [] mNameValueReference.string;
mNameValueReference.string = new char [1];
mNameValueReference.string[0] = 0;
}
break;
default:
break;
}
return;
}
void LLNameValue::setAsset(const char *a)
{
if (mClass == NVC_READ_ONLY)
return;
switch(mType)
{
case NVT_ASSET:
if (a)
{
if (mNameValueReference.string)
{
delete [] mNameValueReference.string;
}
mNameValueReference.string = new char [strlen(a) + 1]; /* Flawfinder: ignore */
if(mNameValueReference.string != NULL)
{
strcpy(mNameValueReference.string, a); /* Flawfinder: ignore */
}
}
else
{
if (mNameValueReference.string)
delete [] mNameValueReference.string;
mNameValueReference.string = new char [1];
mNameValueReference.string[0] = 0;
}
break;
default:
break;
}
}
void LLNameValue::setF32(const F32 a)
{
if (mClass == NVC_READ_ONLY)
return;
switch(mType)
{
case NVT_F32:
*mNameValueReference.f32 = a;
break;
default:
break;
}
return;
}
void LLNameValue::setS32(const S32 a)
{
if (mClass == NVC_READ_ONLY)
return;
switch(mType)
{
case NVT_S32:
*mNameValueReference.s32 = a;
break;
case NVT_U32:
*mNameValueReference.u32 = a;
break;
case NVT_F32:
*mNameValueReference.f32 = (F32)a;
break;
default:
break;
}
return;
}
void LLNameValue::setU32(const U32 a)
{
if (mClass == NVC_READ_ONLY)
return;
switch(mType)
{
case NVT_S32:
*mNameValueReference.s32 = a;
break;
case NVT_U32:
*mNameValueReference.u32 = a;
break;
case NVT_F32:
*mNameValueReference.f32 = (F32)a;
break;
default:
LL_ERRS() << "NameValue: Trying to set U32 into a " << mStringType << ", unknown conversion" << LL_ENDL;
break;
}
return;
}
void LLNameValue::setVec3(const LLVector3 &a)
{
if (mClass == NVC_READ_ONLY)
return;
switch(mType)
{
case NVT_VEC3:
*mNameValueReference.vec3 = a;
break;
default:
LL_ERRS() << "NameValue: Trying to set LLVector3 into a " << mStringType << ", unknown conversion" << LL_ENDL;
break;
}
return;
}
std::string LLNameValue::printNameValue() const
{
std::string buffer;
buffer = llformat("%s %s %s %s ", mName, mStringType, mStringClass, mStringSendto);
buffer += printData();
// LL_INFOS() << "Name Value Length: " << buffer.size() + 1 << LL_ENDL;
return buffer;
}
std::string LLNameValue::printData() const
{
std::string buffer;
switch(mType)
{
case NVT_STRING:
case NVT_ASSET:
buffer = mNameValueReference.string;
break;
case NVT_F32:
buffer = llformat("%f", *mNameValueReference.f32);
break;
case NVT_S32:
buffer = llformat("%d", *mNameValueReference.s32);
break;
case NVT_U32:
buffer = llformat("%u", *mNameValueReference.u32);
break;
case NVT_U64:
{
char u64_string[U64_BUFFER_LEN]; /* Flawfinder: ignore */
U64_to_str(*mNameValueReference.u64, u64_string, sizeof(u64_string));
buffer = u64_string;
}
break;
case NVT_VEC3:
buffer = llformat( "%f, %f, %f", mNameValueReference.vec3->mV[VX], mNameValueReference.vec3->mV[VY], mNameValueReference.vec3->mV[VZ]);
break;
default:
LL_ERRS() << "Trying to print unknown NameValue type " << mStringType << LL_ENDL;
break;
}
return buffer;
}
std::ostream& operator<<(std::ostream& s, const LLNameValue &a)
{
switch(a.mType)
{
case NVT_STRING:
case NVT_ASSET:
s << a.mNameValueReference.string;
break;
case NVT_F32:
s << (*a.mNameValueReference.f32);
break;
case NVT_S32:
s << *(a.mNameValueReference.s32);
break;
case NVT_U32:
s << *(a.mNameValueReference.u32);
break;
case NVT_U64:
{
char u64_string[U64_BUFFER_LEN]; /* Flawfinder: ignore */
U64_to_str(*a.mNameValueReference.u64, u64_string, sizeof(u64_string));
s << u64_string;
}
break;
case NVT_VEC3:
s << *(a.mNameValueReference.vec3);
break;
default:
LL_ERRS() << "Trying to print unknown NameValue type " << a.mStringType << LL_ENDL;
break;
}
return s;
}
+183
View File
@@ -0,0 +1,183 @@
/**
* @file llnamevalue.h
* @brief class for defining name value pairs.
*
* $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$
*/
#ifndef LL_LLNAMEVALUE_H
#define LL_LLNAMEVALUE_H
// As of January 2008, I believe we only use the following name-value
// pairs. This is hard to prove because they are initialized from
// strings. JC
//
// FirstName STRING
// LastName STRING
// AttachPt U32
// AttachmentItemId STRING
// Title STRING
// AttachmentOffset VEC3
// AttachmentOrientation VEC3
// SitObject STRING
// SitPosition VEC3
#include "llstringtable.h"
#include "llmath.h"
#include "v3math.h"
#include "lldbstrings.h"
class LLNameValue;
class LLStringTable;
typedef enum e_name_value_types
{
NVT_NULL,
NVT_STRING,
NVT_F32,
NVT_S32,
NVT_VEC3,
NVT_U32,
NVT_CAMERA, // Deprecated, but leaving in case removing this will cause problems
NVT_ASSET,
NVT_U64,
NVT_EOF
} ENameValueType;
typedef enum e_name_value_class
{
NVC_NULL,
NVC_READ_ONLY,
NVC_READ_WRITE,
NVC_EOF
} ENameValueClass;
typedef enum e_name_value_sento
{
NVS_NULL,
NVS_SIM,
NVS_DATA_SIM,
NVS_SIM_VIEWER,
NVS_DATA_SIM_VIEWER,
NVS_EOF
} ENameValueSendto;
// NameValues can always be "printed" into a buffer of this length.
const U32 NAME_VALUE_BUF_SIZE = 1024;
const U32 NAME_VALUE_TYPE_STRING_LENGTH = 8;
const U32 NAME_VALUE_CLASS_STRING_LENGTH = 16;
const U32 NAME_VALUE_SENDTO_STRING_LENGTH = 18;
const U32 NAME_VALUE_DATA_SIZE =
NAME_VALUE_BUF_SIZE -
( DB_NV_NAME_BUF_SIZE +
NAME_VALUE_TYPE_STRING_LENGTH +
NAME_VALUE_CLASS_STRING_LENGTH +
NAME_VALUE_SENDTO_STRING_LENGTH );
extern char NameValueTypeStrings[NVT_EOF][NAME_VALUE_TYPE_STRING_LENGTH]; /* Flawfinder: Ignore */
extern char NameValueClassStrings[NVC_EOF][NAME_VALUE_CLASS_STRING_LENGTH]; /* Flawfinder: Ignore */
extern char NameValueSendtoStrings[NVS_EOF][NAME_VALUE_SENDTO_STRING_LENGTH]; /* Flawfinder: Ignore */
typedef union u_name_value_reference
{
char *string;
F32 *f32;
S32 *s32;
LLVector3 *vec3;
U32 *u32;
U64 *u64;
} UNameValueReference;
class LLNameValue
{
public:
void baseInit();
void init(const char *name, const char *data, const char *type, const char *nvclass, const char *nvsendto );
LLNameValue();
LLNameValue(const char *data);
LLNameValue(const char *name, const char *type, const char *nvclass );
LLNameValue(const char *name, const char *data, const char *type, const char *nvclass );
LLNameValue(const char *name, const char *data, const char *type, const char *nvclass, const char *nvsendto );
~LLNameValue();
char *getString();
const char *getAsset() const;
F32 *getF32();
S32 *getS32();
void getVec3(LLVector3 &vec);
LLVector3 *getVec3();
U32 *getU32();
U64 *getU64();
const char *getType() const { return mStringType; }
const char *getClass() const { return mStringClass; }
const char *getSendto() const { return mStringSendto; }
bool sendToData() const;
bool sendToViewer() const;
void callCallback();
std::string printNameValue() const;
std::string printData() const;
ENameValueType getTypeEnum() const { return mType; }
ENameValueClass getClassEnum() const { return mClass; }
ENameValueSendto getSendtoEnum() const { return mSendto; }
LLNameValue &operator=(const LLNameValue &a);
void setString(const char *a);
void setAsset(const char *a);
void setF32(const F32 a);
void setS32(const S32 a);
void setVec3(const LLVector3 &a);
void setU32(const U32 a);
friend std::ostream& operator<<(std::ostream& s, const LLNameValue &a);
private:
void printNameValue(std::ostream& s);
public:
char *mName;
char *mStringType;
ENameValueType mType;
char *mStringClass;
ENameValueClass mClass;
char *mStringSendto;
ENameValueSendto mSendto;
UNameValueReference mNameValueReference;
LLStringTable *mNVNameTable;
};
extern LLStringTable gNVNameTable;
#endif
+58
View File
@@ -0,0 +1,58 @@
/**
* @file llnullcipher.cpp
* @brief Implementation of a cipher which does not encrypt.
*
* $LicenseInfo:firstyear=2003&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 "llnullcipher.h"
///----------------------------------------------------------------------------
/// Class LLNullCipher
///----------------------------------------------------------------------------
U32 LLNullCipher::encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len)
{
if((src_len == dst_len) && src && dst)
{
memmove(dst, src, src_len);
return src_len;
}
return 0;
}
U32 LLNullCipher::decrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len)
{
if((src_len == dst_len) && src && dst)
{
memmove(dst, src, src_len);
return src_len;
}
return 0;
}
U32 LLNullCipher::requiredEncryptionSpace(U32 len) const
{
return len;
}
+48
View File
@@ -0,0 +1,48 @@
/**
* @file llnullcipher.h
*
* $LicenseInfo:firstyear=2003&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 LLNULLCIPHER_H
#define LLNULLCIPHER_H
#include "llcipher.h"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLNullCipher
//
// A class which implements LLCipher, but does not transform src
// during encryption.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLNullCipher : public LLCipher
{
public:
LLNullCipher() {}
virtual ~LLNullCipher() {}
virtual U32 encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len);
virtual U32 decrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len);
virtual U32 requiredEncryptionSpace(U32 src_len) const;
};
#endif
+82
View File
@@ -0,0 +1,82 @@
/**
* @file llpacketack.cpp
* @author Phoenix
* @date 2007-05-09
* @brief Implementation of the LLReliablePacket.
*
* $LicenseInfo:firstyear=2007&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 "llpacketack.h"
#if !LL_WINDOWS
#include <netinet/in.h>
#else
#include "winsock2.h"
#endif
#include "message.h"
LLReliablePacket::LLReliablePacket(
S32 socket,
U8* buf_ptr,
S32 buf_len,
LLReliablePacketParams* params) :
mBuffer(NULL),
mBufferLength(0)
{
if (params)
{
mHost = params->mHost;
mRetries = params->mRetries;
mPingBasedRetry = params->mPingBasedRetry;
mTimeout = F32Seconds(params->mTimeout);
mCallback = params->mCallback;
mCallbackData = params->mCallbackData;
mMessageName = params->mMessageName;
}
else
{
mRetries = 0;
mPingBasedRetry = true;
mTimeout = F32Seconds(0.f);
mCallback = NULL;
mCallbackData = NULL;
mMessageName = NULL;
}
mExpirationTime = (F64Seconds)totalTime() + mTimeout;
mPacketID = ntohl(*((U32*)(&buf_ptr[PHL_PACKET_ID])));
mSocket = socket;
if (mRetries)
{
mBuffer = new U8[buf_len];
if (mBuffer != NULL)
{
memcpy(mBuffer,buf_ptr,buf_len); /*Flawfinder: ignore*/
mBufferLength = buf_len;
}
}
}
+116
View File
@@ -0,0 +1,116 @@
/**
* @file llpacketack.h
* @brief Reliable UDP helpers for the message system.
*
* $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$
*/
#ifndef LL_LLPACKETACK_H
#define LL_LLPACKETACK_H
#include "llhost.h"
#include "llunits.h"
class LLReliablePacketParams
{
public:
LLHost mHost;
S32 mRetries;
bool mPingBasedRetry;
F32Seconds mTimeout;
void (*mCallback)(void **,S32);
void** mCallbackData;
char* mMessageName;
public:
LLReliablePacketParams()
{
clear();
};
~LLReliablePacketParams() { };
void clear()
{
mHost.invalidate();
mRetries = 0;
mPingBasedRetry = true;
mTimeout = F32Seconds(0.f);
mCallback = NULL;
mCallbackData = NULL;
mMessageName = NULL;
};
void set(
const LLHost& host,
S32 retries,
bool ping_based_retry,
F32Seconds timeout,
void (*callback)(void**,S32),
void** callback_data, char* name)
{
mHost = host;
mRetries = retries;
mPingBasedRetry = ping_based_retry;
mTimeout = timeout;
mCallback = callback;
mCallbackData = callback_data;
mMessageName = name;
};
};
class LLReliablePacket
{
public:
LLReliablePacket(
S32 socket,
U8* buf_ptr,
S32 buf_len,
LLReliablePacketParams* params);
~LLReliablePacket()
{
mCallback = NULL;
delete [] mBuffer;
mBuffer = NULL;
};
friend class LLCircuitData;
protected:
S32 mSocket;
LLHost mHost;
S32 mRetries;
bool mPingBasedRetry;
F32Seconds mTimeout;
void (*mCallback)(void**,S32);
void** mCallbackData;
char* mMessageName;
U8* mBuffer;
S32 mBufferLength;
TPACKETID mPacketID;
F64Seconds mExpirationTime;
};
#endif
+84
View File
@@ -0,0 +1,84 @@
/**
* @file llpacketbuffer.cpp
* @brief implementation of LLPacketBuffer class for a packet.
*
* $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 "llpacketbuffer.h"
#include "net.h"
#include "lltimer.h"
#include "llhost.h"
LLPacketBuffer::LLPacketBuffer(const LLHost &host, const char *datap, const S32 size) : mHost(host)
{
mSize = 0;
mData[0] = '!';
if (size > NET_BUFFER_SIZE)
{
LL_ERRS() << "Constructing packet with size=" << size << " > " << NET_BUFFER_SIZE << LL_ENDL;
}
else
{
if (datap != NULL)
{
memcpy(mData, datap, size);
mSize = size;
}
}
}
LLPacketBuffer::LLPacketBuffer (S32 hSocket)
{
init(hSocket);
}
LLPacketBuffer::~LLPacketBuffer ()
{
}
void LLPacketBuffer::init(S32 hSocket)
{
mSize = receive_packet(hSocket, mData);
mHost = ::get_sender();
mReceivingIF = ::get_receiving_interface();
}
void LLPacketBuffer::init(const char* buffer, S32 data_size, const LLHost& host)
{
if (data_size > NET_BUFFER_SIZE)
{
LL_ERRS() << "Initializing packet with size=" << data_size << " > " << NET_BUFFER_SIZE << LL_ENDL;
}
else
{
memcpy(mData, buffer, data_size);
mSize = data_size;
mHost = host;
mReceivingIF = ::get_receiving_interface();
}
}
+58
View File
@@ -0,0 +1,58 @@
/**
* @file llpacketbuffer.h
* @brief definition of LLPacketBuffer class for implementing a
* resend, drop, or delay in packet transmissions.
*
* $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$
*/
#ifndef LL_LLPACKETBUFFER_H
#define LL_LLPACKETBUFFER_H
#include "net.h" // for NET_BUFFER_SIZE
#include "llhost.h"
class LLPacketBuffer
{
public:
LLPacketBuffer(const LLHost &host, const char *datap, const S32 size);
LLPacketBuffer(S32 hSocket); // receive a packet
~LLPacketBuffer();
S32 getSize() const { return mSize; }
const char *getData() const { return mData; }
LLHost getHost() const { return mHost; }
LLHost getReceivingInterface() const { return mReceivingIF; }
void init(S32 hSocket);
void init(const char* buffer, S32 data_size, const LLHost& host);
protected:
char mData[NET_BUFFER_SIZE]; // packet data /* Flawfinder : ignore */
S32 mSize; // size of buffer in bytes
LLHost mHost; // source/dest IP and port
LLHost mReceivingIF; // source/dest IP and port
};
#endif
+365
View File
@@ -0,0 +1,365 @@
/**
* @file llpacketring.cpp
* @brief implementation of LLPacketRing class.
*
* $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 "llpacketring.h"
#if LL_WINDOWS
#include <winsock2.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#endif
// linden library includes
#include "llerror.h"
#include "lltimer.h"
#include "llproxy.h"
#include "llrand.h"
#include "message.h"
#include "u64.h"
constexpr S16 MAX_BUFFER_RING_SIZE = 1024;
constexpr S16 DEFAULT_BUFFER_RING_SIZE = 256;
LLPacketRing::LLPacketRing ()
: mPacketRing(DEFAULT_BUFFER_RING_SIZE, nullptr)
{
LLHost invalid_host;
for (size_t i = 0; i < mPacketRing.size(); ++i)
{
mPacketRing[i] = new LLPacketBuffer(invalid_host, nullptr, 0);
}
}
LLPacketRing::~LLPacketRing ()
{
for (auto packet : mPacketRing)
{
delete packet;
}
mPacketRing.clear();
mNumBufferedPackets = 0;
mNumBufferedBytes = 0;
mHeadIndex = 0;
}
S32 LLPacketRing::receivePacket (S32 socket, char *datap)
{
bool drop = computeDrop();
return (mNumBufferedPackets > 0) ?
receiveOrDropBufferedPacket(datap, drop) :
receiveOrDropPacket(socket, datap, drop);
}
bool send_packet_helper(int socket, const char * datap, S32 data_size, LLHost host)
{
if (!LLProxy::isSOCKSProxyEnabled())
{
return send_packet(socket, datap, data_size, host.getAddress(), host.getPort());
}
char headered_send_buffer[NET_BUFFER_SIZE + SOCKS_HEADER_SIZE];
proxywrap_t *socks_header = static_cast<proxywrap_t*>(static_cast<void*>(&headered_send_buffer));
socks_header->rsv = 0;
socks_header->addr = host.getAddress();
socks_header->port = htons(host.getPort());
socks_header->atype = ADDRESS_IPV4;
socks_header->frag = 0;
memcpy(headered_send_buffer + SOCKS_HEADER_SIZE, datap, data_size);
return send_packet( socket,
headered_send_buffer,
data_size + SOCKS_HEADER_SIZE,
LLProxy::getInstance()->getUDPProxy().getAddress(),
LLProxy::getInstance()->getUDPProxy().getPort());
}
bool LLPacketRing::sendPacket(int socket, const char * datap, S32 data_size, LLHost host)
{
mActualBytesOut += data_size;
return send_packet_helper(socket, datap, data_size, host);
}
void LLPacketRing::dropPackets (U32 num_to_drop)
{
mPacketsToDrop += num_to_drop;
}
void LLPacketRing::setDropPercentage (F32 percent_to_drop)
{
mDropPercentage = percent_to_drop;
}
bool LLPacketRing::computeDrop()
{
bool drop= (mDropPercentage > 0.0f && (ll_frand(100.f) < mDropPercentage));
if (drop)
{
++mPacketsToDrop;
}
if (mPacketsToDrop > 0)
{
--mPacketsToDrop;
drop = true;
}
return drop;
}
S32 LLPacketRing::receiveOrDropPacket(S32 socket, char *datap, bool drop)
{
S32 packet_size = 0;
// pull straight from socket
if (LLProxy::isSOCKSProxyEnabled())
{
char buffer[NET_BUFFER_SIZE + SOCKS_HEADER_SIZE]; /* Flawfinder ignore */
packet_size = receive_packet(socket, buffer);
if (packet_size > 0)
{
mActualBytesIn += packet_size;
}
if (packet_size > SOCKS_HEADER_SIZE)
{
if (drop)
{
packet_size = 0;
}
else
{
// *FIX We are assuming ATYP is 0x01 (IPv4), not 0x03 (hostname) or 0x04 (IPv6)
packet_size -= SOCKS_HEADER_SIZE; // The unwrapped packet size
memcpy(datap, buffer + SOCKS_HEADER_SIZE, packet_size);
proxywrap_t * header = static_cast<proxywrap_t*>(static_cast<void*>(buffer));
mLastSender.setAddress(header->addr);
mLastSender.setPort(ntohs(header->port));
mLastReceivingIF = ::get_receiving_interface();
}
}
else
{
packet_size = 0;
}
}
else
{
packet_size = receive_packet(socket, datap);
if (packet_size > 0)
{
mActualBytesIn += packet_size;
if (drop)
{
packet_size = 0;
}
else
{
mLastSender = ::get_sender();
mLastReceivingIF = ::get_receiving_interface();
}
}
}
return packet_size;
}
S32 LLPacketRing::receiveOrDropBufferedPacket(char *datap, bool drop)
{
assert(mNumBufferedPackets > 0);
S32 packet_size = 0;
S16 ring_size = (S16)(mPacketRing.size());
S16 packet_index = (mHeadIndex + ring_size - mNumBufferedPackets) % ring_size;
LLPacketBuffer* packet = mPacketRing[packet_index];
packet_size = packet->getSize();
mLastSender = packet->getHost();
mLastReceivingIF = packet->getReceivingInterface();
--mNumBufferedPackets;
mNumBufferedBytes -= packet_size;
if (mNumBufferedPackets == 0)
{
assert(mNumBufferedBytes == 0);
}
if (!drop)
{
assert(packet_size > 0);
memcpy(datap, packet->getData(), packet_size);
}
else
{
packet_size = 0;
}
return packet_size;
}
S32 LLPacketRing::bufferInboundPacket(S32 socket)
{
if (mNumBufferedPackets == mPacketRing.size() && mNumBufferedPackets < MAX_BUFFER_RING_SIZE)
{
expandRing();
}
LLPacketBuffer* packet = mPacketRing[mHeadIndex];
S32 old_packet_size = packet->getSize();
S32 packet_size = 0;
if (LLProxy::isSOCKSProxyEnabled())
{
char buffer[NET_BUFFER_SIZE + SOCKS_HEADER_SIZE]; /* Flawfinder ignore */
packet_size = receive_packet(socket, buffer);
if (packet_size > 0)
{
mActualBytesIn += packet_size;
if (packet_size > SOCKS_HEADER_SIZE)
{
// *FIX We are assuming ATYP is 0x01 (IPv4), not 0x03 (hostname) or 0x04 (IPv6)
proxywrap_t * header = static_cast<proxywrap_t*>(static_cast<void*>(buffer));
LLHost sender;
sender.setAddress(header->addr);
sender.setPort(ntohs(header->port));
packet_size -= SOCKS_HEADER_SIZE; // The unwrapped packet size
packet->init(buffer + SOCKS_HEADER_SIZE, packet_size, sender);
mHeadIndex = (mHeadIndex + 1) % (S16)(mPacketRing.size());
if (mNumBufferedPackets < MAX_BUFFER_RING_SIZE)
{
++mNumBufferedPackets;
mNumBufferedBytes += packet_size;
}
else
{
// we overwrote an older packet
mNumBufferedBytes += packet_size - old_packet_size;
}
}
else
{
packet_size = 0;
}
}
}
else
{
packet->init(socket);
packet_size = packet->getSize();
if (packet_size > 0)
{
mActualBytesIn += packet_size;
mHeadIndex = (mHeadIndex + 1) % (S16)(mPacketRing.size());
if (mNumBufferedPackets < MAX_BUFFER_RING_SIZE)
{
++mNumBufferedPackets;
mNumBufferedBytes += packet_size;
}
else
{
// we overwrote an older packet
mNumBufferedBytes += packet_size - old_packet_size;
}
}
}
return packet_size;
}
S32 LLPacketRing::drainSocket(S32 socket)
{
// drain into buffer
S32 packet_size = 1;
S32 num_loops = 0;
S32 old_num_packets = mNumBufferedPackets;
while (packet_size > 0)
{
packet_size = bufferInboundPacket(socket);
++num_loops;
}
S32 num_dropped_packets = (num_loops - 1 + old_num_packets) - mNumBufferedPackets;
if (num_dropped_packets > 0)
{
// It will eventually be accounted by mDroppedPackets
// and mPacketsLost, but track it here for logging purposes.
mNumDroppedPackets += num_dropped_packets;
}
return (S32)(mNumBufferedPackets);
}
bool LLPacketRing::expandRing()
{
// compute larger size
constexpr S16 BUFFER_RING_EXPANSION = 256;
S16 old_size = (S16)(mPacketRing.size());
S16 new_size = llmin(old_size + BUFFER_RING_EXPANSION, MAX_BUFFER_RING_SIZE);
if (new_size == old_size)
{
// mPacketRing is already maxed out
return false;
}
// make a larger ring and copy packet pointers
std::vector<LLPacketBuffer*> new_ring(new_size, nullptr);
for (S16 i = 0; i < old_size; ++i)
{
S16 j = (mHeadIndex + i) % old_size;
new_ring[i] = mPacketRing[j];
}
// allocate new packets for the remainder of new_ring
LLHost invalid_host;
for (S16 i = old_size; i < new_size; ++i)
{
new_ring[i] = new LLPacketBuffer(invalid_host, nullptr, 0);
}
// swap the rings and reset mHeadIndex
mPacketRing.swap(new_ring);
mHeadIndex = mNumBufferedPackets;
return true;
}
F32 LLPacketRing::getBufferLoadRate() const
{
// goes up to MAX_BUFFER_RING_SIZE
return (F32)mNumBufferedPackets / (F32)DEFAULT_BUFFER_RING_SIZE;
}
void LLPacketRing::dumpPacketRingStats()
{
mNumDroppedPacketsTotal += mNumDroppedPackets;
LL_INFOS("Messaging") << "Packet ring stats: " << std::endl
<< "Buffered packets: " << mNumBufferedPackets << std::endl
<< "Buffered bytes: " << mNumBufferedBytes << std::endl
<< "Dropped packets current: " << mNumDroppedPackets << std::endl
<< "Dropped packets total: " << mNumDroppedPacketsTotal << std::endl
<< "Dropped packets percentage: " << mDropPercentage << "%" << std::endl
<< "Actual in bytes: " << mActualBytesIn << std::endl
<< "Actual out bytes: " << mActualBytesOut << LL_ENDL;
mNumDroppedPackets = 0;
}
+110
View File
@@ -0,0 +1,110 @@
/**
* @file llpacketring.h
* @brief definition of LLPacketRing class for implementing a resend,
* drop, or delay in packet transmissions
*
* $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$
*/
#pragma once
#include <vector>
#include "llhost.h"
#include "llpacketbuffer.h"
#include "llthrottle.h"
class LLPacketRing
{
public:
LLPacketRing();
~LLPacketRing();
// receive one packet: either buffered or from the socket
S32 receivePacket (S32 socket, char *datap);
// send one packet
bool sendPacket(int h_socket, const char * send_buffer, S32 buf_size, LLHost host);
// drains packets from socket and returns final mNumBufferedPackets
S32 drainSocket(S32 socket);
void dropPackets(U32);
void setDropPercentage (F32 percent_to_drop);
inline LLHost getLastSender() const;
inline LLHost getLastReceivingInterface() const;
S32 getActualInBytes() const { return mActualBytesIn; }
S32 getActualOutBytes() const { return mActualBytesOut; }
S32 getAndResetActualInBits() { S32 bits = mActualBytesIn * 8; mActualBytesIn = 0; return bits;}
S32 getAndResetActualOutBits() { S32 bits = mActualBytesOut * 8; mActualBytesOut = 0; return bits;}
S32 getNumBufferedPackets() const { return (S32)(mNumBufferedPackets); }
S32 getNumBufferedBytes() const { return mNumBufferedBytes; }
S32 getNumDroppedPackets() const { return mNumDroppedPacketsTotal + mNumDroppedPackets; }
F32 getBufferLoadRate() const; // from 0 to 4 (0 - empty, 1 - default size is full)
void dumpPacketRingStats();
protected:
// returns 'true' if we should intentionally drop a packet
bool computeDrop();
// returns packet_size of received packet, zero or less if no packet found
S32 receiveOrDropPacket(S32 socket, char *datap, bool drop);
S32 receiveOrDropBufferedPacket(char *datap, bool drop);
// returns packet_size of packet buffered
S32 bufferInboundPacket(S32 socket);
// returns 'true' if ring was expanded
bool expandRing();
protected:
std::vector<LLPacketBuffer*> mPacketRing;
S16 mHeadIndex { 0 };
S16 mNumBufferedPackets { 0 };
S32 mNumDroppedPackets { 0 };
S32 mNumDroppedPacketsTotal { 0 };
S32 mNumBufferedBytes { 0 };
S32 mActualBytesIn { 0 };
S32 mActualBytesOut { 0 };
F32 mDropPercentage { 0.0f }; // % of inbound packets to drop
U32 mPacketsToDrop { 0 }; // drop next inbound n packets
// These are the sender and receiving_interface for the last packet delivered by receivePacket()
LLHost mLastSender;
LLHost mLastReceivingIF;
};
inline LLHost LLPacketRing::getLastSender() const
{
return mLastSender;
}
inline LLHost LLPacketRing::getLastReceivingInterface() const
{
return mLastReceivingIF;
}
+508
View File
@@ -0,0 +1,508 @@
/**
* @file llpartdata.cpp
* @brief Particle system data packing
*
* $LicenseInfo:firstyear=2003&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 "llpartdata.h"
#include "message.h"
#include "lldatapacker.h"
#include "v4coloru.h"
#include "llsdutil.h"
#include "llsdutil_math.h"
const S32 PS_PART_DATA_GLOW_SIZE = 2;
const S32 PS_PART_DATA_BLEND_SIZE = 2;
const S32 PS_LEGACY_PART_DATA_BLOCK_SIZE = 4 + 2 + 4 + 4 + 2 + 2; //18
const S32 PS_SYS_DATA_BLOCK_SIZE = 68;
const S32 PS_MAX_DATA_BLOCK_SIZE = PS_SYS_DATA_BLOCK_SIZE+
PS_LEGACY_PART_DATA_BLOCK_SIZE +
PS_PART_DATA_BLEND_SIZE +
PS_PART_DATA_GLOW_SIZE+
8; //two S32 size fields
const S32 PS_LEGACY_DATA_BLOCK_SIZE = PS_SYS_DATA_BLOCK_SIZE + PS_LEGACY_PART_DATA_BLOCK_SIZE;
const F32 MAX_PART_SCALE = 4.f;
bool LLPartData::hasGlow() const
{
return mStartGlow > 0.f || mEndGlow > 0.f;
}
bool LLPartData::hasBlendFunc() const
{
return mBlendFuncSource != LLPartData::LL_PART_BF_SOURCE_ALPHA || mBlendFuncDest != LLPartData::LL_PART_BF_ONE_MINUS_SOURCE_ALPHA;
}
S32 LLPartData::getSize() const
{
S32 size = PS_LEGACY_PART_DATA_BLOCK_SIZE;
if (hasGlow()) size += PS_PART_DATA_GLOW_SIZE;
if (hasBlendFunc()) size += PS_PART_DATA_BLEND_SIZE;
return size;
}
bool LLPartData::unpackLegacy(LLDataPacker &dp)
{
LLColor4U coloru;
dp.unpackU32(mFlags, "pdflags");
dp.unpackFixed(mMaxAge, "pdmaxage", false, 8, 8);
dp.unpackColor4U(coloru, "pdstartcolor");
mStartColor.setVec(coloru);
dp.unpackColor4U(coloru, "pdendcolor");
mEndColor.setVec(coloru);
dp.unpackFixed(mStartScale.mV[0], "pdstartscalex", false, 3, 5);
dp.unpackFixed(mStartScale.mV[1], "pdstartscaley", false, 3, 5);
dp.unpackFixed(mEndScale.mV[0], "pdendscalex", false, 3, 5);
dp.unpackFixed(mEndScale.mV[1], "pdendscaley", false, 3, 5);
mStartGlow = 0.f;
mEndGlow = 0.f;
mBlendFuncSource = LLPartData::LL_PART_BF_SOURCE_ALPHA;
mBlendFuncDest = LLPartData::LL_PART_BF_ONE_MINUS_SOURCE_ALPHA;
return true;
}
bool LLPartData::unpack(LLDataPacker &dp)
{
S32 size = 0;
dp.unpackS32(size, "partsize");
unpackLegacy(dp);
size -= PS_LEGACY_PART_DATA_BLOCK_SIZE;
if (mFlags & LL_PART_DATA_GLOW)
{
if (size < PS_PART_DATA_GLOW_SIZE) return false;
U8 tmp_glow = 0;
dp.unpackU8(tmp_glow,"pdstartglow");
mStartGlow = tmp_glow / 255.f;
dp.unpackU8(tmp_glow,"pdendglow");
mEndGlow = tmp_glow / 255.f;
size -= PS_PART_DATA_GLOW_SIZE;
}
else
{
mStartGlow = 0.f;
mEndGlow = 0.f;
}
if (mFlags & LL_PART_DATA_BLEND)
{
if (size < PS_PART_DATA_BLEND_SIZE) return false;
dp.unpackU8(mBlendFuncSource,"pdblendsource");
dp.unpackU8(mBlendFuncDest,"pdblenddest");
size -= PS_PART_DATA_BLEND_SIZE;
}
else
{
mBlendFuncSource = LLPartData::LL_PART_BF_SOURCE_ALPHA;
mBlendFuncDest = LLPartData::LL_PART_BF_ONE_MINUS_SOURCE_ALPHA;
}
if (size > 0)
{ //leftover bytes, unrecognized parameters
U8 feh = 0;
while (size > 0)
{ //read remaining bytes in block
dp.unpackU8(feh, "whippang");
size--;
}
//this particle system won't display properly, better to not show anything
return false;
}
return true;
}
void LLPartData::setFlags(const U32 flags)
{
mFlags = flags;
}
void LLPartData::setMaxAge(const F32 max_age)
{
mMaxAge = llclamp(max_age, 0.f, 30.f);
}
void LLPartData::setStartScale(const F32 xs, const F32 ys)
{
mStartScale.mV[VX] = llmin(xs, MAX_PART_SCALE);
mStartScale.mV[VY] = llmin(ys, MAX_PART_SCALE);
}
void LLPartData::setEndScale(const F32 xs, const F32 ys)
{
mEndScale.mV[VX] = llmin(xs, MAX_PART_SCALE);
mEndScale.mV[VY] = llmin(ys, MAX_PART_SCALE);
}
void LLPartData::setStartColor(const LLVector3 &rgb)
{
mStartColor.setVec(rgb.mV[0], rgb.mV[1], rgb.mV[2]);
}
void LLPartData::setEndColor(const LLVector3 &rgb)
{
mEndColor.setVec(rgb.mV[0], rgb.mV[1], rgb.mV[2]);
}
void LLPartData::setStartAlpha(const F32 alpha)
{
mStartColor.mV[3] = alpha;
}
void LLPartData::setEndAlpha(const F32 alpha)
{
mEndColor.mV[3] = alpha;
}
// static
bool LLPartData::validBlendFunc(S32 func)
{
if (func >= 0
&& func < LL_PART_BF_COUNT
&& func != UNSUPPORTED_DEST_ALPHA
&& func != UNSUPPORTED_ONE_MINUS_DEST_ALPHA)
{
return true;
}
return false;
}
LLPartSysData::LLPartSysData()
{
mCRC = 0;
mFlags = 0;
mPartData.mFlags = 0;
mPartData.mStartColor = LLColor4(1.f, 1.f, 1.f, 1.f);
mPartData.mEndColor = LLColor4(1.f, 1.f, 1.f, 1.f);
mPartData.mStartScale = LLVector2(1.f, 1.f);
mPartData.mEndScale = LLVector2(1.f, 1.f);
mPartData.mMaxAge = 10.0;
mPartData.mBlendFuncSource = LLPartData::LL_PART_BF_SOURCE_ALPHA;
mPartData.mBlendFuncDest = LLPartData::LL_PART_BF_ONE_MINUS_SOURCE_ALPHA;
mPartData.mStartGlow = 0.f;
mPartData.mEndGlow = 0.f;
mMaxAge = 0.0;
mStartAge = 0.0;
mPattern = LL_PART_SRC_PATTERN_DROP; // Pattern for particle velocity
mInnerAngle = 0.0; // Inner angle of PATTERN_ANGLE_*
mOuterAngle = 0.0; // Outer angle of PATTERN_ANGLE_*
mBurstRate = 0.1f; // How often to do a burst of particles
mBurstPartCount = 1; // How many particles in a burst
mBurstSpeedMin = 1.f; // Minimum particle velocity
mBurstSpeedMax = 1.f; // Maximum particle velocity
mBurstRadius = 0.f;
mNumParticles = 0;
}
bool LLPartSysData::unpackSystem(LLDataPacker &dp)
{
dp.unpackU32(mCRC, "pscrc");
dp.unpackU32(mFlags, "psflags");
dp.unpackU8(mPattern, "pspattern");
dp.unpackFixed(mMaxAge, "psmaxage", false, 8, 8);
dp.unpackFixed(mStartAge, "psstartage", false, 8, 8);
dp.unpackFixed(mInnerAngle, "psinnerangle", false, 3, 5);
dp.unpackFixed(mOuterAngle, "psouterangle", false, 3, 5);
dp.unpackFixed(mBurstRate, "psburstrate", false, 8, 8);
mBurstRate = llmax(0.01f, mBurstRate);
dp.unpackFixed(mBurstRadius, "psburstradius", false, 8, 8);
dp.unpackFixed(mBurstSpeedMin, "psburstspeedmin", false, 8, 8);
dp.unpackFixed(mBurstSpeedMax, "psburstspeedmax", false, 8, 8);
dp.unpackU8(mBurstPartCount, "psburstpartcount");
dp.unpackFixed(mAngularVelocity.mV[0], "psangvelx", true, 8, 7);
dp.unpackFixed(mAngularVelocity.mV[1], "psangvely", true, 8, 7);
dp.unpackFixed(mAngularVelocity.mV[2], "psangvelz", true, 8, 7);
dp.unpackFixed(mPartAccel.mV[0], "psaccelx", true, 8, 7);
dp.unpackFixed(mPartAccel.mV[1], "psaccely", true, 8, 7);
dp.unpackFixed(mPartAccel.mV[2], "psaccelz", true, 8, 7);
dp.unpackUUID(mPartImageID, "psuuid");
dp.unpackUUID(mTargetUUID, "pstargetuuid");
return true;
}
bool LLPartSysData::unpackLegacy(LLDataPacker &dp)
{
unpackSystem(dp);
mPartData.unpackLegacy(dp);
return true;
}
bool LLPartSysData::unpack(LLDataPacker &dp)
{
// syssize is currently unused. Adding now when modifying the 'version to make extensible in the future
S32 size = 0;
dp.unpackS32(size, "syssize");
if (size != PS_SYS_DATA_BLOCK_SIZE)
{ //unexpected size, this viewer doesn't know how to parse this particle system
//skip to LLPartData block
U8 feh = 0;
for (S32 i = 0; i < size; ++i)
{
dp.unpackU8(feh, "whippang");
}
dp.unpackS32(size, "partsize");
//skip LLPartData block
for (S32 i = 0; i < size; ++i)
{
dp.unpackU8(feh, "whippang");
}
return false;
}
unpackSystem(dp);
return mPartData.unpack(dp);
}
std::ostream& operator<<(std::ostream& s, const LLPartSysData &data)
{
s << "Flags: " << std::hex << data.mFlags;
s << "Pattern: " << std::hex << (U32) data.mPattern << "\n";
s << "Source Age: [" << data.mStartAge << ", " << data.mMaxAge << "]\n";
s << "Particle Age: " << data.mPartData.mMaxAge << "\n";
s << "Angle: [" << data.mInnerAngle << ", " << data.mOuterAngle << "]\n";
s << "Burst Rate: " << data.mBurstRate << "\n";
s << "Burst Radius: " << data.mBurstRadius << "\n";
s << "Burst Speed: [" << data.mBurstSpeedMin << ", " << data.mBurstSpeedMax << "]\n";
s << "Burst Part Count: " << std::hex << (U32) data.mBurstPartCount << "\n";
s << "Angular Velocity: " << data.mAngularVelocity << "\n";
s << "Accel: " << data.mPartAccel;
return s;
}
bool LLPartSysData::isNullPS(const S32 block_num)
{
U8 ps_data_block[PS_MAX_DATA_BLOCK_SIZE];
U32 crc;
S32 size;
// Check size of block
size = gMessageSystem->getSize("ObjectData", block_num, "PSBlock");
if (!size)
{
return true;
}
if (size > PS_MAX_DATA_BLOCK_SIZE)
{
//size is too big, newer particle version unsupported
return true;
}
gMessageSystem->getBinaryData("ObjectData", "PSBlock", ps_data_block, size, block_num, PS_MAX_DATA_BLOCK_SIZE);
LLDataPackerBinaryBuffer dp(ps_data_block, size);
if (size > PS_LEGACY_DATA_BLOCK_SIZE)
{
// non legacy systems pack a size before the CRC
S32 tmp = 0;
dp.unpackS32(tmp, "syssize");
if (tmp > PS_SYS_DATA_BLOCK_SIZE)
{ //unknown system data block size, don't know how to parse it, treat as NULL
return true;
}
}
dp.unpackU32(crc, "crc");
if (crc == 0)
{
return true;
}
return false;
}
bool LLPartSysData::unpackBlock(const S32 block_num)
{
U8 ps_data_block[PS_MAX_DATA_BLOCK_SIZE];
// Check size of block
S32 size = gMessageSystem->getSize("ObjectData", block_num, "PSBlock");
if (size > PS_MAX_DATA_BLOCK_SIZE)
{
// Larger packets are newer and unsupported
return false;
}
// Get from message
gMessageSystem->getBinaryData("ObjectData", "PSBlock", ps_data_block, size, block_num, PS_MAX_DATA_BLOCK_SIZE);
LLDataPackerBinaryBuffer dp(ps_data_block, size);
if (size == PS_LEGACY_DATA_BLOCK_SIZE)
{
return unpackLegacy(dp);
}
else
{
return unpack(dp);
}
}
bool LLPartSysData::isLegacyCompatible() const
{
return !mPartData.hasGlow() && !mPartData.hasBlendFunc();
}
void LLPartSysData::clampSourceParticleRate()
{
F32 particle_rate = 0;
particle_rate = mBurstPartCount/mBurstRate;
if (particle_rate > 256.f)
{
mBurstPartCount = llfloor(((F32)mBurstPartCount)*(256.f/particle_rate));
}
}
void LLPartSysData::setPartAccel(const LLVector3 &accel)
{
mPartAccel.mV[VX] = llclamp(accel.mV[VX], -100.f, 100.f);
mPartAccel.mV[VY] = llclamp(accel.mV[VY], -100.f, 100.f);
mPartAccel.mV[VZ] = llclamp(accel.mV[VZ], -100.f, 100.f);
}
LLSD LLPartSysData::asLLSD() const
{
LLSD sd = LLSD();
sd["LL_PART_INTERP_COLOR_MASK"] = (LLPartData::LL_PART_INTERP_COLOR_MASK & mPartData.mFlags) ? 1 : 0;
sd["LL_PART_INTERP_SCALE_MASK"] = (LLPartData::LL_PART_INTERP_SCALE_MASK & mPartData.mFlags) ? 1 : 0;
sd["LL_PART_BOUNCE_MASK"] = (LLPartData::LL_PART_BOUNCE_MASK & mPartData.mFlags) ? 1 : 0;
sd["LL_PART_WIND_MASK"] = (LLPartData::LL_PART_WIND_MASK & mPartData.mFlags) ? 1 : 0;
sd["LL_PART_FOLLOW_SRC_MASK"] = (LLPartData::LL_PART_FOLLOW_SRC_MASK & mPartData.mFlags) ? 1 : 0;
sd["LL_PART_FOLLOW_VELOCITY_MASK"] = (LLPartData::LL_PART_FOLLOW_VELOCITY_MASK & mPartData.mFlags) ? 1 : 0;
sd["LL_PART_TARGET_POS_MASK"] = (LLPartData::LL_PART_TARGET_POS_MASK & mPartData.mFlags) ? 1 : 0;
sd["LL_PART_TARGET_LINEAR_MASK"] = (LLPartData::LL_PART_TARGET_LINEAR_MASK & mPartData.mFlags) ? 1 : 0;
sd["LL_PART_EMISSIVE_MASK"] = (LLPartData::LL_PART_EMISSIVE_MASK & mPartData.mFlags) ? 1 : 0;
sd["LL_PART_BEAM_MASK"] = (LLPartData::LL_PART_BEAM_MASK & mPartData.mFlags) ? 1 : 0;
sd["ParticleMaxAge"] = mPartData.mMaxAge;
sd["StartColor"] = ll_sd_from_color4(mPartData.mStartColor);
sd["EndColor"] = ll_sd_from_color4(mPartData.mEndColor);
sd["StartScale"] = ll_sd_from_vector2(mPartData.mStartScale);
sd["EndScale"] = ll_sd_from_vector2(mPartData.mEndScale);
sd["SourceMaxAge"] = mMaxAge;
sd["SourceStartAge"] = mStartAge;
sd["LL_PART_SRC_PATTERN_DROP"] = ( mPattern & LL_PART_SRC_PATTERN_DROP) ? 1 : 0;
sd["LL_PART_SRC_PATTERN_EXPLODE"] = ( mPattern & LL_PART_SRC_PATTERN_EXPLODE) ? 1 : 0;
sd["LL_PART_SRC_PATTERN_ANGLE"] = ( mPattern & LL_PART_SRC_PATTERN_ANGLE) ? 1 : 0;
sd["LL_PART_SRC_PATTERN_ANGLE_CONE"] = ( mPattern & LL_PART_SRC_PATTERN_ANGLE_CONE) ? 1 : 0 ;
sd["LL_PART_SRC_PATTERN_ANGLE_CONE_EMPTY"] = ( mPattern & LL_PART_SRC_PATTERN_ANGLE_CONE_EMPTY) ? 1 : 0;
sd["InnerAngle"] = mInnerAngle;
sd["OuterAngle"] = mOuterAngle;
sd["AngularVelocity"] = ll_sd_from_vector3(mAngularVelocity);
sd["BurstRate"] = mBurstRate;
sd["BurstPartCount"] = mBurstPartCount;
sd["BurstSpeedMin"] = mBurstSpeedMin;
sd["BurstSpeedMax"] = mBurstSpeedMax;
sd["BurstRadius"] = mBurstRadius;
sd["PartImageID"] = mPartImageID.asString();
sd["TargetId"] = mTargetUUID.asString();
return sd;
}
bool LLPartSysData::fromLLSD(LLSD& sd)
{
mPartData.mFlags = 0;
if (sd["LL_PART_INTERP_COLOR_MASK"]) mPartData.mFlags |= LLPartData::LL_PART_INTERP_COLOR_MASK;
if (sd["LL_PART_INTERP_SCALE_MASK"]) mPartData.mFlags |= LLPartData::LL_PART_INTERP_SCALE_MASK;
if (sd["LL_PART_BOUNCE_MASK"]) mPartData.mFlags |= LLPartData::LL_PART_BOUNCE_MASK;
if (sd["LL_PART_WIND_MASK"]) mPartData.mFlags |= LLPartData::LL_PART_WIND_MASK;
if (sd["LL_PART_FOLLOW_SRC_MASK"]) mPartData.mFlags |= LLPartData::LL_PART_FOLLOW_SRC_MASK;
if (sd["LL_PART_FOLLOW_VELOCITY_MASK"]) mPartData.mFlags |= LLPartData::LL_PART_FOLLOW_VELOCITY_MASK;
if (sd["LL_PART_TARGET_POS_MASK"]) mPartData.mFlags |= LLPartData::LL_PART_TARGET_POS_MASK;
if (sd["LL_PART_TARGET_LINEAR_MASK"]) mPartData.mFlags |= LLPartData::LL_PART_TARGET_LINEAR_MASK;
if (sd["LL_PART_EMISSIVE_MASK"]) mPartData.mFlags |= LLPartData::LL_PART_EMISSIVE_MASK;
if (sd["LL_PART_BEAM_MASK"]) mPartData.mFlags |= LLPartData::LL_PART_BEAM_MASK;
mPartData.mMaxAge = (F32)sd["ParticleMaxAge"].asReal();
mPartData.mStartColor = ll_color4_from_sd(sd["StartColor"]);
mPartData.mEndColor = ll_color4_from_sd(sd["EndColor"]);
mPartData.mStartScale = ll_vector2_from_sd(sd["StartScale"]);
mPartData.mEndScale = ll_vector2_from_sd(sd["EndScale"]);
mMaxAge = (F32)sd["SourceMaxAge"].asReal();
mStartAge = (F32)sd["SourceStartAge"].asReal();
mPattern = 0;
if (sd["LL_PART_SRC_PATTERN_DROP"]) mPattern |= LL_PART_SRC_PATTERN_DROP;
if (sd["LL_PART_SRC_PATTERN_EXPLODE"]) mPattern |= LL_PART_SRC_PATTERN_EXPLODE;
if (sd["LL_PART_SRC_PATTERN_ANGLE"]) mPattern |= LL_PART_SRC_PATTERN_ANGLE;
if (sd["LL_PART_SRC_PATTERN_ANGLE_CONE"]) mPattern |= LL_PART_SRC_PATTERN_ANGLE_CONE;
if (sd["LL_PART_SRC_PATTERN_ANGLE_CONE_EMPTY"]) mPattern |= LL_PART_SRC_PATTERN_ANGLE_CONE_EMPTY;
mInnerAngle = (F32)sd["InnerAngle"].asReal();
mOuterAngle = (F32)sd["OuterAngle"].asReal();
mAngularVelocity = ll_vector3_from_sd(sd["AngularVelocity"]);
mBurstRate = (F32)sd["BurstRate"].asReal();
int burst_part_count = sd["BurstPartCount"];
mBurstPartCount = (U8)burst_part_count;
mBurstSpeedMin = (F32)sd["BurstSpeedMin"].asReal();
mBurstSpeedMax = (F32)sd["BurstSpeedMax"].asReal();
mBurstRadius = (F32)sd["BurstRadius"].asReal();
mPartImageID = LLUUID(sd[("PartImageID")].asString());
mTargetUUID = LLUUID(sd["TargetId"].asString());
return true;
}
+287
View File
@@ -0,0 +1,287 @@
/**
* @file llpartdata.h
* @brief Particle system data packing
*
* $LicenseInfo:firstyear=2003&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_LLPARTDATA_H
#define LL_LLPARTDATA_H
#include "lluuid.h"
#include "v3math.h"
#include "v3dmath.h"
#include "v2math.h"
#include "v4color.h"
class LLMessageSystem;
class LLDataPacker;
const S32 PS_CUR_VERSION = 18;
//
// These constants are used by the script code, not by the particle system itself
//
enum LLPSScriptFlags
{
// Flags for the different parameters of individual particles
LLPS_PART_FLAGS,
LLPS_PART_START_COLOR,
LLPS_PART_START_ALPHA,
LLPS_PART_END_COLOR,
LLPS_PART_END_ALPHA,
LLPS_PART_START_SCALE,
LLPS_PART_END_SCALE,
LLPS_PART_MAX_AGE,
// Flags for the different parameters of the particle source
LLPS_SRC_ACCEL,
LLPS_SRC_PATTERN,
LLPS_SRC_INNERANGLE,
LLPS_SRC_OUTERANGLE,
LLPS_SRC_TEXTURE,
LLPS_SRC_BURST_RATE,
LLPS_SRC_BURST_DURATION,
LLPS_SRC_BURST_PART_COUNT,
LLPS_SRC_BURST_RADIUS,
LLPS_SRC_BURST_SPEED_MIN,
LLPS_SRC_BURST_SPEED_MAX,
LLPS_SRC_MAX_AGE,
LLPS_SRC_TARGET_UUID,
LLPS_SRC_OMEGA,
LLPS_SRC_ANGLE_BEGIN,
LLPS_SRC_ANGLE_END,
LLPS_PART_BLEND_FUNC_SOURCE,
LLPS_PART_BLEND_FUNC_DEST,
LLPS_PART_START_GLOW,
LLPS_PART_END_GLOW
};
class LLPartData
{
public:
LLPartData() :
mFlags(0),
mMaxAge(0.f),
mParameter(0.f)
{
}
// <FS:ND> Need virtual dtor so derived classed are properly destroyed.
virtual ~LLPartData()
{ }
// </FS:ND>
bool unpackLegacy(LLDataPacker &dp);
bool unpack(LLDataPacker &dp);
bool pack(LLDataPacker &dp);
bool hasGlow() const;
bool hasBlendFunc() const;
// Masks for the different particle flags
enum
{
LL_PART_INTERP_COLOR_MASK = 0x01,
LL_PART_INTERP_SCALE_MASK = 0x02,
LL_PART_BOUNCE_MASK = 0x04,
LL_PART_WIND_MASK = 0x08,
LL_PART_FOLLOW_SRC_MASK = 0x10, // Follows source, no rotation following (expensive!)
LL_PART_FOLLOW_VELOCITY_MASK = 0x20, // Particles orient themselves with velocity
LL_PART_TARGET_POS_MASK = 0x40,
LL_PART_TARGET_LINEAR_MASK = 0x80, // Particle uses a direct linear interpolation
LL_PART_EMISSIVE_MASK = 0x100, // Particle is "emissive", instead of being lit
LL_PART_BEAM_MASK = 0x200, // Particle is a "beam" connecting source and target
LL_PART_RIBBON_MASK = 0x400, // Particles are joined together into one continuous triangle strip
// Not implemented yet!
//LL_PART_RANDOM_ACCEL_MASK = 0x100, // Particles have random acceleration
//LL_PART_RANDOM_VEL_MASK = 0x200, // Particles have random velocity shifts"
//LL_PART_TRAIL_MASK = 0x400, // Particles have historical "trails"
//sYSTEM SET FLAGS
LL_PART_DATA_GLOW = 0x10000,
LL_PART_DATA_BLEND = 0x20000,
// Viewer side use only!
LL_PART_HUD = 0x40000000,
LL_PART_DEAD_MASK = 0x80000000,
};
enum
{
LL_PART_BF_ONE = 0,
LL_PART_BF_ZERO = 1,
LL_PART_BF_DEST_COLOR = 2,
LL_PART_BF_SOURCE_COLOR = 3,
LL_PART_BF_ONE_MINUS_DEST_COLOR = 4,
LL_PART_BF_ONE_MINUS_SOURCE_COLOR = 5,
UNSUPPORTED_DEST_ALPHA = 6,
LL_PART_BF_SOURCE_ALPHA = 7,
UNSUPPORTED_ONE_MINUS_DEST_ALPHA = 8,
LL_PART_BF_ONE_MINUS_SOURCE_ALPHA = 9,
LL_PART_BF_COUNT = 10
};
static bool validBlendFunc(S32 func);
void setFlags(const U32 flags);
void setMaxAge(const F32 max_age);
void setStartScale(const F32 xs, F32 ys);
void setEndScale(const F32 xs, F32 ys);
void setStartColor(const LLVector3 &rgb);
void setEndColor(const LLVector3 &rgb);
void setStartAlpha(const F32 alpha);
void setEndAlpha(const F32 alpha);
friend class LLPartSysData;
friend class LLViewerPartSourceScript;
private:
S32 getSize() const;
// These are public because I'm really lazy...
public:
U32 mFlags; // Particle state/interpolators in effect
F32 mMaxAge; // Maximum age of the particle
LLColor4 mStartColor; // Start color
LLColor4 mEndColor; // End color
LLVector2 mStartScale; // Start scale
LLVector2 mEndScale; // End scale
LLVector3 mPosOffset; // Offset from source if using FOLLOW_SOURCE
F32 mParameter; // A single floating point parameter
F32 mStartGlow;
F32 mEndGlow;
U8 mBlendFuncSource;
U8 mBlendFuncDest;
};
class LLPartSysData
{
public:
LLPartSysData();
bool unpack(LLDataPacker &dp);
bool unpackLegacy(LLDataPacker &dp);
bool unpackBlock(const S32 block_num);
LLSD asLLSD() const;
bool fromLLSD(LLSD& sd);
static bool isNullPS(const S32 block_num); // Returns false if this is a "NULL" particle system (i.e. no system)
bool isLegacyCompatible() const;
// Different masks for effects on the source
enum
{
LL_PART_SRC_OBJ_REL_MASK = 0x01, // Accel and velocity for particles relative object rotation
LL_PART_USE_NEW_ANGLE = 0x02, // Particles uses new 'correct' angle parameters.
};
// The different patterns for how particles are created
enum
{
LL_PART_SRC_PATTERN_DROP = 0x01,
LL_PART_SRC_PATTERN_EXPLODE = 0x02,
// Not implemented fully yet
LL_PART_SRC_PATTERN_ANGLE = 0x04,
LL_PART_SRC_PATTERN_ANGLE_CONE = 0x08,
LL_PART_SRC_PATTERN_ANGLE_CONE_EMPTY = 0x10,
};
void setBurstSpeedMin(const F32 spd) { mBurstSpeedMin = llclamp(spd, -100.f, 100.f); }
void setBurstSpeedMax(const F32 spd) { mBurstSpeedMax = llclamp(spd, -100.f, 100.f); }
void setBurstRadius(const F32 rad) { mBurstRadius = llclamp(rad, 0.f, 50.f); }
void setPartAccel(const LLVector3 &accel);
void setUseNewAngle() { mFlags |= LL_PART_USE_NEW_ANGLE; }
void unsetUseNewAngle() { mFlags &= ~LL_PART_USE_NEW_ANGLE; }
// Since the actual particle creation rate is
// a combination of multiple parameters, we
// need to clamp it using a separate method instead of an accessor.
void clampSourceParticleRate();
friend std::ostream& operator<<(std::ostream& s, const LLPartSysData &data); // Stream a
S32 getdataBlockSize() const;
private:
bool unpackSystem(LLDataPacker &dp);
public:
// Public because I'm lazy....
//
// There are two kinds of data for the particle system
// 1. Parameters which specify parameters of the source (mSource*)
// 2. Parameters which specify parameters of the particles generated by the source (mPart*)
//
U32 mCRC;
U32 mFlags;
U8 mPattern; // Pattern for particle velocity/output
F32 mInnerAngle; // Inner angle for PATTERN_ANGLE
F32 mOuterAngle; // Outer angle for PATTERN_ANGLE
LLVector3 mAngularVelocity; // Angular velocity for emission axis (for PATTERN_ANGLE)
F32 mBurstRate; // How often to do a burst of particles
U8 mBurstPartCount; // How many particles in a burst
F32 mBurstRadius;
F32 mBurstSpeedMin; // Minimum particle velocity
F32 mBurstSpeedMax; // Maximum particle velocity
F32 mMaxAge; // Maximum lifetime of this particle source
LLUUID mTargetUUID; // Target UUID for the particle system
F32 mStartAge; // Age at which to start the particle system (for an update after the
// particle system has started)
//
// These are actually particle properties, but can be mutated by the source,
// so are stored here instead
//
LLVector3 mPartAccel;
LLUUID mPartImageID;
//
// The "template" partdata where we actually store the non-mutable particle parameters
//
LLPartData mPartData;
protected:
S32 mNumParticles; // Number of particles generated
};
#endif // LL_LLPARTDATA_H
+555
View File
@@ -0,0 +1,555 @@
/**
* @file llproxy.cpp
* @brief UDP and HTTP proxy communications
*
* $LicenseInfo:firstyear=2011&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2011, 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 "llproxy.h"
#include <string>
#include <curl/curl.h>
#include "httpcommon.h"
#include "llapr.h"
#include "llhost.h"
// Static class variable instances
// We want this to be static to avoid excessive indirection on every
// incoming packet just to do a simple bool test. The getter for this
// member is also static
bool LLProxy::sUDPProxyEnabled = false;
LLProxy* LLProxy::sProxyInstance = NULL;
// Some helpful TCP static functions.
static apr_status_t tcp_blocking_handshake(LLSocket::ptr_t handle, char * dataout, apr_size_t outlen, char * datain, apr_size_t maxinlen); // Do a TCP data handshake
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
LLProxy::LLProxy():
mHTTPProxyEnabled(false),
mProxyMutex(),
mUDPProxy(),
mTCPProxy(),
mHTTPProxy(),
mProxyType(LLPROXY_SOCKS),
mAuthMethodSelected(METHOD_NOAUTH),
mSocksUsername(),
mSocksPassword()
{}
LLProxy::~LLProxy()
{
if (ll_apr_is_initialized())
{
// locks mutex
stopSOCKSProxy();
disableHTTPProxy();
}
// The primary safety of sProxyInstance is the fact that by the
// point SUBSYSTEM_CLEANUP(LLProxy) gets called, nothing should
// be capable of using proxy
sProxyInstance = NULL;
}
void LLProxy::initSingleton()
{
sProxyInstance = this;
}
/**
* @brief Open the SOCKS 5 TCP control channel.
*
* Perform a SOCKS 5 authentication and UDP association with the proxy server.
*
* @param proxy The SOCKS 5 server to connect to.
* @return SOCKS_OK if successful, otherwise a socks error code from llproxy.h.
*/
S32 LLProxy::proxyHandshake(LLHost proxy)
{
S32 result;
/* 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(); // Send only the selected method.
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)),
sizeof(socks_auth_response));
if (result != APR_SUCCESS)
{
LL_WARNS("Proxy") << "SOCKS authentication request failed, error on TCP control channel : " << result << LL_ENDL;
stopSOCKSProxy();
return SOCKS_CONNECT_ERROR;
}
if (socks_auth_response.method == AUTH_NOT_ACCEPTABLE)
{
LL_WARNS("Proxy") << "SOCKS 5 server refused all our authentication methods." << LL_ENDL;
stopSOCKSProxy();
return SOCKS_NOT_ACCEPTABLE;
}
/* SOCKS 5 USERNAME/PASSWORD authentication */
if (socks_auth_response.method == METHOD_PASSWORD)
{
// The server has requested a username/password combination
std::string socks_username(getSocksUser());
std::string socks_password(getSocksPwd());
U32 request_size = static_cast<S32>(socks_username.size() + socks_password.size() + 3);
char * password_auth = new char[request_size];
password_auth[0] = 0x01;
password_auth[1] = (char)(socks_username.size());
memcpy(&password_auth[2], socks_username.c_str(), socks_username.size());
password_auth[socks_username.size() + 2] = (char)(socks_password.size());
memcpy(&password_auth[socks_username.size() + 3], socks_password.c_str(), socks_password.size());
authmethod_password_reply_t password_reply;
result = tcp_blocking_handshake(mProxyControlChannel,
password_auth,
request_size,
static_cast<char*>(static_cast<void*>(&password_reply)),
sizeof(password_reply));
delete[] password_auth;
if (result != APR_SUCCESS)
{
LL_WARNS("Proxy") << "SOCKS authentication failed, error on TCP control channel : " << result << LL_ENDL;
stopSOCKSProxy();
return SOCKS_CONNECT_ERROR;
}
if (password_reply.status != AUTH_SUCCESS)
{
LL_WARNS("Proxy") << "SOCKS authentication failed" << LL_ENDL;
stopSOCKSProxy();
return SOCKS_AUTH_FAIL;
}
}
/* SOCKS5 connect request */
socks_command_request_t connect_request;
socks_command_response_t connect_reply;
connect_request.version = SOCKS_VERSION; // SOCKS V5
connect_request.command = COMMAND_UDP_ASSOCIATE; // Associate UDP
connect_request.reserved = FIELD_RESERVED;
connect_request.atype = ADDRESS_IPV4;
connect_request.address = htonl(0); // 0.0.0.0
connect_request.port = htons(0); // 0
// "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(mProxyControlChannel,
static_cast<char*>(static_cast<void*>(&connect_request)),
sizeof(connect_request),
static_cast<char*>(static_cast<void*>(&connect_reply)),
sizeof(connect_reply));
if (result != APR_SUCCESS)
{
LL_WARNS("Proxy") << "SOCKS connect request failed, error on TCP control channel : " << result << LL_ENDL;
stopSOCKSProxy();
return SOCKS_CONNECT_ERROR;
}
if (connect_reply.reply != REPLY_REQUEST_GRANTED)
{
LL_WARNS("Proxy") << "Connection to SOCKS 5 server failed, UDP forward request not granted" << LL_ENDL;
stopSOCKSProxy();
return SOCKS_UDP_FWD_NOT_GRANTED;
}
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 " << mUDPProxy << LL_ENDL;
return SOCKS_OK;
}
/**
* @brief Initiates a SOCKS 5 proxy session.
*
* Performs basic checks on host to verify that it is a valid address. Opens the control channel
* and then negotiates the proxy connection with the server. Closes any existing SOCKS
* connection before proceeding. Also disables an HTTP proxy if it is using SOCKS as the proxy.
*
*
* @param host Socks server to connect to.
* @return SOCKS_OK if successful, otherwise a SOCKS error code defined in llproxy.h.
*/
S32 LLProxy::startSOCKSProxy(LLHost host)
{
if (host.isOk())
{
mTCPProxy = host;
}
else
{
return SOCKS_INVALID_HOST;
}
// Close any running SOCKS connection.
stopSOCKSProxy();
mProxyControlChannel = tcp_open_channel(mTCPProxy);
if (!mProxyControlChannel)
{
return SOCKS_HOST_CONNECT_FAILED;
}
S32 status = proxyHandshake(mTCPProxy);
if (status != SOCKS_OK)
{
// Shut down the proxy if any of the above steps failed.
stopSOCKSProxy();
}
else
{
// Connection was successful.
sUDPProxyEnabled = true;
}
return status;
}
/**
* @brief Stop using the SOCKS 5 proxy.
*
* This will stop sending UDP packets through the SOCKS 5 proxy
* and will also stop the HTTP proxy if it is configured to use SOCKS.
* The proxy control channel will also be disconnected.
*/
void LLProxy::stopSOCKSProxy()
{
sUDPProxyEnabled = false;
// If the SOCKS proxy is requested to stop and we are using that for HTTP as well
// then we must shut down any HTTP proxy operations. But it is allowable if web
// proxy is being used to continue proxying HTTP.
if (LLPROXY_SOCKS == getHTTPProxyType())
{
disableHTTPProxy();
}
if (mProxyControlChannel)
{
tcp_close_channel(&mProxyControlChannel);
}
}
/**
* @brief Set the proxy's SOCKS authentication method to none.
*/
void LLProxy::setAuthNone()
{
LLMutexLock lock(&mProxyMutex);
mAuthMethodSelected = METHOD_NOAUTH;
}
/**
* @brief Set the proxy's SOCKS authentication method to password.
*
* Check whether the lengths of the supplied username
* and password conform to the lengths allowed by the
* SOCKS protocol.
*
* @param username The SOCKS username to send.
* @param password The SOCKS password to send.
* @return Return true if applying the settings was successful. No changes are made if false.
*
*/
bool LLProxy::setAuthPassword(const std::string &username, const std::string &password)
{
if (username.length() > SOCKSMAXUSERNAMELEN || password.length() > SOCKSMAXPASSWORDLEN ||
username.length() < SOCKSMINUSERNAMELEN || password.length() < SOCKSMINPASSWORDLEN)
{
LL_WARNS("Proxy") << "Invalid SOCKS 5 password or username length." << LL_ENDL;
return false;
}
LLMutexLock lock(&mProxyMutex);
mAuthMethodSelected = METHOD_PASSWORD;
mSocksUsername = username;
mSocksPassword = password;
return true;
}
/**
* @brief Enable the HTTP proxy for either SOCKS or HTTP.
*
* Check the supplied host to see if it is a valid IP and port.
*
* @param httpHost Proxy server to connect to.
* @param type Is the host a SOCKS or HTTP proxy.
* @return Return true if applying the setting was successful. No changes are made if false.
*/
bool LLProxy::enableHTTPProxy(LLHost httpHost, LLHttpProxyType type)
{
if (!httpHost.isOk())
{
LL_WARNS("Proxy") << "Invalid SOCKS 5 Server" << LL_ENDL;
return false;
}
LLMutexLock lock(&mProxyMutex);
mHTTPProxy = httpHost;
mProxyType = type;
mHTTPProxyEnabled = true;
return true;
}
/**
* @brief Enable the HTTP proxy without changing the proxy settings.
*
* This should not be called unless the proxy has already been set up.
*
* @return Return true only if the current settings are valid and the proxy was enabled.
*/
bool LLProxy::enableHTTPProxy()
{
bool ok;
LLMutexLock lock(&mProxyMutex);
ok = (mHTTPProxy.isOk());
if (ok)
{
mHTTPProxyEnabled = true;
}
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.
*
* Deletes the LLProxy singleton, destroying the APR pool used by the control channel as well as .
*/
//static
void LLProxy::cleanupClass()
{
if (instanceExists())
{
getInstance()->stopSOCKSProxy();
deleteSingleton();
}
}
/**
* @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 (sProxyInstance && sProxyInstance->mHTTPProxyEnabled)
{
// We think we should proxy, lock the proxy mutex. sProxyInstance is not protected by mutex
LLMutexLock lock(&sProxyInstance->mProxyMutex);
// Now test again to verify that the proxy wasn't disabled between the first check and the lock.
if (sProxyInstance->mHTTPProxyEnabled)
{
LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXY, sProxyInstance->mHTTPProxy.getIPString().c_str()), CURLOPT_PROXY);
LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYPORT, sProxyInstance->mHTTPProxy.getPort()), CURLOPT_PROXYPORT);
if (sProxyInstance->mProxyType == LLPROXY_SOCKS)
{
LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5), CURLOPT_PROXYTYPE);
if (sProxyInstance->mAuthMethodSelected == METHOD_PASSWORD)
{
std::string auth_string = sProxyInstance->mSocksUsername + ":" + sProxyInstance->mSocksPassword;
LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYUSERPWD, auth_string.c_str()), CURLOPT_PROXYUSERPWD);
}
}
else
{
LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP), CURLOPT_PROXYTYPE);
}
}
}
}
/**
* @brief Send one TCP packet and receive one in return.
*
* This operation is done synchronously with a 100ms timeout. Therefore, it should not be used when a blocking
* operation would impact the operation of the viewer.
*
* @param handle_ptr Pointer to a connected LLSocket of type STREAM_TCP.
* @param dataout Data to send.
* @param outlen Length of dataout.
* @param datain Buffer for received data. Undefined if return value is not APR_SUCCESS.
* @param maxinlen Maximum possible length of received data. Short reads are allowed.
* @return Indicates APR status code of exchange. APR_SUCCESS if exchange was successful, -1 if invalid data length was received.
*/
static apr_status_t tcp_blocking_handshake(LLSocket::ptr_t handle, char * dataout, apr_size_t outlen, char * datain, apr_size_t maxinlen)
{
apr_socket_t* apr_socket = handle->getSocket();
apr_status_t rv = APR_SUCCESS;
apr_size_t expected_len = outlen;
handle->setBlocking(100000); // 100ms, 100000us. Should be sufficient for localhost, nearby network
rv = apr_socket_send(apr_socket, dataout, &outlen);
if (APR_SUCCESS != rv)
{
char buf[MAX_STRING];
LL_WARNS("Proxy") << "Error sending data to proxy control channel, status: " << rv << " " << apr_strerror(rv, buf, MAX_STRING) << LL_ENDL;
ll_apr_warn_status(rv);
}
else if (expected_len != outlen)
{
LL_WARNS("Proxy") << "Incorrect data length sent. Expected: " << expected_len <<
" Sent: " << outlen << LL_ENDL;
rv = -1;
}
// ms_sleep(1); // <FS:Beq/> remove the unnecessary sleep.
if (APR_SUCCESS == rv)
{
expected_len = maxinlen;
rv = apr_socket_recv(apr_socket, datain, &maxinlen);
if (rv != APR_SUCCESS)
{
char buf[MAX_STRING];
LL_WARNS("Proxy") << "Error receiving data from proxy control channel, status: " << rv << " " << apr_strerror(rv, buf, MAX_STRING) << LL_ENDL;
ll_apr_warn_status(rv);
}
else if (expected_len < maxinlen)
{
LL_WARNS("Proxy") << "Incorrect data length received. Expected: " << expected_len <<
" Received: " << maxinlen << LL_ENDL;
rv = -1;
}
}
handle->setNonBlocking();
return rv;
}
/**
* @brief Open a LLSocket and do a blocking connect to the chosen host.
*
* Checks for a successful connection, and makes sure the connection is closed if it fails.
*
* @param host The host to open the connection to.
* @return The created socket. Will evaluate as NULL if the connection is unsuccessful.
*/
static LLSocket::ptr_t tcp_open_channel(LLHost host)
{
LLSocket::ptr_t socket = LLSocket::create(NULL, LLSocket::STREAM_TCP);
bool connected = socket->blockingConnect(host);
if (!connected)
{
tcp_close_channel(&socket);
}
return socket;
}
/**
* @brief Close the socket.
*
* @param handle_ptr The handle of the socket being closed. A pointer-to-pointer to avoid increasing the use count.
*/
static void tcp_close_channel(LLSocket::ptr_t* handle_ptr)
{
LL_DEBUGS("Proxy") << "Resetting proxy LLSocket handle, use_count == " << handle_ptr->use_count() << LL_ENDL;
handle_ptr->reset();
}
+355
View File
@@ -0,0 +1,355 @@
/**
* @file llproxy.h
* @brief UDP and HTTP proxy communications
*
* $LicenseInfo:firstyear=2011&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2011, 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_PROXY_H
#define LL_PROXY_H
#include "llhost.h"
#include "lliosocket.h"
#include "llmemory.h"
#include "llsingleton.h"
#include "llthread.h"
#include "llmutex.h"
#include <curl/curl.h>
#include <string>
// SOCKS error codes returned from the StartProxy method
#define SOCKS_OK 0
#define SOCKS_CONNECT_ERROR (-1)
#define SOCKS_NOT_PERMITTED (-2)
#define SOCKS_NOT_ACCEPTABLE (-3)
#define SOCKS_AUTH_FAIL (-4)
#define SOCKS_UDP_FWD_NOT_GRANTED (-5)
#define SOCKS_HOST_CONNECT_FAILED (-6)
#define SOCKS_INVALID_HOST (-7)
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN (255 + 1) /* socks5: 255, +1 for len. */
#endif
#define SOCKSMAXUSERNAMELEN 255
#define SOCKSMAXPASSWORDLEN 255
#define SOCKSMINUSERNAMELEN 1
#define SOCKSMINPASSWORDLEN 1
#define SOCKS_VERSION 0x05 // we are using SOCKS 5
#define SOCKS_HEADER_SIZE 10
// SOCKS 5 address/hostname types
#define ADDRESS_IPV4 0x01
#define ADDRESS_HOSTNAME 0x03
#define ADDRESS_IPV6 0x04
// Lets just use our own ipv4 struct rather than dragging in system
// specific headers
union ipv4_address_t {
U8 octets[4];
U32 addr32;
};
// SOCKS 5 control channel commands
#define COMMAND_TCP_STREAM 0x01
#define COMMAND_TCP_BIND 0x02
#define COMMAND_UDP_ASSOCIATE 0x03
// SOCKS 5 command replies
#define REPLY_REQUEST_GRANTED 0x00
#define REPLY_GENERAL_FAIL 0x01
#define REPLY_RULESET_FAIL 0x02
#define REPLY_NETWORK_UNREACHABLE 0x03
#define REPLY_HOST_UNREACHABLE 0x04
#define REPLY_CONNECTION_REFUSED 0x05
#define REPLY_TTL_EXPIRED 0x06
#define REPLY_PROTOCOL_ERROR 0x07
#define REPLY_TYPE_NOT_SUPPORTED 0x08
#define FIELD_RESERVED 0x00
// The standard SOCKS 5 request packet
// Push current alignment to stack and set alignment to 1 byte boundary
// This enabled us to use structs directly to set up and receive network packets
// into the correct fields, without fear of boundary alignment causing issues
#pragma pack(push,1)
// SOCKS 5 command packet
struct socks_command_request_t {
U8 version;
U8 command;
U8 reserved;
U8 atype;
U32 address;
U16 port;
};
// Standard SOCKS 5 reply packet
struct socks_command_response_t {
U8 version;
U8 reply;
U8 reserved;
U8 atype;
U8 add_bytes[4];
U16 port;
};
#define AUTH_NOT_ACCEPTABLE 0xFF // reply if preferred methods are not available
#define AUTH_SUCCESS 0x00 // reply if authentication successful
// SOCKS 5 authentication request, stating which methods the client supports
struct socks_auth_request_t {
U8 version;
U8 num_methods;
U8 methods; // We are only using a single method currently
};
// SOCKS 5 authentication response packet, stating server preferred method
struct socks_auth_response_t {
U8 version;
U8 method;
};
// SOCKS 5 password reply packet
struct authmethod_password_reply_t {
U8 version;
U8 status;
};
// SOCKS 5 UDP packet header
struct proxywrap_t {
U16 rsv;
U8 frag;
U8 atype;
U32 addr;
U16 port;
};
#pragma pack(pop) /* restore original alignment from stack */
// Currently selected HTTP proxy type
enum LLHttpProxyType
{
LLPROXY_SOCKS = 0,
LLPROXY_HTTP = 1
};
// Auth types
enum LLSocks5AuthType
{
METHOD_NOAUTH = 0x00, // Client supports no auth
METHOD_GSSAPI = 0x01, // Client supports GSSAPI (Not currently supported)
METHOD_PASSWORD = 0x02 // Client supports username/password
};
/**
* @brief Manage SOCKS 5 UDP proxy and HTTP proxy.
*
* This class is responsible for managing two interconnected tasks,
* connecting to a SOCKS 5 proxy for use by LLPacketRing to send UDP
* packets and managing proxy settings for HTTP requests.
*
* <h1>Threading:</h1>
* Because HTTP requests can be generated in threads outside the
* main thread, it is necessary for some of the information stored
* by this class to be available to other threads. The members that
* need to be read across threads are in a labeled section below.
* To protect those members, a mutex, mProxyMutex should be locked
* before reading or writing those members. Methods that can lock
* mProxyMutex are in a labeled section below. Those methods should
* not be called while the mutex is already locked.
*
* There is also a LLAtomic type flag (mHTTPProxyEnabled) that is used
* to track whether the HTTP proxy is currently enabled. This allows
* for faster unlocked checks to see if the proxy is enabled. This
* allows us to cut down on the performance hit when the proxy is
* disabled compared to before this class was introduced.
*
* <h1>UDP Proxying:</h1>
* UDP datagrams are proxied via a SOCKS 5 proxy with the UDP associate
* command. To initiate the proxy, a TCP socket connection is opened
* to the SOCKS 5 host, and after a handshake exchange, the server
* returns a port and address to send the UDP traffic that is to be
* proxied to. The LLProxy class tracks this address and port after the
* exchange and provides it to LLPacketRing when required to. All UDP
* proxy management occurs in the main thread.
*
* <h1>HTTP Proxying:</h1>
* This class allows all viewer HTTP packets to be sent through a proxy.
* The user can select whether to send HTTP packets through a standard
* "web" HTTP proxy, through a SOCKS 5 proxy, or to not proxy HTTP
* communication. This class does not manage the integrated web browser
* proxy, which is handled in llviewermedia.cpp.
*
* 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()). This method is overloaded
* to accommodate the various abstraction libcurl layers that exist
* throughout the viewer (CURL).
*
* To ensure thread safety, all LLProxy members that relate to the HTTP
* proxy require the LLProxyMutex to be locked before accessing.
*
* *TODO$: This should be moved into the LLCore::Http space.
*
*/
class LLProxy: public LLSingleton<LLProxy>
{
/*###########################################################################################
METHODS THAT DO NOT LOCK mProxyMutex!
###########################################################################################*/
// Constructor, cannot have parameters due to LLSingleton parent class. Call from main thread only.
LLSINGLETON(LLProxy);
LOG_CLASS(LLProxy);
/*virtual*/ void initSingleton() override;
public:
// 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. Call from main thread only.
LLHost getUDPProxy() const { return mUDPProxy; }
/*###########################################################################################
END OF NON-LOCKING METHODS
###########################################################################################*/
/*###########################################################################################
METHODS THAT LOCK mProxyMutex! DO NOT CALL WHILE mProxyMutex IS LOCKED!
###########################################################################################*/
private:
// Destructor, closes open connections. Do not call directly, use cleanupClass().
~LLProxy();
public:
// Delete LLProxy singleton. Allows the apr_socket used in the SOCKS 5 control channel to be
// destroyed before the call to apr_terminate. Call from main thread only.
static void cleanupClass();
// Apply the current proxy settings to a curl request. Doesn't do anything if mHTTPProxyEnabled is false.
// Safe to call from any thread.
static void applyProxySettings(CURL* handle);
// Start a connection to the SOCKS 5 proxy. Call from main thread only.
S32 startSOCKSProxy(LLHost host);
// Disconnect and clean up any connection to the SOCKS 5 proxy. Call from main thread only.
void stopSOCKSProxy();
// Use Password auth when connecting to the SOCKS proxy. Call from main thread only.
bool setAuthPassword(const std::string &username, const std::string &password);
// Disable authentication when connecting to the SOCKS proxy. Call from main thread only.
void setAuthNone();
// Proxy HTTP packets via httpHost, which can be a SOCKS 5 or a HTTP proxy.
// as specified in type. Call from main thread only.
bool enableHTTPProxy(LLHost httpHost, LLHttpProxyType type);
bool enableHTTPProxy();
// Stop proxying HTTP packets. Call from main thread only.
void disableHTTPProxy();
/*###########################################################################################
END OF LOCKING METHODS
###########################################################################################*/
private:
/*###########################################################################################
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 LOCKING METHODS
###########################################################################################*/
private:
// Is the HTTP proxy enabled? Safe to read in any thread, but do not write directly.
// Instead use enableHTTPProxy() and disableHTTPProxy() instead.
mutable LLAtomicBool 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;
// 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
###########################################################################################*/
/*###########################################################################################
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
###########################################################################################*/
// A hack to get arround getInstance() and capture_dependency() which are unsafe to use inside threads
// set/reset on init/cleanup, strictly for use in applyProxySettings
static LLProxy* sProxyInstance;
};
#endif
File diff suppressed because it is too large Load Diff
+442
View File
@@ -0,0 +1,442 @@
/**
* @file llpumpio.h
* @author Phoenix
* @date 2004-11-19
* @brief Declaration of pump class which manages io chains.
*
* $LicenseInfo:firstyear=2004&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_LLPUMPIO_H
#define LL_LLPUMPIO_H
#include <set>
#if LL_LINUX // needed for PATH_MAX in APR.
#include <sys/param.h>
#endif
#include "apr_pools.h"
#include "llbuffer.h"
#include "llframetimer.h"
#include "lliopipe.h"
#include "llrun.h"
// some simple constants to help with timeouts
extern const F32 DEFAULT_CHAIN_EXPIRY_SECS;
extern const F32 SHORT_CHAIN_EXPIRY_SECS;
extern const F32 NEVER_CHAIN_EXPIRY_SECS;
/**
* @class LLPumpIO
* @brief Class to manage sets of io chains.
*
* The pump class provides a thread abstraction for doing IO based
* communication between two threads in a structured and optimized for
* processor time. The primary usage is to create a pump, and call
* <code>pump()</code> on a thread used for IO and call
* <code>respond()</code> on a thread that is expected to do higher
* level processing. You can call almost any other method from any
* thread - see notes for each method for details. In order for the
* threading abstraction to work, you need to call <code>prime()</code>
* with a valid apr pool.
* A pump instance manages much of the state for the pipe, including
* the list of pipes in the chain, the channel for each element in the
* chain, the buffer, and if any pipe has marked the stream or process
* as done. Pipes can also set file descriptor based conditional
* statements so that calls to process do not happen until data is
* ready to be read or written. Pipes control execution of calls to
* process by returning a status code such as STATUS_OK or
* STATUS_BREAK.
* One way to conceptualize the way IO will work is that a pump
* combines the unit processing of pipes to behave like file pipes on
* the unix command line.
*/
class LLPumpIO
{
public:
/**
* @brief Constructor.
*/
LLPumpIO(apr_pool_t* pool);
/**
* @brief Destructor.
*/
~LLPumpIO();
/**
* @brief Prepare this pump for usage.
*
* If you fail to call this method prior to use, the pump will
* try to work, but will not come with any thread locking
* mechanisms.
* @param pool The apr pool to use.
* @return Returns true if the pump is primed.
*/
bool prime(apr_pool_t* pool);
/**
* @brief Typedef for having a chain of pipes.
*/
typedef std::vector<LLIOPipe::ptr_t> chain_t;
/**
* @brief Add a chain to this pump and process in the next cycle.
*
* This method will automatically generate a buffer and assign
* each link in the chain as if it were the consumer to the
* previous.
* @param chain The pipes for the chain
* @param timeout The number of seconds in the future to
* expire. Pass in 0.0f to never expire.
* @param has_curl_request The chain contains LLURLRequest if true.
* @return Returns true if anything was added to the pump.
*/
bool addChain(const chain_t& chain, F32 timeout, bool has_curl_request = false);
/**
* @brief Struct to associate a pipe with it's buffer io indexes.
*/
struct LLLinkInfo
{
LLIOPipe::ptr_t mPipe;
LLChannelDescriptors mChannels;
};
/**
* @brief Typedef for having a chain of <code>LLLinkInfo</code>
* instances.
*/
typedef std::vector<LLLinkInfo> links_t;
/**
* @brief Add a chain to this pump and process in the next cycle.
*
* This method provides a slightly more sophisticated method for
* adding a chain where the caller can specify which link elements
* are on what channels. This method will fail if no buffer is
* provided since any calls to generate new channels for the
* buffers will cause unpredictable interleaving of data.
* @param links The pipes and io indexes for the chain
* @param data Shared pointer to data buffer
* @param context Potentially undefined context meta-data for chain.
* @param timeout The number of seconds in the future to
* expire. Pass in 0.0f to never expire.
* @return Returns true if anything was added to the pump.
*/
bool addChain(
const links_t& links,
LLIOPipe::buffer_ptr_t data,
LLSD context,
F32 timeout);
/**
* @brief Set or clear a timeout for the running chain
*
* @param timeout The number of seconds in the future to
* expire. Pass in 0.0f to never expire.
* @return Returns true if the timer was set.
*/
bool setTimeoutSeconds(F32 timeout);
/**
* @brief Adjust the timeout of the running chain.
*
* This method has no effect if there is no timeout on the chain.
* @param delta The number of seconds to add to/remove from the timeout.
*/
void adjustTimeoutSeconds(F32 delta);
/**
* @brief Set up file descriptors for for the running chain.
* @see rebuildPollset()
*
* There is currently a limit of one conditional per pipe.
* *NOTE: The internal mechanism for building a pollset based on
* pipe/pollfd/chain generates an epoll error on linux (and
* probably behaves similarly on other platforms) because the
* pollset rebuilder will add each apr_pollfd_t serially. This
* does not matter for pipes on the same chain, since any
* signalled pipe will eventually invoke a call to process(), but
* is a problem if the same apr_pollfd_t is on different
* chains. Once we have more than just network i/o on the pump,
* this might matter.
* *FIX: Given the structure of the pump and pipe relationship,
* this should probably go through a different mechanism than the
* pump. I think it would be best if the pipe had some kind of
* controller which was passed into <code>process()</code> rather
* than the pump which exposed this interface.
* @param pipe The pipe which is setting a conditional
* @param poll The entire socket and read/write condition - null to remove
* @return Returns true if the poll state was set.
*/
bool setConditional(LLIOPipe* pipe, const apr_pollfd_t* poll);
/**
* @brief Lock the current chain.
* @see sleepChain() since it relies on the implementation of this method.
*
* This locks the currently running chain so that no more calls to
* <code>process()</code> until you call <code>clearLock()</code>
* with the lock identifier.
* *FIX: Given the structure of the pump and pipe relationship,
* this should probably go through a different mechanism than the
* pump. I think it would be best if the pipe had some kind of
* controller which was passed into <code>process()</code> rather
* than the pump which exposed this interface.
* @return Returns the lock identifer to be used in
* <code>clearLock()</code> or 0 on failure.
*/
S32 setLock();
/**
* @brief Clears the identified lock.
*
* @param links A container for the links which will be appended
*/
void clearLock(S32 key);
/**
* @brief Stop processing a chain for a while.
* @see setLock()
*
* This method will <em>not</em> update the timeout for this
* chain, so it is possible to sleep the chain until it is
* collected by the pump during a timeout cleanup.
* @param seconds The number of seconds in the future to
* resume processing.
* @return Returns true if the
*/
bool sleepChain(F64 seconds);
/**
* @brief Copy the currently running chain link info
*
* *FIX: Given the structure of the pump and pipe relationship,
* this should probably go through a different mechanism than the
* pump. I think it would be best if the pipe had some kind of
* controller which was passed into <code>process()</code> rather
* than the pump which exposed this interface.
* @param links A container for the links which will be appended
* @return Returns true if the currently running chain was copied.
*/
bool copyCurrentLinkInfo(links_t& links) const;
/**
* @brief Call this method to call process on all running chains.
*
* This method iterates through the running chains, and if all
* pipe on a chain are unconditionally ready or if any pipe has
* any conditional processiong condition then process will be
* called on every chain which has requested processing. that
* chain has a file descriptor ready, <code>process()</code> will
* be called for all pipes which have requested it.
*/
void pump(const S32& poll_timeout);
void pump();
/**
* @brief Add a chain to a special queue which will be called
* during the next call to <code>callback()</code> and then
* dropped from the queue.
*
* @param chain The IO chain that will get one <code>process()</code>.
*/
//void respond(const chain_t& pipes);
/**
* @brief Add pipe to a special queue which will be called
* during the next call to <code>callback()</code> and then dropped
* from the queue.
*
* This call will add a single pipe, with no buffer, context, or
* channel information to the callback queue. It will be called
* once, and then dropped.
* @param pipe A single io pipe which will be called
* @return Returns true if anything was added to the pump.
*/
bool respond(LLIOPipe* pipe);
/**
* @brief Add a chain to a special queue which will be called
* during the next call to <code>callback()</code> and then
* dropped from the queue.
*
* It is important to remember that you should not add a data
* buffer or context which may still be in another chain - that
* will almost certainly lead to a problems. Ensure that you are
* done reading and writing to those parameters, have new
* generated, or empty pointers.
* @param links The pipes and io indexes for the chain
* @param data Shared pointer to data buffer
* @param context Potentially undefined context meta-data for chain.
* @return Returns true if anything was added to the pump.
*/
bool respond(
const links_t& links,
LLIOPipe::buffer_ptr_t data,
LLSD context);
/**
* @brief Run through the callback queue and call <code>process()</code>.
*
* This call will process all prending responses and call process
* on each. This method will then drop all processed callback
* requests which may lead to deleting the referenced objects.
*/
void callback();
/**
* @brief Enumeration to send commands to the pump.
*/
enum EControl
{
PAUSE,
RESUME,
};
/**
* @brief Send a command to the pump.
*
* @param op What control to send to the pump.
*/
void control(EControl op);
protected:
/**
* @brief State of the pump
*/
enum EState
{
NORMAL,
PAUSING,
PAUSED
};
// instance data
EState mState;
bool mRebuildPollset;
apr_pollset_t* mPollset;
S32 mPollsetClientID;
S32 mNextLock;
std::set<S32> mClearLocks;
// This is the pump's runnable scheduler used for handling
// expiring locks.
LLRunner mRunner;
// This structure is the stuff we track while running chains.
struct LLChainInfo
{
// methods
LLChainInfo();
void setTimeoutSeconds(F32 timeout);
void adjustTimeoutSeconds(F32 delta);
// basic member data
bool mInit;
bool mEOS;
bool mHasCurlRequest;
S32 mLock;
LLFrameTimer mTimer;
links_t::iterator mHead;
links_t mChainLinks;
LLIOPipe::buffer_ptr_t mData;
LLSD mContext;
// tracking inside the pump
typedef std::pair<LLIOPipe::ptr_t, apr_pollfd_t> pipe_conditional_t;
typedef std::vector<pipe_conditional_t> conditionals_t;
conditionals_t mDescriptors;
};
// All the running chains & info
typedef std::vector<LLChainInfo> pending_chains_t;
pending_chains_t mPendingChains;
typedef std::list<LLChainInfo> running_chains_t;
running_chains_t mRunningChains;
typedef running_chains_t::iterator current_chain_t;
current_chain_t mCurrentChain;
// structures necessary for doing callbacks
// since the callbacks only get one chance to run, we do not have
// to maintain a list.
typedef std::vector<LLChainInfo> callbacks_t;
callbacks_t mPendingCallbacks;
callbacks_t mCallbacks;
// memory allocator for pollsets & mutexes.
apr_pool_t* mPool;
apr_pool_t* mCurrentPool;
S32 mCurrentPoolReallocCount;
protected:
void initialize(apr_pool_t* pool);
void cleanup();
current_chain_t removeRunningChain(current_chain_t& chain) ;
/**
* @brief Given the internal state of the chains, rebuild the pollset
* @see setConditional()
*/
void rebuildPollset();
/**
* @brief Process the chain passed in.
*
* This method will potentially modify the internals of the
* chain. On end, the chain.mHead will equal
* chain.mChainLinks.end().
* @param chain The LLChainInfo object to work on.
*/
void processChain(LLChainInfo& chain);
/**
* @brief Rewind through the chain to try to recover from an error.
*
* This method will potentially modify the internals of the
* chain.
* @param chain The LLChainInfo object to work on.
* @return Retuns true if someone handled the error
*/
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.
*
* *NOTE: This is only used in debugging and not considered
* efficient or safe enough for production use.
*/
running_chains_t::size_type runningChains() const
{
return mRunningChains.size();
}
};
#endif // LL_LLPUMPIO_H
+102
View File
@@ -0,0 +1,102 @@
/**
* @file llqueryflags.h
* @brief Flags for directory queries
*
* $LicenseInfo:firstyear=2003&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_LLQUERYFLAGS_H
#define LL_LLQUERYFLAGS_H
// Binary flags used for Find queries, shared between viewer and dataserver.
// DirFindQuery flags
const U32 DFQ_PEOPLE = 0x1 << 0;
const U32 DFQ_ONLINE = 0x1 << 1;
//const U32 DFQ_PLACES = 0x1 << 2;
const U32 DFQ_EVENTS = 0x1 << 3; // This is not set by the 1.21 viewer, but I don't know about older versions. JC
const U32 DFQ_GROUPS = 0x1 << 4;
const U32 DFQ_DATE_EVENTS = 0x1 << 5;
const U32 DFQ_AGENT_OWNED = 0x1 << 6;
const U32 DFQ_FOR_SALE = 0x1 << 7;
const U32 DFQ_GROUP_OWNED = 0x1 << 8;
//const U32 DFQ_AUCTION = 0x1 << 9;
const U32 DFQ_DWELL_SORT = 0x1 << 10;
const U32 DFQ_PG_SIMS_ONLY = 0x1 << 11;
const U32 DFQ_PICTURES_ONLY = 0x1 << 12;
const U32 DFQ_PG_EVENTS_ONLY = 0x1 << 13;
const U32 DFQ_MATURE_SIMS_ONLY = 0x1 << 14;
const U32 DFQ_SORT_ASC = 0x1 << 15;
const U32 DFQ_PRICE_SORT = 0x1 << 16;
const U32 DFQ_PER_METER_SORT = 0x1 << 17;
const U32 DFQ_AREA_SORT = 0x1 << 18;
const U32 DFQ_NAME_SORT = 0x1 << 19;
const U32 DFQ_LIMIT_BY_PRICE = 0x1 << 20;
const U32 DFQ_LIMIT_BY_AREA = 0x1 << 21;
const U32 DFQ_FILTER_MATURE = 0x1 << 22;
const U32 DFQ_PG_PARCELS_ONLY = 0x1 << 23;
const U32 DFQ_INC_PG = 0x1 << 24; // Flags appear in 1.23 viewer or later
const U32 DFQ_INC_MATURE = 0x1 << 25;
const U32 DFQ_INC_ADULT = 0x1 << 26;
const U32 DFQ_INC_NEW_VIEWER = (DFQ_INC_PG | DFQ_INC_MATURE | DFQ_INC_ADULT); // Indicates 1.23 viewer or later
const U32 DFQ_ADULT_SIMS_ONLY = 0x1 << 27;
// Sell Type flags
const U32 ST_AUCTION = 0x1 << 1;
const U32 ST_NEWBIE = 0x1 << 2;
const U32 ST_MAINLAND = 0x1 << 3;
const U32 ST_ESTATE = 0x1 << 4;
const U32 ST_ALL = 0xFFFFFFFF;
// status flags embedded in search replay messages of classifieds, events, groups, and places.
// Places
const U32 STATUS_SEARCH_PLACES_NONE = 0x0;
const U32 STATUS_SEARCH_PLACES_BANNEDWORD = 0x1 << 0;
const U32 STATUS_SEARCH_PLACES_SHORTSTRING = 0x1 << 1;
const U32 STATUS_SEARCH_PLACES_FOUNDNONE = 0x1 << 2;
const U32 STATUS_SEARCH_PLACES_SEARCHDISABLED = 0x1 << 3;
const U32 STATUS_SEARCH_PLACES_ESTATEEMPTY = 0x1 << 4;
// Events
const U32 STATUS_SEARCH_EVENTS_NONE = 0x0;
const U32 STATUS_SEARCH_EVENTS_BANNEDWORD = 0x1 << 0;
const U32 STATUS_SEARCH_EVENTS_SHORTSTRING = 0x1 << 1;
const U32 STATUS_SEARCH_EVENTS_FOUNDNONE = 0x1 << 2;
const U32 STATUS_SEARCH_EVENTS_SEARCHDISABLED = 0x1 << 3;
const U32 STATUS_SEARCH_EVENTS_NODATEOFFSET = 0x1 << 4;
const U32 STATUS_SEARCH_EVENTS_NOCATEGORY = 0x1 << 5;
const U32 STATUS_SEARCH_EVENTS_NOQUERY = 0x1 << 6;
//Classifieds
const U32 STATUS_SEARCH_CLASSIFIEDS_NONE = 0x0;
const U32 STATUS_SEARCH_CLASSIFIEDS_BANNEDWORD = 0x1 << 0;
const U32 STATUS_SEARCH_CLASSIFIEDS_SHORTSTRING = 0x1 << 1;
const U32 STATUS_SEARCH_CLASSIFIEDS_FOUNDNONE = 0x1 << 2;
const U32 STATUS_SEARCH_CLASSIFIEDS_SEARCHDISABLED = 0x1 << 3;
#endif
+209
View File
@@ -0,0 +1,209 @@
/**
* @file llregionflags.h
* @brief Flags that are sent in the statistics message region_flags field.
*
* $LicenseInfo:firstyear=2002&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_LLREGIONFLAGS_H
#define LL_LLREGIONFLAGS_H
// Can you be hurt here? Should health be on?
constexpr U64 REGION_FLAGS_ALLOW_DAMAGE = (1ULL << 0);
// Can you make landmarks here?
constexpr U64 REGION_FLAGS_ALLOW_LANDMARK = (1ULL << 1);
// Do we reset the home position when someone teleports away from here?
constexpr U64 REGION_FLAGS_ALLOW_SET_HOME = (1ULL << 2);
// Do we reset the home position when someone teleports away from here?
constexpr U64 REGION_FLAGS_RESET_HOME_ON_TELEPORT = (1ULL << 3);
// Does the sun move?
constexpr U64 REGION_FLAGS_SUN_FIXED = (1ULL << 4);
// Does the estate owner allow private parcels?
constexpr U64 REGION_FLAGS_ALLOW_ACCESS_OVERRIDE = (1ULL << 5);
// Can't change the terrain heightfield, even on owned parcels,
// but can plant trees and grass.
constexpr U64 REGION_FLAGS_BLOCK_TERRAFORM = (1ULL << 6);
// Can't release, sell, or buy land.
constexpr U64 REGION_FLAGS_BLOCK_LAND_RESELL = (1ULL << 7);
// All content wiped once per night
constexpr U64 REGION_FLAGS_SANDBOX = (1ULL << 8);
constexpr U64 REGION_FLAGS_ALLOW_ENVIRONMENT_OVERRIDE = (1ULL << 9);
constexpr U64 REGION_FLAGS_SKIP_COLLISIONS = (1ULL << 12); // Pin all non agent rigid bodies
constexpr U64 REGION_FLAGS_SKIP_SCRIPTS = (1ULL << 13);
constexpr U64 REGION_FLAGS_SKIP_PHYSICS = (1ULL << 14); // Skip all physics
constexpr U64 REGION_FLAGS_EXTERNALLY_VISIBLE = (1ULL << 15);
constexpr U64 REGION_FLAGS_ALLOW_RETURN_ENCROACHING_OBJECT = (1ULL << 16);
constexpr U64 REGION_FLAGS_ALLOW_RETURN_ENCROACHING_ESTATE_OBJECT = (1ULL << 17);
constexpr U64 REGION_FLAGS_BLOCK_DWELL = (1ULL << 18);
// Is flight allowed?
constexpr U64 REGION_FLAGS_BLOCK_FLY = (1ULL << 19);
// Is direct teleport (p2p) allowed?
constexpr U64 REGION_FLAGS_ALLOW_DIRECT_TELEPORT = (1ULL << 20);
// Is there an administrative override on scripts in the region at the
// moment. This is the similar skip scripts, except this flag is
// presisted in the database on an estate level.
constexpr U64 REGION_FLAGS_ESTATE_SKIP_SCRIPTS = (1ULL << 21);
constexpr U64 REGION_FLAGS_RESTRICT_PUSHOBJECT = (1ULL << 22);
constexpr U64 REGION_FLAGS_DENY_ANONYMOUS = (1ULL << 23);
constexpr U64 REGION_FLAGS_ALLOW_PARCEL_CHANGES = (1ULL << 26);
constexpr U64 REGION_FLAGS_BLOCK_FLYOVER = (1ULL << 27);
constexpr U64 REGION_FLAGS_ALLOW_VOICE = (1ULL << 28);
constexpr U64 REGION_FLAGS_BLOCK_PARCEL_SEARCH = (1ULL << 29);
constexpr U64 REGION_FLAGS_DENY_AGEUNVERIFIED = (1ULL << 30);
constexpr U64 REGION_FLAGS_DENY_BOTS = (1ULL << 31);
constexpr U64 REGION_FLAGS_DEFAULT = REGION_FLAGS_ALLOW_LANDMARK |
REGION_FLAGS_ALLOW_SET_HOME |
REGION_FLAGS_ALLOW_PARCEL_CHANGES |
REGION_FLAGS_ALLOW_VOICE;
constexpr U64 REGION_FLAGS_PRELUDE_SET = REGION_FLAGS_RESET_HOME_ON_TELEPORT;
constexpr U64 REGION_FLAGS_PRELUDE_UNSET = REGION_FLAGS_ALLOW_LANDMARK |
REGION_FLAGS_ALLOW_SET_HOME;
constexpr U64 REGION_FLAGS_ESTATE_MASK = REGION_FLAGS_EXTERNALLY_VISIBLE |
REGION_FLAGS_SUN_FIXED |
REGION_FLAGS_DENY_ANONYMOUS |
REGION_FLAGS_DENY_AGEUNVERIFIED;
inline bool is_flag_set(U64 flags, U64 flag)
{
return (flags & flag) != 0;
}
inline bool is_prelude( U64 flags )
{
// definition of prelude does not depend on fixed-sun
return !is_flag_set(flags, REGION_FLAGS_PRELUDE_UNSET) &&
is_flag_set(flags, REGION_FLAGS_PRELUDE_SET);
}
inline U64 set_prelude_flags(U64 flags)
{
// also set the sun-fixed flag
return ((flags & ~REGION_FLAGS_PRELUDE_UNSET)
| (REGION_FLAGS_PRELUDE_SET | REGION_FLAGS_SUN_FIXED));
}
inline U64 unset_prelude_flags(U64 flags)
{
// also unset the fixed-sun flag
return ((flags | REGION_FLAGS_PRELUDE_UNSET)
& ~(REGION_FLAGS_PRELUDE_SET | REGION_FLAGS_SUN_FIXED));
}
// Region protocols
constexpr U64 REGION_PROTOCOLS_AGENT_APPEARANCE_SERVICE = (1ULL << 0);
// estate constants. Need to match first few etries in indra.estate table.
constexpr U32 ESTATE_ALL = 0; // will not match in db, reserved key for logic
constexpr U32 ESTATE_MAINLAND = 1;
constexpr U32 ESTATE_ORIENTATION = 2;
constexpr U32 ESTATE_INTERNAL = 3;
constexpr U32 ESTATE_SHOWCASE = 4;
constexpr U32 ESTATE_TEEN = 5;
constexpr U32 ESTATE_LAST_LINDEN = 5; // last linden owned/managed estate
// for EstateOwnerRequest, setaccess message
constexpr U32 ESTATE_ACCESS_ALLOWED_AGENTS = 1 << 0;
constexpr U32 ESTATE_ACCESS_ALLOWED_GROUPS = 1 << 1;
constexpr U32 ESTATE_ACCESS_BANNED_AGENTS = 1 << 2;
constexpr U32 ESTATE_ACCESS_MANAGERS = 1 << 3;
//maximum number of access list entries we can fit in one packet
constexpr S32 ESTATE_ACCESS_MAX_ENTRIES_PER_PACKET = 63;
// for reply to "getinfo", don't need to forward to all sims in estate
constexpr U32 ESTATE_ACCESS_SEND_TO_AGENT_ONLY = 1 << 4;
constexpr U32 ESTATE_ACCESS_ALL = ESTATE_ACCESS_ALLOWED_AGENTS
| ESTATE_ACCESS_ALLOWED_GROUPS
| ESTATE_ACCESS_BANNED_AGENTS
| ESTATE_ACCESS_MANAGERS;
// for EstateOwnerRequest, estateaccessdelta, estateexperiencedelta messages
constexpr U32 ESTATE_ACCESS_APPLY_TO_ALL_ESTATES = 1U << 0;
constexpr U32 ESTATE_ACCESS_APPLY_TO_MANAGED_ESTATES = 1U << 1;
constexpr U32 ESTATE_ACCESS_ALLOWED_AGENT_ADD = 1U << 2;
constexpr U32 ESTATE_ACCESS_ALLOWED_AGENT_REMOVE = 1U << 3;
constexpr U32 ESTATE_ACCESS_ALLOWED_GROUP_ADD = 1U << 4;
constexpr U32 ESTATE_ACCESS_ALLOWED_GROUP_REMOVE = 1U << 5;
constexpr U32 ESTATE_ACCESS_BANNED_AGENT_ADD = 1U << 6;
constexpr U32 ESTATE_ACCESS_BANNED_AGENT_REMOVE = 1U << 7;
constexpr U32 ESTATE_ACCESS_MANAGER_ADD = 1U << 8;
constexpr U32 ESTATE_ACCESS_MANAGER_REMOVE = 1U << 9;
constexpr U32 ESTATE_ACCESS_NO_REPLY = 1U << 10;
constexpr U32 ESTATE_ACCESS_FAILED_BAN_ESTATE_MANAGER = 1U << 11;
constexpr S32 ESTATE_MAX_MANAGERS = 20;
constexpr S32 ESTATE_MAX_MANAGERS_OS = 15; // <FS:Ansariel> OpenSim
constexpr S32 ESTATE_MAX_ACCESS_IDS = 500; // max for access
constexpr S32 ESTATE_MAX_BANNED_IDS = 750; // max for banned
constexpr S32 ESTATE_MAX_BANNED_IDS_OS = 500; // max for banned // <FS:Ansariel> OpenSim
constexpr S32 ESTATE_MAX_GROUP_IDS = (S32) ESTATE_ACCESS_MAX_ENTRIES_PER_PACKET;
// 'Sim Wide Delete' flags
constexpr U32 SWD_OTHERS_LAND_ONLY = (1 << 0);
constexpr U32 SWD_ALWAYS_RETURN_OBJECTS = (1 << 1);
constexpr U32 SWD_SCRIPTED_ONLY = (1 << 2);
// Controls experience key validity in the estate
constexpr U32 EXPERIENCE_KEY_TYPE_NONE = 0;
constexpr U32 EXPERIENCE_KEY_TYPE_BLOCKED = 1;
constexpr U32 EXPERIENCE_KEY_TYPE_ALLOWED = 2;
constexpr U32 EXPERIENCE_KEY_TYPE_TRUSTED = 3;
constexpr U32 EXPERIENCE_KEY_TYPE_FIRST = EXPERIENCE_KEY_TYPE_BLOCKED;
constexpr U32 EXPERIENCE_KEY_TYPE_LAST = EXPERIENCE_KEY_TYPE_TRUSTED;
//
constexpr U32 ESTATE_EXPERIENCE_TRUSTED_ADD = 1U << 2;
constexpr U32 ESTATE_EXPERIENCE_TRUSTED_REMOVE = 1U << 3;
constexpr U32 ESTATE_EXPERIENCE_ALLOWED_ADD = 1U << 4;
constexpr U32 ESTATE_EXPERIENCE_ALLOWED_REMOVE = 1U << 5;
constexpr U32 ESTATE_EXPERIENCE_BLOCKED_ADD = 1U << 6;
constexpr U32 ESTATE_EXPERIENCE_BLOCKED_REMOVE = 1U << 7;
constexpr S32 ESTATE_MAX_EXPERIENCE_IDS = 8;
#endif
+149
View File
@@ -0,0 +1,149 @@
/**
* @file llregionhandle.h
* @brief Routines for converting positions to/from region handles.
*
* $LicenseInfo:firstyear=2002&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_LLREGIONHANDLE_H
#define LL_LLREGIONHANDLE_H
#include "indra_constants.h"
#include "v3math.h"
#include "v3dmath.h"
inline U64 to_region_handle(const U32 x_origin, const U32 y_origin)
{
U64 region_handle;
region_handle = ((U64)x_origin) << 32;
region_handle |= (U64) y_origin;
return region_handle;
}
// <FS:Beq> FIRE-30534 Overload that takes explicit region origin and width to improve Var Region identification.
inline U64 to_region_handle(const LLVector3d& pos_global, const LLVector3d& agent_region_origin, const F32 width)
{
U32 global_x { static_cast<U32>( pos_global.mdV[VX] ) };
U32 global_y { static_cast<U32>( pos_global.mdV[VY] ) };
U32 agent_region_origin_x { static_cast<U32>( agent_region_origin.mdV[VX] ) };
U32 agent_region_origin_y { static_cast<U32>( agent_region_origin.mdV[VY] ) };
if( agent_region_origin_x < global_x && ( agent_region_origin_x + width ) > global_x &&
agent_region_origin_y < global_y && ( agent_region_origin_y + width ) > global_y )
{
// target is local to current region we can make a more informed guess
return to_region_handle( agent_region_origin_x, agent_region_origin_y );
}
// fallback to legacy 256m tile-based guess and let the region server / map work it out.
global_x -= global_x % 256;
global_y -= global_y % 256;
return to_region_handle( global_x, global_y );
}
// </FS:Beq>
inline U64 to_region_handle(const LLVector3d& pos_global)
{
U32 global_x = (U32)pos_global.mdV[VX];
global_x -= global_x % 256;
U32 global_y = (U32)pos_global.mdV[VY];
global_y -= global_y % 256;
return to_region_handle(global_x, global_y);
}
inline U64 to_region_handle_global(const F32 x_global, const F32 y_global)
{
// Round down to the nearest origin
U32 x_origin = (U32)x_global;
x_origin -= x_origin % REGION_WIDTH_U32;
U32 y_origin = (U32)y_global;
y_origin -= y_origin % REGION_WIDTH_U32;
U64 region_handle;
region_handle = ((U64)x_origin) << 32;
region_handle |= (U64) y_origin;
return region_handle;
}
inline bool to_region_handle(const F32 x_pos, const F32 y_pos, U64 *region_handle)
{
U32 x_int, y_int;
if (x_pos < 0.f)
{
// LL_WARNS() << "to_region_handle:Clamping negative x position " << x_pos << " to zero!" << LL_ENDL;
return false;
}
else
{
x_int = (U32)ll_round(x_pos);
}
if (y_pos < 0.f)
{
// LL_WARNS() << "to_region_handle:Clamping negative y position " << y_pos << " to zero!" << LL_ENDL;
return false;
}
else
{
y_int = (U32)ll_round(y_pos);
}
*region_handle = to_region_handle(x_int, y_int);
return true;
}
// stuff the word-frame XY location of sim's SouthWest corner in x_pos, y_pos
inline void from_region_handle(const U64 &region_handle, F32 *x_pos, F32 *y_pos)
{
*x_pos = (F32)((U32)(region_handle >> 32));
*y_pos = (F32)((U32)(region_handle & 0xFFFFFFFF));
}
// stuff the word-frame XY location of sim's SouthWest corner in x_pos, y_pos
inline void from_region_handle(const U64 &region_handle, U32 *x_pos, U32 *y_pos)
{
*x_pos = ((U32)(region_handle >> 32));
*y_pos = ((U32)(region_handle & 0xFFFFFFFF));
}
// return the word-frame XY location of sim's SouthWest corner in LLVector3d
inline LLVector3d from_region_handle(const U64 &region_handle)
{
return LLVector3d(((U32)(region_handle >> 32)), (U32)(region_handle & 0xFFFFFFFF), 0.f);
}
// grid-based region handle encoding. pass in a grid position
// (eg: 1000,1000) and this will return the region handle.
inline U64 grid_to_region_handle(const U32 grid_x, const U32 grid_y)
{
return to_region_handle(grid_x * REGION_WIDTH_UNITS,
grid_y * REGION_WIDTH_UNITS);
}
inline void grid_from_region_handle(const U64& region_handle, U32* grid_x, U32* grid_y)
{
from_region_handle(region_handle, grid_x, grid_y);
*grid_x /= REGION_WIDTH_UNITS;
*grid_y /= REGION_WIDTH_UNITS;
}
#endif
+277
View File
@@ -0,0 +1,277 @@
/**
* @file llsdappservices.cpp
* @author Phoenix
* @date 2006-09-12
*
* $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
* 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 "llsdappservices.h"
#include "llapp.h"
#include "llhttpnode.h"
#include "llsdserialize.h"
void LLSDAppServices::useServices()
{
/*
Having this function body here, causes the classes and globals in this
file to be linked into any program that uses the llmessage library.
*/
}
class LLHTTPConfigService : public LLHTTPNode
{
public:
virtual void describe(Description& desc) const
{
desc.shortInfo("GET an array of all the options in priority order.");
desc.getAPI();
desc.source(__FILE__, __LINE__);
}
virtual LLSD simpleGet() const
{
LLSD result;
LLApp* app = LLApp::instance();
for(int ii = 0; ii < LLApp::PRIORITY_COUNT; ++ii)
{
result.append(app->getOptionData((LLApp::OptionPriority)ii));
}
return result;
}
};
LLHTTPRegistration<LLHTTPConfigService>
gHTTPRegistratiAppConfig("/app/config");
class LLHTTPConfigRuntimeService : public LLHTTPNode
{
public:
virtual void describe(Description& desc) const
{
desc.shortInfo("Manipulate a map of runtime-override options.");
desc.getAPI();
desc.postAPI();
desc.source(__FILE__, __LINE__);
}
virtual LLSD simpleGet() const
{
return LLApp::instance()->getOptionData(
LLApp::PRIORITY_RUNTIME_OVERRIDE);
}
virtual void post(
LLHTTPNode::ResponsePtr response,
const LLSD& context,
const LLSD& input) const
{
LLSD result = LLApp::instance()->getOptionData(
LLApp::PRIORITY_RUNTIME_OVERRIDE);
LLSD::map_const_iterator iter = input.beginMap();
LLSD::map_const_iterator end = input.endMap();
for(; iter != end; ++iter)
{
result[(*iter).first] = (*iter).second;
}
LLApp::instance()->setOptionData(
LLApp::PRIORITY_RUNTIME_OVERRIDE,
result);
response->result(result);
}
};
LLHTTPRegistration<LLHTTPConfigRuntimeService>
gHTTPRegistrationRuntimeConfig("/app/config/runtime-override");
class LLHTTPConfigRuntimeSingleService : public LLHTTPNode
{
public:
virtual void describe(Description& desc) const
{
desc.shortInfo("Manipulate a single runtime-override option.");
desc.getAPI();
desc.putAPI();
desc.delAPI();
desc.source(__FILE__, __LINE__);
}
virtual bool validate(const std::string& name, LLSD& context) const
{
//LL_INFOS() << "validate: " << name << ", "
// << LLSDOStreamer<LLSDNotationFormatter>(context) << LL_ENDL;
if((std::string("PUT") == context[CONTEXT_REQUEST][CONTEXT_VERB].asString()) && !name.empty())
{
return true;
}
else
{
// This is for GET and DELETE
LLSD options = LLApp::instance()->getOptionData(
LLApp::PRIORITY_RUNTIME_OVERRIDE);
if(options.has(name)) return true;
else return false;
}
}
virtual void get(
LLHTTPNode::ResponsePtr response,
const LLSD& context) const
{
std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["option-name"];
LLSD options = LLApp::instance()->getOptionData(
LLApp::PRIORITY_RUNTIME_OVERRIDE);
response->result(options[name]);
}
virtual void put(
LLHTTPNode::ResponsePtr response,
const LLSD& context,
const LLSD& input) const
{
std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["option-name"];
LLSD options = LLApp::instance()->getOptionData(
LLApp::PRIORITY_RUNTIME_OVERRIDE);
options[name] = input;
LLApp::instance()->setOptionData(
LLApp::PRIORITY_RUNTIME_OVERRIDE,
options);
response->result(input);
}
virtual void del(
LLHTTPNode::ResponsePtr response,
const LLSD& context) const
{
std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["option-name"];
LLSD options = LLApp::instance()->getOptionData(
LLApp::PRIORITY_RUNTIME_OVERRIDE);
options.erase(name);
LLApp::instance()->setOptionData(
LLApp::PRIORITY_RUNTIME_OVERRIDE,
options);
response->result(LLSD());
}
};
LLHTTPRegistration<LLHTTPConfigRuntimeSingleService>
gHTTPRegistrationRuntimeSingleConfig(
"/app/config/runtime-override/<option-name>");
template<int PRIORITY>
class LLHTTPConfigPriorityService : public LLHTTPNode
{
public:
virtual void describe(Description& desc) const
{
desc.shortInfo("Get a map of the options at this priority.");
desc.getAPI();
desc.source(__FILE__, __LINE__);
}
virtual void get(
LLHTTPNode::ResponsePtr response,
const LLSD& context) const
{
response->result(LLApp::instance()->getOptionData(
(LLApp::OptionPriority)PRIORITY));
}
};
LLHTTPRegistration< LLHTTPConfigPriorityService<LLApp::PRIORITY_COMMAND_LINE> >
gHTTPRegistrationCommandLineConfig("/app/config/command-line");
LLHTTPRegistration<
LLHTTPConfigPriorityService<LLApp::PRIORITY_SPECIFIC_CONFIGURATION> >
gHTTPRegistrationSpecificConfig("/app/config/specific");
LLHTTPRegistration<
LLHTTPConfigPriorityService<LLApp::PRIORITY_GENERAL_CONFIGURATION> >
gHTTPRegistrationGeneralConfig("/app/config/general");
LLHTTPRegistration< LLHTTPConfigPriorityService<LLApp::PRIORITY_DEFAULT> >
gHTTPRegistrationDefaultConfig("/app/config/default");
class LLHTTPLiveConfigService : public LLHTTPNode
{
public:
virtual void describe(Description& desc) const
{
desc.shortInfo("Get a map of the currently live options.");
desc.getAPI();
desc.source(__FILE__, __LINE__);
}
virtual void get(
LLHTTPNode::ResponsePtr response,
const LLSD& context) const
{
LLSD result;
LLApp* app = LLApp::instance();
LLSD::map_const_iterator iter;
LLSD::map_const_iterator end;
for(int ii = LLApp::PRIORITY_COUNT - 1; ii >= 0; --ii)
{
LLSD options = app->getOptionData((LLApp::OptionPriority)ii);
iter = options.beginMap();
end = options.endMap();
for(; iter != end; ++iter)
{
result[(*iter).first] = (*iter).second;
}
}
response->result(result);
}
};
LLHTTPRegistration<LLHTTPLiveConfigService>
gHTTPRegistrationLiveConfig("/app/config/live");
class LLHTTPLiveConfigSingleService : public LLHTTPNode
{
public:
virtual void describe(Description& desc) const
{
desc.shortInfo("Get the named live option.");
desc.getAPI();
desc.source(__FILE__, __LINE__);
}
virtual bool validate(const std::string& name, LLSD& context) const
{
LL_INFOS() << "LLHTTPLiveConfigSingleService::validate(" << name
<< ")" << LL_ENDL;
LLSD option = LLApp::instance()->getOption(name);
if(option.isDefined()) return true;
else return false;
}
virtual void get(
LLHTTPNode::ResponsePtr response,
const LLSD& context) const
{
std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["option-name"];
response->result(LLApp::instance()->getOption(name));
}
};
LLHTTPRegistration<LLHTTPLiveConfigSingleService>
gHTTPRegistrationLiveSingleConfig("/app/config/live/<option-name>");
+58
View File
@@ -0,0 +1,58 @@
/**
* @file llsdappservices.h
* @author Phoenix
* @date 2006-09-12
* @brief Header file to declare the /app common web services.
*
* $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
* 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_LLSDAPPSERVICES_H
#define LL_LLSDAPPSERVICES_H
/**
* @class LLSDAppServices
* @brief This class forces a link to llsdappservices if the static
* method is called which declares the /app web services.
*/
class LLSDAppServices
{
public:
/**
* @brief Call this method to declare the /app common web services.
*
* This will register:
* /app/config
* /app/config/runtime-override
* /app/config/runtime-override/<option-name>
* /app/config/command-line
* /app/config/specific
* /app/config/general
* /app/config/default
* /app/config/live
* /app/config/live/<option-name>
*/
static void useServices();
};
#endif // LL_LLSDAPPSERVICES_H
+150
View File
@@ -0,0 +1,150 @@
/**
* @file llsdhttpserver.cpp
* @brief Standard LLSD services
*
* $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
* 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 "llsdhttpserver.h"
#include "llhttpnode.h"
/**
* This module implements common services that should be included
* in all server URL trees. These services facilitate debugging and
* introsepction.
*/
void LLHTTPStandardServices::useServices()
{
/*
Having this function body here, causes the classes and globals in this
file to be linked into any program that uses the llmessage library.
*/
}
class LLHTTPHelloService : public LLHTTPNode
{
public:
virtual void describe(Description& desc) const
{
desc.shortInfo("says hello");
desc.getAPI();
desc.output("\"hello\"");
desc.source(__FILE__, __LINE__);
}
virtual LLSD simpleGet() const
{
LLSD result = "hello";
return result;
}
};
LLHTTPRegistration<LLHTTPHelloService>
gHTTPRegistrationWebHello("/web/hello");
class LLHTTPEchoService : public LLHTTPNode
{
public:
virtual void describe(Description& desc) const
{
desc.shortInfo("echo input");
desc.postAPI();
desc.input("<any>");
desc.output("<the input>");
desc.source(__FILE__, __LINE__);
}
virtual LLSD simplePost(const LLSD& params) const
{
return params;
}
};
LLHTTPRegistration<LLHTTPEchoService>
gHTTPRegistrationWebEcho("/web/echo");
class LLAPIService : public LLHTTPNode
{
public:
virtual void describe(Description& desc) const
{
desc.shortInfo("information about the URLs this server supports");
desc.getAPI();
desc.output("a list of URLs supported");
desc.source(__FILE__, __LINE__);
}
virtual bool handles(const LLSD& remainder, LLSD& context) const
{
return followRemainder(remainder) != NULL;
}
virtual void get(ResponsePtr response, const LLSD& context) const
{
const LLSD& remainder = context[CONTEXT_REQUEST]["remainder"];
if (remainder.size() > 0)
{
const LLHTTPNode* node = followRemainder(remainder);
if (!node)
{
response->notFound();
return;
}
Description desc;
node->describe(desc);
response->result(desc.getInfo());
return;
}
response->result(rootNode()->allNodePaths());
}
private:
const LLHTTPNode* followRemainder(const LLSD& remainder) const
{
const LLHTTPNode* node = rootNode();
LLSD::array_const_iterator i = remainder.beginArray();
LLSD::array_const_iterator end = remainder.endArray();
for (; node && i != end; ++i)
{
node = node->findNode(*i);
}
return node;
}
};
LLHTTPRegistration<LLAPIService>
gHTTPRegistrationWebServerApi("/web/server/api");
+51
View File
@@ -0,0 +1,51 @@
/**
* @file llsdhttpserver.h
* @brief Standard LLSD services
*
* $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
* 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_LLSDHTTPSERVER_H
#define LL_LLSDHTTPSERVER_H
/**
* This module implements and defines common services that should be included
* in all server URL trees. These services facilitate debugging and
* introsepction.
*/
class LLHTTPStandardServices
{
public:
static void useServices();
/**<
Having a call to this function causes the following services to be
registered:
/web/echo -- echo input
/web/hello -- return "hello"
/web/server/api -- return a list of url paths on the server
/web/server/api/<..path..>
-- return description of the path
*/
};
#endif // LL_LLSDHTTPSERVER_H

Some files were not shown because too many files have changed in this diff Show More