diff options
Diffstat (limited to 'indra/llmessage')
24 files changed, 1348 insertions, 1402 deletions
diff --git a/indra/llmessage/llassetstorage.cpp b/indra/llmessage/llassetstorage.cpp index bcf4e52b8f..596d57c7b7 100644 --- a/indra/llmessage/llassetstorage.cpp +++ b/indra/llmessage/llassetstorage.cpp @@ -60,64 +60,60 @@ static LLTrace::CountStatHandle<> sFailedDownloadCount("faileddownloads", "Numbe const LLUUID CATEGORIZE_LOST_AND_FOUND_ID(std::string("00000000-0000-0000-0000-000000000010")); -const U64 TOXIC_ASSET_LIFETIME = (120 * 1000000); // microseconds - -LLTempAssetStorage::~LLTempAssetStorage() -{ -} +const U64 TOXIC_ASSET_LIFETIME = (120 * 1000000); // microseconds ///---------------------------------------------------------------------------- /// LLAssetInfo ///---------------------------------------------------------------------------- LLAssetInfo::LLAssetInfo( void ) -: mDescription(), - mName(), - mUuid(), - mCreatorID(), - mType( LLAssetType::AT_NONE ) + : mDescription(), + mName(), + mUuid(), + mCreatorID(), + mType( LLAssetType::AT_NONE ) { } LLAssetInfo::LLAssetInfo( const LLUUID& object_id, const LLUUID& creator_id, - LLAssetType::EType type, const char* name, - const char* desc ) -: mUuid( object_id ), - mCreatorID( creator_id ), - mType( type ) + LLAssetType::EType type, const char* name, + const char* desc ) + : mUuid( object_id ), + mCreatorID( creator_id ), + mType( type ) { - setName( name ); - setDescription( desc ); + setName( name ); + setDescription( desc ); } LLAssetInfo::LLAssetInfo( const LLNameValue& nv ) { - setFromNameValue( nv ); + setFromNameValue( nv ); } // make sure the name is short enough, and strip all pipes since they // are reserved characters in our inventory tracking system. void LLAssetInfo::setName( const std::string& name ) { - if( !name.empty() ) - { - mName.assign( name, 0, llmin((U32)name.size(), (U32)DB_INV_ITEM_NAME_STR_LEN) ); - mName.erase( std::remove(mName.begin(), mName.end(), '|'), - mName.end() ); - } + if( !name.empty() ) + { + mName.assign( name, 0, llmin((U32)name.size(), (U32)DB_INV_ITEM_NAME_STR_LEN) ); + mName.erase( std::remove(mName.begin(), mName.end(), '|'), + mName.end() ); + } } // make sure the name is short enough, and strip all pipes since they // are reserved characters in our inventory tracking system. void LLAssetInfo::setDescription( const std::string& desc ) { - if( !desc.empty() ) - { - mDescription.assign( desc, 0, llmin((U32)desc.size(), - (U32)DB_INV_ITEM_DESC_STR_LEN) ); - mDescription.erase( std::remove(mDescription.begin(), - mDescription.end(), '|'), - mDescription.end() ); - } + if( !desc.empty() ) + { + mDescription.assign( desc, 0, llmin((U32)desc.size(), + (U32)DB_INV_ITEM_DESC_STR_LEN) ); + mDescription.erase( std::remove(mDescription.begin(), + mDescription.end(), '|'), + mDescription.end() ); + } } // Assets (aka potential inventory items) can be applied to an @@ -130,31 +126,31 @@ void LLAssetInfo::setDescription( const std::string& desc ) // value=<creatorid>|<name>|<description>| void LLAssetInfo::setFromNameValue( const LLNameValue& nv ) { - std::string str; - std::string buf; - std::string::size_type pos1; - std::string::size_type pos2; - - // convert the name to useful information - str.assign( nv.mName ); - pos1 = str.find('|'); - buf.assign( str, 0, pos1++ ); - mType = LLAssetType::lookup( buf ); - buf.assign( str, pos1, std::string::npos ); - mUuid.set( buf ); - - // convert the value to useful information - str.assign( nv.getAsset() ); - pos1 = str.find('|'); - buf.assign( str, 0, pos1++ ); - mCreatorID.set( buf ); - pos2 = str.find( '|', pos1 ); - buf.assign( str, pos1, (pos2++) - pos1 ); - setName( buf ); - buf.assign( str, pos2, std::string::npos ); - setDescription( buf ); - LL_DEBUGS("AssetStorage") << "uuid: " << mUuid << LL_ENDL; - LL_DEBUGS("AssetStorage") << "creator: " << mCreatorID << LL_ENDL; + std::string str; + std::string buf; + std::string::size_type pos1; + std::string::size_type pos2; + + // convert the name to useful information + str.assign( nv.mName ); + pos1 = str.find('|'); + buf.assign( str, 0, pos1++ ); + mType = LLAssetType::lookup( buf ); + buf.assign( str, pos1, std::string::npos ); + mUuid.set( buf ); + + // convert the value to useful information + str.assign( nv.getAsset() ); + pos1 = str.find('|'); + buf.assign( str, 0, pos1++ ); + mCreatorID.set( buf ); + pos2 = str.find( '|', pos1 ); + buf.assign( str, pos1, (pos2++) - pos1 ); + setName( buf ); + buf.assign( str, pos2, std::string::npos ); + setDescription( buf ); + LL_DEBUGS("AssetStorage") << "uuid: " << mUuid << LL_ENDL; + LL_DEBUGS("AssetStorage") << "creator: " << mCreatorID << LL_ENDL; } ///---------------------------------------------------------------------------- @@ -162,15 +158,15 @@ void LLAssetInfo::setFromNameValue( const LLNameValue& nv ) ///---------------------------------------------------------------------------- LLBaseDownloadRequest::LLBaseDownloadRequest(const LLUUID &uuid, const LLAssetType::EType type) -: mUUID(uuid), -mType(type), -mDownCallback(NULL), -mUserData(NULL), -mHost(), -mIsTemp(FALSE), -mIsPriority(FALSE), -mDataSentInFirstPacket(FALSE), -mDataIsInVFS(FALSE) + : mUUID(uuid), + mType(type), + mDownCallback(NULL), + mUserData(NULL), + mHost(), + mIsTemp(FALSE), + mIsPriority(FALSE), + mDataSentInFirstPacket(FALSE), + mDataIsInVFS(FALSE) { // Need to guarantee that this time is up to date, we may be creating a circuit even though we haven't been // running a message system loop. @@ -194,12 +190,13 @@ LLBaseDownloadRequest* LLBaseDownloadRequest::getCopy() ///---------------------------------------------------------------------------- LLAssetRequest::LLAssetRequest(const LLUUID &uuid, const LLAssetType::EType type) -: LLBaseDownloadRequest(uuid, type), - mUpCallback( NULL ), - mInfoCallback( NULL ), - mIsLocal(FALSE), - mIsUserWaiting(FALSE), - mTimeout(LL_ASSET_STORAGE_TIMEOUT) + : LLBaseDownloadRequest(uuid, type), + mUpCallback( NULL ), + mInfoCallback( NULL ), + mIsLocal(FALSE), + mIsUserWaiting(FALSE), + mTimeout(LL_ASSET_STORAGE_TIMEOUT), + mBytesFetched(0) { } @@ -211,31 +208,31 @@ LLAssetRequest::~LLAssetRequest() // virtual LLSD LLAssetRequest::getTerseDetails() const { - LLSD sd; - sd["asset_id"] = getUUID(); - sd["type_long"] = LLAssetType::lookupHumanReadable(getType()); - sd["type"] = LLAssetType::lookup(getType()); - sd["time"] = mTime.value(); - time_t timestamp = (time_t) mTime.value(); - std::ostringstream time_string; - time_string << ctime(×tamp); - sd["time_string"] = time_string.str(); - return sd; + LLSD sd; + sd["asset_id"] = getUUID(); + sd["type_long"] = LLAssetType::lookupHumanReadable(getType()); + sd["type"] = LLAssetType::lookup(getType()); + sd["time"] = mTime.value(); + time_t timestamp = (time_t) mTime.value(); + std::ostringstream time_string; + time_string << ctime(×tamp); + sd["time_string"] = time_string.str(); + return sd; } // virtual LLSD LLAssetRequest::getFullDetails() const { - LLSD sd = getTerseDetails(); - sd["host"] = mHost.getIPandPort(); - sd["requesting_agent"] = mRequestingAgentID; - sd["is_temp"] = mIsTemp; - sd["is_local"] = mIsLocal; - sd["is_priority"] = mIsPriority; - sd["data_send_in_first_packet"] = mDataSentInFirstPacket; - sd["data_is_in_vfs"] = mDataIsInVFS; - - return sd; + LLSD sd = getTerseDetails(); + sd["host"] = mHost.getIPandPort(); + sd["requesting_agent"] = mRequestingAgentID; + sd["is_temp"] = mIsTemp; + sd["is_local"] = mIsLocal; + sd["is_priority"] = mIsPriority; + sd["data_send_in_first_packet"] = mDataSentInFirstPacket; + sd["data_is_in_vfs"] = mDataIsInVFS; + + return sd; } LLBaseDownloadRequest* LLAssetRequest::getCopy() @@ -248,7 +245,7 @@ LLBaseDownloadRequest* LLAssetRequest::getCopy() ///---------------------------------------------------------------------------- LLInvItemRequest::LLInvItemRequest(const LLUUID &uuid, const LLAssetType::EType type) -: LLBaseDownloadRequest(uuid, type) + : LLBaseDownloadRequest(uuid, type) { } @@ -267,9 +264,9 @@ LLBaseDownloadRequest* LLInvItemRequest::getCopy() ///---------------------------------------------------------------------------- LLEstateAssetRequest::LLEstateAssetRequest(const LLUUID &uuid, const LLAssetType::EType atype, - EstateAssetType etype) -: LLBaseDownloadRequest(uuid, atype), - mEstateAssetType(etype) + EstateAssetType etype) + : LLBaseDownloadRequest(uuid, atype), + mEstateAssetType(etype) { } @@ -299,152 +296,150 @@ LLBaseDownloadRequest* LLEstateAssetRequest::getCopy() LLAssetStorage::LLAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, LLVFS *vfs, LLVFS *static_vfs, const LLHost &upstream_host) { - _init(msg, xfer, vfs, static_vfs, upstream_host); + _init(msg, xfer, vfs, static_vfs, upstream_host); } - LLAssetStorage::LLAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, - LLVFS *vfs, LLVFS *static_vfs) + LLVFS *vfs, LLVFS *static_vfs) { - _init(msg, xfer, vfs, static_vfs, LLHost()); + _init(msg, xfer, vfs, static_vfs, LLHost()); } - void LLAssetStorage::_init(LLMessageSystem *msg, - LLXferManager *xfer, - LLVFS *vfs, - LLVFS *static_vfs, - const LLHost &upstream_host) + LLXferManager *xfer, + LLVFS *vfs, + LLVFS *static_vfs, + const LLHost &upstream_host) { - mShutDown = FALSE; - mMessageSys = msg; - mXferManager = xfer; - mVFS = vfs; - mStaticVFS = static_vfs; - - setUpstream(upstream_host); - msg->setHandlerFuncFast(_PREHASH_AssetUploadComplete, processUploadComplete, (void **)this); + mShutDown = FALSE; + mMessageSys = msg; + mXferManager = xfer; + mVFS = vfs; + mStaticVFS = static_vfs; + + setUpstream(upstream_host); + msg->setHandlerFuncFast(_PREHASH_AssetUploadComplete, processUploadComplete, (void **)this); } LLAssetStorage::~LLAssetStorage() { - mShutDown = TRUE; - - _cleanupRequests(TRUE, LL_ERR_CIRCUIT_GONE); - - if (gMessageSystem) - { - // Warning! This won't work if there's more than one asset storage. - // unregister our callbacks with the message system - gMessageSystem->setHandlerFuncFast(_PREHASH_AssetUploadComplete, NULL, NULL); - } - - // Clear the toxic asset map - mToxicAssetMap.clear(); + mShutDown = TRUE; + + _cleanupRequests(TRUE, LL_ERR_CIRCUIT_GONE); + + if (gMessageSystem) + { + // Warning! This won't work if there's more than one asset storage. + // unregister our callbacks with the message system + gMessageSystem->setHandlerFuncFast(_PREHASH_AssetUploadComplete, NULL, NULL); + } + + // Clear the toxic asset map + mToxicAssetMap.clear(); } void LLAssetStorage::setUpstream(const LLHost &upstream_host) { - LL_DEBUGS("AppInit") << "AssetStorage: Setting upstream provider to " << upstream_host << LL_ENDL; - - mUpstreamHost = upstream_host; + LL_DEBUGS("AppInit") << "AssetStorage: Setting upstream provider to " << upstream_host << LL_ENDL; + + mUpstreamHost = upstream_host; } void LLAssetStorage::checkForTimeouts() { - _cleanupRequests(FALSE, LL_ERR_TCP_TIMEOUT); + _cleanupRequests(FALSE, LL_ERR_TCP_TIMEOUT); } void LLAssetStorage::_cleanupRequests(BOOL all, S32 error) { - F64Seconds mt_secs = LLMessageSystem::getMessageTimeSeconds(); - - request_list_t timed_out; - S32 rt; - for (rt = 0; rt < RT_COUNT; rt++) - { - request_list_t* requests = getRequestList((ERequestType)rt); - for (request_list_t::iterator iter = requests->begin(); - iter != requests->end(); ) - { - request_list_t::iterator curiter = iter++; - LLAssetRequest* tmp = *curiter; - // if all is true, we want to clean up everything - // otherwise just check for timed out requests - // EXCEPT for upload timeouts - if (all - || ((RT_DOWNLOAD == rt) - && LL_ASSET_STORAGE_TIMEOUT < (mt_secs - tmp->mTime))) - { - LL_WARNS() << "Asset " << getRequestName((ERequestType)rt) << " request " - << (all ? "aborted" : "timed out") << " for " - << tmp->getUUID() << "." - << LLAssetType::lookup(tmp->getType()) << LL_ENDL; - - timed_out.push_front(tmp); - iter = requests->erase(curiter); - } - } - } - - LLAssetInfo info; - for (request_list_t::iterator iter = timed_out.begin(); - iter != timed_out.end(); ) - { - request_list_t::iterator curiter = iter++; - LLAssetRequest* tmp = *curiter; - if (tmp->mUpCallback) - { - tmp->mUpCallback(tmp->getUUID(), tmp->mUserData, error, LL_EXSTAT_NONE); - } - if (tmp->mDownCallback) - { - tmp->mDownCallback(mVFS, tmp->getUUID(), tmp->getType(), tmp->mUserData, error, LL_EXSTAT_NONE); - } - if (tmp->mInfoCallback) - { - tmp->mInfoCallback(&info, tmp->mUserData, error); - } - delete tmp; - } + F64Seconds mt_secs = LLMessageSystem::getMessageTimeSeconds(); + + request_list_t timed_out; + S32 rt; + for (rt = 0; rt < RT_COUNT; rt++) + { + request_list_t* requests = getRequestList((ERequestType)rt); + for (request_list_t::iterator iter = requests->begin(); + iter != requests->end(); ) + { + request_list_t::iterator curiter = iter++; + LLAssetRequest* tmp = *curiter; + // if all is true, we want to clean up everything + // otherwise just check for timed out requests + // EXCEPT for upload timeouts + if (all + || ((RT_DOWNLOAD == rt) + && LL_ASSET_STORAGE_TIMEOUT < (mt_secs - tmp->mTime))) + { + LL_WARNS("AssetStorage") << "Asset " << getRequestName((ERequestType)rt) << " request " + << (all ? "aborted" : "timed out") << " for " + << tmp->getUUID() << "." + << LLAssetType::lookup(tmp->getType()) << LL_ENDL; + + timed_out.push_front(tmp); + iter = requests->erase(curiter); + } + } + } + + LLAssetInfo info; + for (request_list_t::iterator iter = timed_out.begin(); + iter != timed_out.end(); ) + { + request_list_t::iterator curiter = iter++; + LLAssetRequest* tmp = *curiter; + if (tmp->mUpCallback) + { + tmp->mUpCallback(tmp->getUUID(), tmp->mUserData, error, LL_EXSTAT_NONE); + } + if (tmp->mDownCallback) + { + tmp->mDownCallback(mVFS, tmp->getUUID(), tmp->getType(), tmp->mUserData, error, LL_EXSTAT_NONE); + } + if (tmp->mInfoCallback) + { + tmp->mInfoCallback(&info, tmp->mUserData, error); + } + delete tmp; + } } BOOL LLAssetStorage::hasLocalAsset(const LLUUID &uuid, const LLAssetType::EType type) { - return mStaticVFS->getExists(uuid, type) || mVFS->getExists(uuid, type); + return mStaticVFS->getExists(uuid, type) || mVFS->getExists(uuid, type); } bool LLAssetStorage::findInStaticVFSAndInvokeCallback(const LLUUID& uuid, LLAssetType::EType type, - LLGetAssetCallback callback, void *user_data) -{ - if (user_data) - { - // The *user_data should not be passed without a callback to clean it up. - llassert(callback != NULL); - } - - BOOL exists = mStaticVFS->getExists(uuid, type); - if (exists) - { - LLVFile file(mStaticVFS, uuid, type); - U32 size = file.getSize(); - if (size > 0) - { - // we've already got the file - if (callback) - { - callback(mStaticVFS, uuid, type, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED); - } - return true; - } - else - { - LL_WARNS() << "Asset vfile " << uuid << ":" << type - << " found in static cache with bad size " << file.getSize() << ", ignoring" << LL_ENDL; - } - } - return false; + LLGetAssetCallback callback, void *user_data) +{ + if (user_data) + { + // The *user_data should not be passed without a callback to clean it up. + llassert(callback != NULL); + } + + BOOL exists = mStaticVFS->getExists(uuid, type); + if (exists) + { + LLVFile file(mStaticVFS, uuid, type); + U32 size = file.getSize(); + if (size > 0) + { + // we've already got the file + if (callback) + { + callback(mStaticVFS, uuid, type, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED); + } + return true; + } + else + { + LL_WARNS("AssetStorage") << "Asset vfile " << uuid << ":" << type + << " found in static cache with bad size " << file.getSize() << ", ignoring" << LL_ENDL; + } + } + return false; } /////////////////////////////////////////////////////////////////////////// @@ -452,526 +447,506 @@ bool LLAssetStorage::findInStaticVFSAndInvokeCallback(const LLUUID& uuid, LLAsse /////////////////////////////////////////////////////////////////////////// // IW - uuid is passed by value to avoid side effects, please don't re-add & -void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, LLGetAssetCallback callback, void *user_data, BOOL is_priority) -{ - LL_DEBUGS("AssetStorage") << "LLAssetStorage::getAssetData() - " << uuid << "," << LLAssetType::lookup(type) << LL_ENDL; - - LL_DEBUGS("AssetStorage") << "ASSET_TRACE requesting " << uuid << " type " << LLAssetType::lookup(type) << LL_ENDL; - - if (user_data) - { - // The *user_data should not be passed without a callback to clean it up. - llassert(callback != NULL); - } - - if (mShutDown) - { - LL_DEBUGS("AssetStorage") << "ASSET_TRACE cancelled " << uuid << " type " << LLAssetType::lookup(type) << " shutting down" << LL_ENDL; - - if (callback) - { - add(sFailedDownloadCount, 1); - callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_FAILED, LL_EXSTAT_NONE); - } - return; - } - - if (uuid.isNull()) - { - // Special case early out for NULL uuid and for shutting down - if (callback) - { - add(sFailedDownloadCount, 1); - callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LL_EXSTAT_NULL_UUID); - } - return; - } - - // Try static VFS first. - if (findInStaticVFSAndInvokeCallback(uuid,type,callback,user_data)) - { - LL_DEBUGS("AssetStorage") << "ASSET_TRACE asset " << uuid << " found in static VFS" << LL_ENDL; - return; - } - - BOOL exists = mVFS->getExists(uuid, type); - LLVFile file(mVFS, uuid, type); - U32 size = exists ? file.getSize() : 0; - - if (size > 0) - { - // we've already got the file - // theoretically, partial files w/o a pending request shouldn't happen - // unless there's a weird error - if (callback) - { - callback(mVFS, uuid, type, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED); - } - - LL_DEBUGS("AssetStorage") << "ASSET_TRACE asset " << uuid << " found in VFS" << LL_ENDL; - } - else - { - if (exists) - { - LL_WARNS() << "Asset vfile " << uuid << ":" << type << " found with bad size " << file.getSize() << ", removing" << LL_ENDL; - file.remove(); - } - - BOOL duplicate = FALSE; - - // check to see if there's a pending download of this uuid already - for (request_list_t::iterator iter = mPendingDownloads.begin(); - iter != mPendingDownloads.end(); ++iter ) - { - LLAssetRequest *tmp = *iter; - if ((type == tmp->getType()) && (uuid == tmp->getUUID())) - { - if (callback == tmp->mDownCallback && user_data == tmp->mUserData) - { - // this is a duplicate from the same subsystem - throw it away - LL_WARNS() << "Discarding duplicate request for asset " << uuid - << "." << LLAssetType::lookup(type) << LL_ENDL; - return; - } - - // this is a duplicate request - // queue the request, but don't actually ask for it again - duplicate = TRUE; - } - } - if (duplicate) - { - LL_DEBUGS("AssetStorage") << "Adding additional non-duplicate request for asset " << uuid - << "." << LLAssetType::lookup(type) << LL_ENDL; - } - - // This can be overridden by subclasses - _queueDataRequest(uuid, type, callback, user_data, duplicate, is_priority); - } - +void LLAssetStorage::getAssetData(const LLUUID uuid, + LLAssetType::EType type, + LLGetAssetCallback callback, + void *user_data, + BOOL is_priority) +{ + LL_DEBUGS("AssetStorage") << "LLAssetStorage::getAssetData() - " << uuid << "," << LLAssetType::lookup(type) << LL_ENDL; + + LL_DEBUGS("AssetStorage") << "ASSET_TRACE requesting " << uuid << " type " << LLAssetType::lookup(type) << LL_ENDL; + + if (user_data) + { + // The *user_data should not be passed without a callback to clean it up. + llassert(callback != NULL); + } + + if (mShutDown) + { + LL_DEBUGS("AssetStorage") << "ASSET_TRACE cancelled " << uuid << " type " << LLAssetType::lookup(type) << " shutting down" << LL_ENDL; + + if (callback) + { + add(sFailedDownloadCount, 1); + callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_FAILED, LL_EXSTAT_NONE); + } + return; + } + + if (uuid.isNull()) + { + // Special case early out for NULL uuid and for shutting down + if (callback) + { + add(sFailedDownloadCount, 1); + callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LL_EXSTAT_NULL_UUID); + } + return; + } + + // Try static VFS first. + if (findInStaticVFSAndInvokeCallback(uuid,type,callback,user_data)) + { + LL_DEBUGS("AssetStorage") << "ASSET_TRACE asset " << uuid << " found in static VFS" << LL_ENDL; + return; + } + + BOOL exists = mVFS->getExists(uuid, type); + LLVFile file(mVFS, uuid, type); + U32 size = exists ? file.getSize() : 0; + + if (size > 0) + { + // we've already got the file + // theoretically, partial files w/o a pending request shouldn't happen + // unless there's a weird error + if (callback) + { + callback(mVFS, uuid, type, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED); + } + + LL_DEBUGS("AssetStorage") << "ASSET_TRACE asset " << uuid << " found in VFS" << LL_ENDL; + } + else + { + if (exists) + { + LL_WARNS("AssetStorage") << "Asset vfile " << uuid << ":" << type << " found with bad size " << file.getSize() << ", removing" << LL_ENDL; + file.remove(); + } + + BOOL duplicate = FALSE; + + // check to see if there's a pending download of this uuid already + for (request_list_t::iterator iter = mPendingDownloads.begin(); + iter != mPendingDownloads.end(); ++iter ) + { + LLAssetRequest *tmp = *iter; + if ((type == tmp->getType()) && (uuid == tmp->getUUID())) + { + if (callback == tmp->mDownCallback && user_data == tmp->mUserData) + { + // this is a duplicate from the same subsystem - throw it away + LL_WARNS("AssetStorage") << "Discarding duplicate request for asset " << uuid + << "." << LLAssetType::lookup(type) << LL_ENDL; + return; + } + + // this is a duplicate request + // queue the request, but don't actually ask for it again + duplicate = TRUE; + } + } + if (duplicate) + { + LL_DEBUGS("AssetStorage") << "Adding additional non-duplicate request for asset " << uuid + << "." << LLAssetType::lookup(type) << LL_ENDL; + } + + _queueDataRequest(uuid, type, callback, user_data, duplicate, is_priority); + } } -// -// *NOTE: Logic here is replicated in LLViewerAssetStorage::_queueDataRequest. -// Changes here may need to be replicated in the viewer's derived class. -// -void LLAssetStorage::_queueDataRequest(const LLUUID& uuid, LLAssetType::EType atype, - LLGetAssetCallback callback, - void *user_data, BOOL duplicate, - BOOL is_priority) -{ - if (mUpstreamHost.isOk()) - { - // stash the callback info so we can find it after we get the response message - LLAssetRequest *req = new LLAssetRequest(uuid, atype); - req->mDownCallback = callback; - req->mUserData = user_data; - req->mIsPriority = is_priority; - - mPendingDownloads.push_back(req); - - if (!duplicate) - { - // send request message to our upstream data provider - // Create a new asset transfer. - LLTransferSourceParamsAsset spa; - spa.setAsset(uuid, atype); - - // Set our destination file, and the completion callback. - LLTransferTargetParamsVFile tpvf; - tpvf.setAsset(uuid, atype); - tpvf.setCallback(downloadCompleteCallback, *req); - - //LL_INFOS() << "Starting transfer for " << uuid << LL_ENDL; - LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(mUpstreamHost, LLTCT_ASSET); - ttcp->requestTransfer(spa, tpvf, 100.f + (is_priority ? 1.f : 0.f)); - } - } - else - { - // uh-oh, we shouldn't have gotten here - LL_WARNS() << "Attempt to move asset data request upstream w/o valid upstream provider" << LL_ENDL; - if (callback) - { - add(sFailedDownloadCount, 1); - callback(mVFS, uuid, atype, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM); - } - } +// static +void LLAssetStorage::removeAndCallbackPendingDownloads(const LLUUID& file_id, LLAssetType::EType file_type, + const LLUUID& callback_id, LLAssetType::EType callback_type, + S32 result_code, LLExtStat ext_status) +{ + // find and callback ALL pending requests for this UUID + // SJB: We process the callbacks in reverse order, I do not know if this is important, + // but I didn't want to mess with it. + request_list_t requests; + for (request_list_t::iterator iter = gAssetStorage->mPendingDownloads.begin(); + iter != gAssetStorage->mPendingDownloads.end(); ) + { + request_list_t::iterator curiter = iter++; + LLAssetRequest* tmp = *curiter; + if ((tmp->getUUID() == file_id) && (tmp->getType()== file_type)) + { + requests.push_front(tmp); + iter = gAssetStorage->mPendingDownloads.erase(curiter); + } + } + for (request_list_t::iterator iter = requests.begin(); + iter != requests.end(); ) + { + request_list_t::iterator curiter = iter++; + LLAssetRequest* tmp = *curiter; + if (tmp->mDownCallback) + { + if (result_code!= LL_ERR_NOERR) + { + add(sFailedDownloadCount, 1); + } + tmp->mDownCallback(gAssetStorage->mVFS, callback_id, callback_type, tmp->mUserData, result_code, ext_status); + } + delete tmp; + } } - void LLAssetStorage::downloadCompleteCallback( - S32 result, - const LLUUID& file_id, - LLAssetType::EType file_type, - LLBaseDownloadRequest* user_data, LLExtStat ext_status) -{ - LL_DEBUGS("AssetStorage") << "ASSET_TRACE asset " << file_id << " downloadCompleteCallback" << LL_ENDL; - - LL_DEBUGS("AssetStorage") << "LLAssetStorage::downloadCompleteCallback() for " << file_id - << "," << LLAssetType::lookup(file_type) << LL_ENDL; - LLAssetRequest* req = (LLAssetRequest*)user_data; - if(!req) - { - LL_WARNS() << "LLAssetStorage::downloadCompleteCallback called without" - "a valid request." << LL_ENDL; - return; - } - if (!gAssetStorage) - { - LL_WARNS() << "LLAssetStorage::downloadCompleteCallback called without any asset system, aborting!" << LL_ENDL; - return; - } - - LLUUID callback_id; - LLAssetType::EType callback_type; - - // Inefficient since we're doing a find through a list that may have thousands of elements. - // This is due for refactoring; we will probably change mPendingDownloads into a set. - request_list_t::iterator download_iter = std::find(gAssetStorage->mPendingDownloads.begin(), - gAssetStorage->mPendingDownloads.end(), - req); - - if (download_iter != gAssetStorage->mPendingDownloads.end()) - { - callback_id = file_id; - callback_type = file_type; - } - else - { - // either has already been deleted by _cleanupRequests or it's a transfer. - callback_id = req->getUUID(); - callback_type = req->getType(); - } - - if (LL_ERR_NOERR == result) - { - // we might have gotten a zero-size file - LLVFile vfile(gAssetStorage->mVFS, callback_id, callback_type); - if (vfile.getSize() <= 0) - { - LL_WARNS() << "downloadCompleteCallback has non-existent or zero-size asset " << callback_id << LL_ENDL; - - result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE; - vfile.remove(); - } - } - - // find and callback ALL pending requests for this UUID - // SJB: We process the callbacks in reverse order, I do not know if this is important, - // but I didn't want to mess with it. - request_list_t requests; - for (request_list_t::iterator iter = gAssetStorage->mPendingDownloads.begin(); - iter != gAssetStorage->mPendingDownloads.end(); ) - { - request_list_t::iterator curiter = iter++; - LLAssetRequest* tmp = *curiter; - if ((tmp->getUUID() == file_id) && (tmp->getType()== file_type)) - { - requests.push_front(tmp); - iter = gAssetStorage->mPendingDownloads.erase(curiter); - } - } - for (request_list_t::iterator iter = requests.begin(); - iter != requests.end(); ) - { - request_list_t::iterator curiter = iter++; - LLAssetRequest* tmp = *curiter; - if (tmp->mDownCallback) - { - if (result != LL_ERR_NOERR) - { - add(sFailedDownloadCount, 1); - } - tmp->mDownCallback(gAssetStorage->mVFS, callback_id, callback_type, tmp->mUserData, result, ext_status); - } - delete tmp; - } -} - -void LLAssetStorage::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) -{ - LL_DEBUGS() << "LLAssetStorage::getEstateAsset() - " << asset_id << "," << LLAssetType::lookup(atype) << ", estatetype " << etype << LL_ENDL; - - // - // Probably will get rid of this early out? - // - if (asset_id.isNull()) - { - // Special case early out for NULL uuid - if (callback) - { - add(sFailedDownloadCount, 1); - callback(mVFS, asset_id, atype, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LL_EXSTAT_NULL_UUID); - } - return; - } - - // Try static VFS first. - if (findInStaticVFSAndInvokeCallback(asset_id,atype,callback,user_data)) - { - return; - } - - BOOL exists = mVFS->getExists(asset_id, atype); - LLVFile file(mVFS, asset_id, atype); - U32 size = exists ? file.getSize() : 0; - - if (size > 0) - { - // we've already got the file - // theoretically, partial files w/o a pending request shouldn't happen - // unless there's a weird error - if (callback) - { - callback(mVFS, asset_id, atype, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED); - } - } - else - { - if (exists) - { - LL_WARNS() << "Asset vfile " << asset_id << ":" << atype << " found with bad size " << file.getSize() << ", removing" << LL_ENDL; - file.remove(); - } - - // See whether we should talk to the object's originating sim, or the upstream provider. - LLHost source_host; - if (object_sim.isOk()) - { - source_host = object_sim; - } - else - { - source_host = mUpstreamHost; - } - if (source_host.isOk()) - { - // stash the callback info so we can find it after we get the response message - LLEstateAssetRequest req(asset_id, atype, etype); - req.mDownCallback = callback; - req.mUserData = user_data; - req.mIsPriority = is_priority; - - // send request message to our upstream data provider - // Create a new asset transfer. - LLTransferSourceParamsEstate spe; - spe.setAgentSession(agent_id, session_id); - spe.setEstateAssetType(etype); - - // Set our destination file, and the completion callback. - LLTransferTargetParamsVFile tpvf; - tpvf.setAsset(asset_id, atype); - tpvf.setCallback(downloadEstateAssetCompleteCallback, req); - - LL_DEBUGS("AssetStorage") << "Starting transfer for " << asset_id << LL_ENDL; - LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(source_host, LLTCT_ASSET); - ttcp->requestTransfer(spe, tpvf, 100.f + (is_priority ? 1.f : 0.f)); - } - else - { - // uh-oh, we shouldn't have gotten here - LL_WARNS() << "Attempt to move asset data request upstream w/o valid upstream provider" << LL_ENDL; - if (callback) - { - add(sFailedDownloadCount, 1); - callback(mVFS, asset_id, atype, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM); - } - } - } + S32 result, + const LLUUID& file_id, + LLAssetType::EType file_type, + LLBaseDownloadRequest* user_data, + LLExtStat ext_status) +{ + LL_DEBUGS("AssetStorage") << "ASSET_TRACE asset " << file_id << " downloadCompleteCallback" << LL_ENDL; + + LL_DEBUGS("AssetStorage") << "LLAssetStorage::downloadCompleteCallback() for " << file_id + << "," << LLAssetType::lookup(file_type) << LL_ENDL; + LLAssetRequest* req = (LLAssetRequest*)user_data; + if(!req) + { + LL_WARNS("AssetStorage") << "LLAssetStorage::downloadCompleteCallback called without" + "a valid request." << LL_ENDL; + return; + } + if (!gAssetStorage) + { + LL_WARNS("AssetStorage") << "LLAssetStorage::downloadCompleteCallback called without any asset system, aborting!" << LL_ENDL; + return; + } + + LLUUID callback_id; + LLAssetType::EType callback_type; + + // Inefficient since we're doing a find through a list that may have thousands of elements. + // This is due for refactoring; we will probably change mPendingDownloads into a set. + request_list_t::iterator download_iter = std::find(gAssetStorage->mPendingDownloads.begin(), + gAssetStorage->mPendingDownloads.end(), + req); + + if (download_iter != gAssetStorage->mPendingDownloads.end()) + { + callback_id = file_id; + callback_type = file_type; + } + else + { + // either has already been deleted by _cleanupRequests or it's a transfer. + callback_id = req->getUUID(); + callback_type = req->getType(); + } + + if (LL_ERR_NOERR == result) + { + // we might have gotten a zero-size file + LLVFile vfile(gAssetStorage->mVFS, callback_id, callback_type); + if (vfile.getSize() <= 0) + { + LL_WARNS("AssetStorage") << "downloadCompleteCallback has non-existent or zero-size asset " << callback_id << LL_ENDL; + + result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE; + vfile.remove(); + } + else + { +#if 1 + for (request_list_t::iterator iter = gAssetStorage->mPendingDownloads.begin(); + iter != gAssetStorage->mPendingDownloads.end(); ++iter ) + { + LLAssetRequest* dlreq = *iter; + if ((dlreq->getUUID() == file_id) && (dlreq->getType()== file_type)) + { + dlreq->mBytesFetched = vfile.getSize(); + } + } +#endif + } + } + + removeAndCallbackPendingDownloads(file_id, file_type, callback_id, callback_type, ext_status, result); +} + +void LLAssetStorage::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) +{ + LL_DEBUGS() << "LLAssetStorage::getEstateAsset() - " << asset_id << "," << LLAssetType::lookup(atype) << ", estatetype " << etype << LL_ENDL; + + // + // Probably will get rid of this early out? + // + if (asset_id.isNull()) + { + // Special case early out for NULL uuid + if (callback) + { + add(sFailedDownloadCount, 1); + callback(mVFS, asset_id, atype, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LL_EXSTAT_NULL_UUID); + } + return; + } + + // Try static VFS first. + if (findInStaticVFSAndInvokeCallback(asset_id,atype,callback,user_data)) + { + return; + } + + BOOL exists = mVFS->getExists(asset_id, atype); + LLVFile file(mVFS, asset_id, atype); + U32 size = exists ? file.getSize() : 0; + + if (size > 0) + { + // we've already got the file + // theoretically, partial files w/o a pending request shouldn't happen + // unless there's a weird error + if (callback) + { + callback(mVFS, asset_id, atype, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED); + } + } + else + { + if (exists) + { + LL_WARNS("AssetStorage") << "Asset vfile " << asset_id << ":" << atype << " found with bad size " << file.getSize() << ", removing" << LL_ENDL; + file.remove(); + } + + // See whether we should talk to the object's originating sim, or the upstream provider. + LLHost source_host; + if (object_sim.isOk()) + { + source_host = object_sim; + } + else + { + source_host = mUpstreamHost; + } + if (source_host.isOk()) + { + // stash the callback info so we can find it after we get the response message + LLEstateAssetRequest req(asset_id, atype, etype); + req.mDownCallback = callback; + req.mUserData = user_data; + req.mIsPriority = is_priority; + + // send request message to our upstream data provider + // Create a new asset transfer. + LLTransferSourceParamsEstate spe; + spe.setAgentSession(agent_id, session_id); + spe.setEstateAssetType(etype); + + // Set our destination file, and the completion callback. + LLTransferTargetParamsVFile tpvf; + tpvf.setAsset(asset_id, atype); + tpvf.setCallback(downloadEstateAssetCompleteCallback, req); + + LL_DEBUGS("AssetStorage") << "Starting transfer for " << asset_id << LL_ENDL; + LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(source_host, LLTCT_ASSET); + ttcp->requestTransfer(spe, tpvf, 100.f + (is_priority ? 1.f : 0.f)); + } + else + { + // uh-oh, we shouldn't have gotten here + LL_WARNS("AssetStorage") << "Attempt to move asset data request upstream w/o valid upstream provider" << LL_ENDL; + if (callback) + { + add(sFailedDownloadCount, 1); + callback(mVFS, asset_id, atype, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM); + } + } + } } void LLAssetStorage::downloadEstateAssetCompleteCallback( - S32 result, - const LLUUID& file_id, - LLAssetType::EType file_type, - LLBaseDownloadRequest* user_data, - LLExtStat ext_status) -{ - LLEstateAssetRequest *req = (LLEstateAssetRequest*)user_data; - if(!req) - { - LL_WARNS() << "LLAssetStorage::downloadEstateAssetCompleteCallback called" - " without a valid request." << LL_ENDL; - return; - } - if (!gAssetStorage) - { - LL_WARNS() << "LLAssetStorage::downloadEstateAssetCompleteCallback called" - " without any asset system, aborting!" << LL_ENDL; - return; - } - - req->setUUID(file_id); - req->setType(file_type); - if (LL_ERR_NOERR == result) - { - // we might have gotten a zero-size file - LLVFile vfile(gAssetStorage->mVFS, req->getUUID(), req->getAType()); - if (vfile.getSize() <= 0) - { - LL_WARNS() << "downloadCompleteCallback has non-existent or zero-size asset!" << LL_ENDL; - - result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE; - vfile.remove(); - } - } - - if (result != LL_ERR_NOERR) - { - add(sFailedDownloadCount, 1); - } - req->mDownCallback(gAssetStorage->mVFS, req->getUUID(), req->getAType(), req->mUserData, result, ext_status); -} - -void LLAssetStorage::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 callback, void *user_data, BOOL is_priority) -{ - LL_DEBUGS() << "LLAssetStorage::getInvItemAsset() - " << asset_id << "," << LLAssetType::lookup(atype) << LL_ENDL; - - // - // Probably will get rid of this early out? - // - //if (asset_id.isNull()) - //{ - // // Special case early out for NULL uuid - // if (callback) - // { - // callback(mVFS, asset_id, atype, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE); - // } - // return; - //} - - bool exists = false; - U32 size = 0; - - if(asset_id.notNull()) - { - // Try static VFS first. - if (findInStaticVFSAndInvokeCallback( asset_id, atype, callback, user_data)) - { - return; - } - - exists = mVFS->getExists(asset_id, atype); - LLVFile file(mVFS, asset_id, atype); - size = exists ? file.getSize() : 0; - if(exists && size < 1) - { - LL_WARNS() << "Asset vfile " << asset_id << ":" << atype << " found with bad size " << file.getSize() << ", removing" << LL_ENDL; - file.remove(); - } - - } - - if (size > 0) - { - // we've already got the file - // theoretically, partial files w/o a pending request shouldn't happen - // unless there's a weird error - if (callback) - { - callback(mVFS, asset_id, atype, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED); - } - } - else - { - // See whether we should talk to the object's originating sim, - // or the upstream provider. - LLHost source_host; - if (object_sim.isOk()) - { - source_host = object_sim; - } - else - { - source_host = mUpstreamHost; - } - if (source_host.isOk()) - { - // stash the callback info so we can find it after we get the response message - LLInvItemRequest req(asset_id, atype); - req.mDownCallback = callback; - req.mUserData = user_data; - req.mIsPriority = is_priority; - - // send request message to our upstream data provider - // Create a new asset transfer. - LLTransferSourceParamsInvItem spi; - spi.setAgentSession(agent_id, session_id); - spi.setInvItem(owner_id, task_id, item_id); - spi.setAsset(asset_id, atype); - - // Set our destination file, and the completion callback. - LLTransferTargetParamsVFile tpvf; - tpvf.setAsset(asset_id, atype); - tpvf.setCallback(downloadInvItemCompleteCallback, req); - - LL_DEBUGS("AssetStorage") << "Starting transfer for inventory asset " - << item_id << " owned by " << owner_id << "," << task_id - << LL_ENDL; - LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(source_host, LLTCT_ASSET); - ttcp->requestTransfer(spi, tpvf, 100.f + (is_priority ? 1.f : 0.f)); - } - else - { - // uh-oh, we shouldn't have gotten here - LL_WARNS() << "Attempt to move asset data request upstream w/o valid upstream provider" << LL_ENDL; - if (callback) - { - add(sFailedDownloadCount, 1); - callback(mVFS, asset_id, atype, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM); - } - } - } + S32 result, + const LLUUID& file_id, + LLAssetType::EType file_type, + LLBaseDownloadRequest* user_data, + LLExtStat ext_status) +{ + LLEstateAssetRequest *req = (LLEstateAssetRequest*)user_data; + if(!req) + { + LL_WARNS("AssetStorage") << "LLAssetStorage::downloadEstateAssetCompleteCallback called" + " without a valid request." << LL_ENDL; + return; + } + if (!gAssetStorage) + { + LL_WARNS("AssetStorage") << "LLAssetStorage::downloadEstateAssetCompleteCallback called" + " without any asset system, aborting!" << LL_ENDL; + return; + } + + req->setUUID(file_id); + req->setType(file_type); + if (LL_ERR_NOERR == result) + { + // we might have gotten a zero-size file + LLVFile vfile(gAssetStorage->mVFS, req->getUUID(), req->getAType()); + if (vfile.getSize() <= 0) + { + LL_WARNS("AssetStorage") << "downloadCompleteCallback has non-existent or zero-size asset!" << LL_ENDL; + + result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE; + vfile.remove(); + } + } + + if (result != LL_ERR_NOERR) + { + add(sFailedDownloadCount, 1); + } + req->mDownCallback(gAssetStorage->mVFS, req->getUUID(), req->getAType(), req->mUserData, result, ext_status); +} + +void LLAssetStorage::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 callback, + void *user_data, + BOOL is_priority) +{ + LL_DEBUGS() << "LLAssetStorage::getInvItemAsset() - " << asset_id << "," << LLAssetType::lookup(atype) << LL_ENDL; + + bool exists = false; + U32 size = 0; + + if(asset_id.notNull()) + { + // Try static VFS first. + if (findInStaticVFSAndInvokeCallback( asset_id, atype, callback, user_data)) + { + return; + } + + exists = mVFS->getExists(asset_id, atype); + LLVFile file(mVFS, asset_id, atype); + size = exists ? file.getSize() : 0; + if(exists && size < 1) + { + LL_WARNS("AssetStorage") << "Asset vfile " << asset_id << ":" << atype << " found with bad size " << file.getSize() << ", removing" << LL_ENDL; + file.remove(); + } + + } + + if (size > 0) + { + // we've already got the file + // theoretically, partial files w/o a pending request shouldn't happen + // unless there's a weird error + if (callback) + { + callback(mVFS, asset_id, atype, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED); + } + } + else + { + // See whether we should talk to the object's originating sim, + // or the upstream provider. + LLHost source_host; + if (object_sim.isOk()) + { + source_host = object_sim; + } + else + { + source_host = mUpstreamHost; + } + if (source_host.isOk()) + { + // stash the callback info so we can find it after we get the response message + LLInvItemRequest req(asset_id, atype); + req.mDownCallback = callback; + req.mUserData = user_data; + req.mIsPriority = is_priority; + + // send request message to our upstream data provider + // Create a new asset transfer. + LLTransferSourceParamsInvItem spi; + spi.setAgentSession(agent_id, session_id); + spi.setInvItem(owner_id, task_id, item_id); + spi.setAsset(asset_id, atype); + + LL_DEBUGS("ViewerAsset") << "requesting inv item id " << item_id << " asset_id " << asset_id << " type " << LLAssetType::lookup(atype) << LL_ENDL; + + // Set our destination file, and the completion callback. + LLTransferTargetParamsVFile tpvf; + tpvf.setAsset(asset_id, atype); + tpvf.setCallback(downloadInvItemCompleteCallback, req); + + LL_DEBUGS("AssetStorage") << "Starting transfer for inventory asset " + << item_id << " owned by " << owner_id << "," << task_id + << LL_ENDL; + LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(source_host, LLTCT_ASSET); + ttcp->requestTransfer(spi, tpvf, 100.f + (is_priority ? 1.f : 0.f)); + } + else + { + // uh-oh, we shouldn't have gotten here + LL_WARNS("AssetStorage") << "Attempt to move asset data request upstream w/o valid upstream provider" << LL_ENDL; + if (callback) + { + add(sFailedDownloadCount, 1); + callback(mVFS, asset_id, atype, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM); + } + } + } } void LLAssetStorage::downloadInvItemCompleteCallback( - S32 result, - const LLUUID& file_id, - LLAssetType::EType file_type, - LLBaseDownloadRequest* user_data, - LLExtStat ext_status) -{ - LLInvItemRequest *req = (LLInvItemRequest*)user_data; - if(!req) - { - LL_WARNS() << "LLAssetStorage::downloadEstateAssetCompleteCallback called" - " without a valid request." << LL_ENDL; - return; - } - if (!gAssetStorage) - { - LL_WARNS() << "LLAssetStorage::downloadCompleteCallback called without any asset system, aborting!" << LL_ENDL; - return; - } - - req->setUUID(file_id); - req->setType(file_type); - if (LL_ERR_NOERR == result) - { - // we might have gotten a zero-size file - LLVFile vfile(gAssetStorage->mVFS, req->getUUID(), req->getType()); - if (vfile.getSize() <= 0) - { - LL_WARNS() << "downloadCompleteCallback has non-existent or zero-size asset!" << LL_ENDL; - - result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE; - vfile.remove(); - } - } - - if (result != LL_ERR_NOERR) - { - add(sFailedDownloadCount, 1); - } - req->mDownCallback(gAssetStorage->mVFS, req->getUUID(), req->getType(), req->mUserData, result, ext_status); + S32 result, + const LLUUID& file_id, + LLAssetType::EType file_type, + LLBaseDownloadRequest* user_data, + LLExtStat ext_status) +{ + LLInvItemRequest *req = (LLInvItemRequest*)user_data; + if(!req) + { + LL_WARNS("AssetStorage") << "LLAssetStorage::downloadEstateAssetCompleteCallback called" + " without a valid request." << LL_ENDL; + return; + } + if (!gAssetStorage) + { + LL_WARNS("AssetStorage") << "LLAssetStorage::downloadCompleteCallback called without any asset system, aborting!" << LL_ENDL; + return; + } + + req->setUUID(file_id); + req->setType(file_type); + if (LL_ERR_NOERR == result) + { + // we might have gotten a zero-size file + LLVFile vfile(gAssetStorage->mVFS, req->getUUID(), req->getType()); + if (vfile.getSize() <= 0) + { + LL_WARNS("AssetStorage") << "downloadCompleteCallback has non-existent or zero-size asset!" << LL_ENDL; + + result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE; + vfile.remove(); + } + } + + if (result != LL_ERR_NOERR) + { + add(sFailedDownloadCount, 1); + } + req->mDownCallback(gAssetStorage->mVFS, req->getUUID(), req->getType(), req->mUserData, result, ext_status); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -979,654 +954,558 @@ void LLAssetStorage::downloadInvItemCompleteCallback( ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// // static -void LLAssetStorage::uploadCompleteCallback(const LLUUID& uuid, void *user_data, S32 result, LLExtStat ext_status) // StoreAssetData callback (fixed) -{ - if (!gAssetStorage) - { - LL_WARNS() << "LLAssetStorage::uploadCompleteCallback has no gAssetStorage!" << LL_ENDL; - return; - } - LLAssetRequest *req = (LLAssetRequest *)user_data; - BOOL success = TRUE; - - if (result) - { - LL_WARNS() << "LLAssetStorage::uploadCompleteCallback " << result << ":" << getErrorString(result) << " trying to upload file to upstream provider" << LL_ENDL; - success = FALSE; - } - - // we're done grabbing the file, tell the client - gAssetStorage->mMessageSys->newMessageFast(_PREHASH_AssetUploadComplete); - gAssetStorage->mMessageSys->nextBlockFast(_PREHASH_AssetBlock); - gAssetStorage->mMessageSys->addUUIDFast(_PREHASH_UUID, uuid); - gAssetStorage->mMessageSys->addS8Fast(_PREHASH_Type, req->getType()); - gAssetStorage->mMessageSys->addBOOLFast(_PREHASH_Success, success); - gAssetStorage->mMessageSys->sendReliable(req->mHost); - - delete req; +void LLAssetStorage::uploadCompleteCallback( + const LLUUID& uuid, + void *user_data, + S32 result, + LLExtStat ext_status) // StoreAssetData callback (fixed) +{ + if (!gAssetStorage) + { + LL_WARNS("AssetStorage") << "LLAssetStorage::uploadCompleteCallback has no gAssetStorage!" << LL_ENDL; + return; + } + LLAssetRequest *req = (LLAssetRequest *)user_data; + BOOL success = TRUE; + + if (result) + { + LL_WARNS("AssetStorage") << "LLAssetStorage::uploadCompleteCallback " << result << ":" << getErrorString(result) << " trying to upload file to upstream provider" << LL_ENDL; + success = FALSE; + } + + // we're done grabbing the file, tell the client + gAssetStorage->mMessageSys->newMessageFast(_PREHASH_AssetUploadComplete); + gAssetStorage->mMessageSys->nextBlockFast(_PREHASH_AssetBlock); + gAssetStorage->mMessageSys->addUUIDFast(_PREHASH_UUID, uuid); + gAssetStorage->mMessageSys->addS8Fast(_PREHASH_Type, req->getType()); + gAssetStorage->mMessageSys->addBOOLFast(_PREHASH_Success, success); + gAssetStorage->mMessageSys->sendReliable(req->mHost); + + delete req; } void LLAssetStorage::processUploadComplete(LLMessageSystem *msg, void **user_data) { - LLAssetStorage *this_ptr = (LLAssetStorage *)user_data; - LLUUID uuid; - S8 asset_type_s8; - LLAssetType::EType asset_type; - BOOL success = FALSE; - - msg->getUUIDFast(_PREHASH_AssetBlock, _PREHASH_UUID, uuid); - msg->getS8Fast(_PREHASH_AssetBlock, _PREHASH_Type, asset_type_s8); - msg->getBOOLFast(_PREHASH_AssetBlock, _PREHASH_Success, success); - - asset_type = (LLAssetType::EType)asset_type_s8; - this_ptr->_callUploadCallbacks(uuid, asset_type, success, LL_EXSTAT_NONE); + LLAssetStorage *this_ptr = (LLAssetStorage *)user_data; + LLUUID uuid; + S8 asset_type_s8; + LLAssetType::EType asset_type; + BOOL success = FALSE; + + msg->getUUIDFast(_PREHASH_AssetBlock, _PREHASH_UUID, uuid); + msg->getS8Fast(_PREHASH_AssetBlock, _PREHASH_Type, asset_type_s8); + msg->getBOOLFast(_PREHASH_AssetBlock, _PREHASH_Success, success); + + asset_type = (LLAssetType::EType)asset_type_s8; + this_ptr->_callUploadCallbacks(uuid, asset_type, success, LL_EXSTAT_NONE); } void LLAssetStorage::_callUploadCallbacks(const LLUUID &uuid, LLAssetType::EType asset_type, BOOL success, LLExtStat ext_status ) { - // SJB: We process the callbacks in reverse order, I do not know if this is important, - // but I didn't want to mess with it. - request_list_t requests; - for (request_list_t::iterator iter = mPendingUploads.begin(); - iter != mPendingUploads.end(); ) - { - request_list_t::iterator curiter = iter++; - LLAssetRequest* req = *curiter; - if ((req->getUUID() == uuid) && (req->getType() == asset_type)) - { - requests.push_front(req); - iter = mPendingUploads.erase(curiter); - } - } - for (request_list_t::iterator iter = mPendingLocalUploads.begin(); - iter != mPendingLocalUploads.end(); ) - { - request_list_t::iterator curiter = iter++; - LLAssetRequest* req = *curiter; - if ((req->getUUID() == uuid) && (req->getType() == asset_type)) - { - requests.push_front(req); - iter = mPendingLocalUploads.erase(curiter); - } - } - for (request_list_t::iterator iter = requests.begin(); - iter != requests.end(); ) - { - request_list_t::iterator curiter = iter++; - LLAssetRequest* req = *curiter; - if (req->mUpCallback) - { - req->mUpCallback(uuid, req->mUserData, (success ? LL_ERR_NOERR : LL_ERR_ASSET_REQUEST_FAILED ), ext_status ); - } - delete req; - } + // SJB: We process the callbacks in reverse order, I do not know if this is important, + // but I didn't want to mess with it. + request_list_t requests; + for (request_list_t::iterator iter = mPendingUploads.begin(); + iter != mPendingUploads.end(); ) + { + request_list_t::iterator curiter = iter++; + LLAssetRequest* req = *curiter; + if ((req->getUUID() == uuid) && (req->getType() == asset_type)) + { + requests.push_front(req); + iter = mPendingUploads.erase(curiter); + } + } + for (request_list_t::iterator iter = mPendingLocalUploads.begin(); + iter != mPendingLocalUploads.end(); ) + { + request_list_t::iterator curiter = iter++; + LLAssetRequest* req = *curiter; + if ((req->getUUID() == uuid) && (req->getType() == asset_type)) + { + requests.push_front(req); + iter = mPendingLocalUploads.erase(curiter); + } + } + for (request_list_t::iterator iter = requests.begin(); + iter != requests.end(); ) + { + request_list_t::iterator curiter = iter++; + LLAssetRequest* req = *curiter; + if (req->mUpCallback) + { + req->mUpCallback(uuid, req->mUserData, (success ? LL_ERR_NOERR : LL_ERR_ASSET_REQUEST_FAILED ), ext_status ); + } + delete req; + } } LLAssetStorage::request_list_t* LLAssetStorage::getRequestList(LLAssetStorage::ERequestType rt) { - switch (rt) - { - case RT_DOWNLOAD: - return &mPendingDownloads; - case RT_UPLOAD: - return &mPendingUploads; - case RT_LOCALUPLOAD: - return &mPendingLocalUploads; - default: - LL_WARNS() << "Unable to find request list for request type '" << rt << "'" << LL_ENDL; - return NULL; - } + switch (rt) + { + case RT_DOWNLOAD: + return &mPendingDownloads; + case RT_UPLOAD: + return &mPendingUploads; + case RT_LOCALUPLOAD: + return &mPendingLocalUploads; + default: + LL_WARNS("AssetStorage") << "Unable to find request list for request type '" << rt << "'" << LL_ENDL; + return NULL; + } } const LLAssetStorage::request_list_t* LLAssetStorage::getRequestList(LLAssetStorage::ERequestType rt) const { - switch (rt) - { - case RT_DOWNLOAD: - return &mPendingDownloads; - case RT_UPLOAD: - return &mPendingUploads; - case RT_LOCALUPLOAD: - return &mPendingLocalUploads; - default: - LL_WARNS() << "Unable to find request list for request type '" << rt << "'" << LL_ENDL; - return NULL; - } + switch (rt) + { + case RT_DOWNLOAD: + return &mPendingDownloads; + case RT_UPLOAD: + return &mPendingUploads; + case RT_LOCALUPLOAD: + return &mPendingLocalUploads; + default: + LL_WARNS("AssetStorage") << "Unable to find request list for request type '" << rt << "'" << LL_ENDL; + return NULL; + } } // static std::string LLAssetStorage::getRequestName(LLAssetStorage::ERequestType rt) { - switch (rt) - { - case RT_DOWNLOAD: - return "download"; - case RT_UPLOAD: - return "upload"; - case RT_LOCALUPLOAD: - return "localupload"; - default: - LL_WARNS() << "Unable to find request name for request type '" << rt << "'" << LL_ENDL; - return ""; - } + switch (rt) + { + case RT_DOWNLOAD: + return "download"; + case RT_UPLOAD: + return "upload"; + case RT_LOCALUPLOAD: + return "localupload"; + default: + LL_WARNS("AssetStorage") << "Unable to find request name for request type '" << rt << "'" << LL_ENDL; + return ""; + } } S32 LLAssetStorage::getNumPending(LLAssetStorage::ERequestType rt) const { - const request_list_t* requests = getRequestList(rt); - S32 num_pending = -1; - if (requests) - { - num_pending = requests->size(); - } - return num_pending; + const request_list_t* requests = getRequestList(rt); + S32 num_pending = -1; + if (requests) + { + num_pending = requests->size(); + } + return num_pending; } S32 LLAssetStorage::getNumPendingDownloads() const { - return getNumPending(RT_DOWNLOAD); + return getNumPending(RT_DOWNLOAD); } S32 LLAssetStorage::getNumPendingUploads() const { - return getNumPending(RT_UPLOAD); + return getNumPending(RT_UPLOAD); } S32 LLAssetStorage::getNumPendingLocalUploads() { - return getNumPending(RT_LOCALUPLOAD); + return getNumPending(RT_LOCALUPLOAD); } -// virtual LLSD LLAssetStorage::getPendingDetails(LLAssetStorage::ERequestType rt, - LLAssetType::EType asset_type, - const std::string& detail_prefix) const + LLAssetType::EType asset_type, + const std::string& detail_prefix) const { - const request_list_t* requests = getRequestList(rt); - LLSD sd; - sd["requests"] = getPendingDetailsImpl(requests, asset_type, detail_prefix); - return sd; + const request_list_t* requests = getRequestList(rt); + LLSD sd; + sd["requests"] = getPendingDetailsImpl(requests, asset_type, detail_prefix); + return sd; } -// virtual LLSD LLAssetStorage::getPendingDetailsImpl(const LLAssetStorage::request_list_t* requests, - LLAssetType::EType asset_type, - const std::string& detail_prefix) const -{ - LLSD details; - if (requests) - { - request_list_t::const_iterator it = requests->begin(); - request_list_t::const_iterator end = requests->end(); - for ( ; it != end; ++it) - { - LLAssetRequest* req = *it; - if ( (LLAssetType::AT_NONE == asset_type) - || (req->getType() == asset_type) ) - { - LLSD row = req->getTerseDetails(); - - std::ostringstream detail; - detail << detail_prefix << "/" << LLAssetType::lookup(req->getType()) - << "/" << req->getUUID(); - row["detail"] = LLURI(detail.str()); - - details.append(row); - } - } - } - return details; + LLAssetType::EType asset_type, + const std::string& detail_prefix) const +{ + LLSD details; + if (requests) + { + request_list_t::const_iterator it = requests->begin(); + request_list_t::const_iterator end = requests->end(); + for ( ; it != end; ++it) + { + LLAssetRequest* req = *it; + if ( (LLAssetType::AT_NONE == asset_type) + || (req->getType() == asset_type) ) + { + LLSD row = req->getTerseDetails(); + + std::ostringstream detail; + detail << detail_prefix << "/" << LLAssetType::lookup(req->getType()) + << "/" << req->getUUID(); + row["detail"] = LLURI(detail.str()); + + details.append(row); + } + } + } + return details; } // static const LLAssetRequest* LLAssetStorage::findRequest(const LLAssetStorage::request_list_t* requests, - LLAssetType::EType asset_type, - const LLUUID& asset_id) -{ - if (requests) - { - // Search the requests list for the asset. - request_list_t::const_iterator iter = requests->begin(); - request_list_t::const_iterator end = requests->end(); - for (; iter != end; ++iter) - { - const LLAssetRequest* req = *iter; - if (asset_type == req->getType() && - asset_id == req->getUUID() ) - { - return req; - } - } - } - return NULL; + LLAssetType::EType asset_type, + const LLUUID& asset_id) +{ + if (requests) + { + // Search the requests list for the asset. + request_list_t::const_iterator iter = requests->begin(); + request_list_t::const_iterator end = requests->end(); + for (; iter != end; ++iter) + { + const LLAssetRequest* req = *iter; + if (asset_type == req->getType() && + asset_id == req->getUUID() ) + { + return req; + } + } + } + return NULL; } // static LLAssetRequest* LLAssetStorage::findRequest(LLAssetStorage::request_list_t* requests, - LLAssetType::EType asset_type, - const LLUUID& asset_id) -{ - if (requests) - { - // Search the requests list for the asset. - request_list_t::iterator iter = requests->begin(); - request_list_t::iterator end = requests->end(); - for (; iter != end; ++iter) - { - LLAssetRequest* req = *iter; - if (asset_type == req->getType() && - asset_id == req->getUUID() ) - { - return req; - } - } - } - return NULL; + LLAssetType::EType asset_type, + const LLUUID& asset_id) +{ + if (requests) + { + // Search the requests list for the asset. + request_list_t::iterator iter = requests->begin(); + request_list_t::iterator end = requests->end(); + for (; iter != end; ++iter) + { + LLAssetRequest* req = *iter; + if (asset_type == req->getType() && + asset_id == req->getUUID() ) + { + return req; + } + } + } + return NULL; } -// virtual LLSD LLAssetStorage::getPendingRequest(LLAssetStorage::ERequestType rt, - LLAssetType::EType asset_type, - const LLUUID& asset_id) const + LLAssetType::EType asset_type, + const LLUUID& asset_id) const { - const request_list_t* requests = getRequestList(rt); - return getPendingRequestImpl(requests, asset_type, asset_id); + const request_list_t* requests = getRequestList(rt); + return getPendingRequestImpl(requests, asset_type, asset_id); } -// virtual LLSD LLAssetStorage::getPendingRequestImpl(const LLAssetStorage::request_list_t* requests, - LLAssetType::EType asset_type, - const LLUUID& asset_id) const + LLAssetType::EType asset_type, + const LLUUID& asset_id) const { - LLSD sd; - const LLAssetRequest* req = findRequest(requests, asset_type, asset_id); - if (req) - { - sd = req->getFullDetails(); - } - return sd; + LLSD sd; + const LLAssetRequest* req = findRequest(requests, asset_type, asset_id); + if (req) + { + sd = req->getFullDetails(); + } + return sd; } -// virtual bool LLAssetStorage::deletePendingRequest(LLAssetStorage::ERequestType rt, - LLAssetType::EType asset_type, - const LLUUID& asset_id) + LLAssetType::EType asset_type, + const LLUUID& asset_id) { - request_list_t* requests = getRequestList(rt); - if (deletePendingRequestImpl(requests, asset_type, asset_id)) - { - LL_DEBUGS("AssetStorage") << "Asset " << getRequestName(rt) << " request for " - << asset_id << "." << LLAssetType::lookup(asset_type) - << " removed from pending queue." << LL_ENDL; - return true; - } - return false; + request_list_t* requests = getRequestList(rt); + if (deletePendingRequestImpl(requests, asset_type, asset_id)) + { + LL_DEBUGS("AssetStorage") << "Asset " << getRequestName(rt) << " request for " + << asset_id << "." << LLAssetType::lookup(asset_type) + << " removed from pending queue." << LL_ENDL; + return true; + } + return false; } -// virtual bool LLAssetStorage::deletePendingRequestImpl(LLAssetStorage::request_list_t* requests, - LLAssetType::EType asset_type, - const LLUUID& asset_id) -{ - LLAssetRequest* req = findRequest(requests, asset_type, asset_id); - if (req) - { - // Remove the request from this list. - requests->remove(req); - S32 error = LL_ERR_TCP_TIMEOUT; - // Run callbacks. - if (req->mUpCallback) - { - req->mUpCallback(req->getUUID(), req->mUserData, error, LL_EXSTAT_REQUEST_DROPPED); - } - if (req->mDownCallback) - { - add(sFailedDownloadCount, 1); - req->mDownCallback(mVFS, req->getUUID(), req->getType(), req->mUserData, error, LL_EXSTAT_REQUEST_DROPPED); - } - if (req->mInfoCallback) - { - LLAssetInfo info; - req->mInfoCallback(&info, req->mUserData, error); - } - delete req; - return true; - } - - return false; + LLAssetType::EType asset_type, + const LLUUID& asset_id) +{ + LLAssetRequest* req = findRequest(requests, asset_type, asset_id); + if (req) + { + // Remove the request from this list. + requests->remove(req); + S32 error = LL_ERR_TCP_TIMEOUT; + // Run callbacks. + if (req->mUpCallback) + { + req->mUpCallback(req->getUUID(), req->mUserData, error, LL_EXSTAT_REQUEST_DROPPED); + } + if (req->mDownCallback) + { + add(sFailedDownloadCount, 1); + req->mDownCallback(mVFS, req->getUUID(), req->getType(), req->mUserData, error, LL_EXSTAT_REQUEST_DROPPED); + } + if (req->mInfoCallback) + { + LLAssetInfo info; + req->mInfoCallback(&info, req->mUserData, error); + } + delete req; + return true; + } + + return false; } // static const char* LLAssetStorage::getErrorString(S32 status) { - switch( status ) - { - case LL_ERR_NOERR: - return "No error"; + switch( status ) + { + case LL_ERR_NOERR: + return "No error"; - case LL_ERR_ASSET_REQUEST_FAILED: - return "Asset request: failed"; + case LL_ERR_ASSET_REQUEST_FAILED: + return "Asset request: failed"; - case LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE: - return "Asset request: non-existent file"; + case LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE: + return "Asset request: non-existent file"; - case LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE: - return "Asset request: asset not found in database"; + case LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE: + return "Asset request: asset not found in database"; - case LL_ERR_EOF: - return "End of file"; + case LL_ERR_EOF: + return "End of file"; - case LL_ERR_CANNOT_OPEN_FILE: - return "Cannot open file"; + case LL_ERR_CANNOT_OPEN_FILE: + return "Cannot open file"; - case LL_ERR_FILE_NOT_FOUND: - return "File not found"; + case LL_ERR_FILE_NOT_FOUND: + return "File not found"; - case LL_ERR_TCP_TIMEOUT: - return "File transfer timeout"; + case LL_ERR_TCP_TIMEOUT: + return "File transfer timeout"; - case LL_ERR_CIRCUIT_GONE: - return "Circuit gone"; + case LL_ERR_CIRCUIT_GONE: + return "Circuit gone"; - case LL_ERR_PRICE_MISMATCH: - return "Viewer and server do not agree on price"; + case LL_ERR_PRICE_MISMATCH: + return "Viewer and server do not agree on price"; - default: - return "Unknown status"; - } + default: + return "Unknown status"; + } } - - -void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, void (*callback)(const char*, const LLUUID&, void *, S32, LLExtStat), void *user_data, BOOL is_priority) +void LLAssetStorage::getAssetData(const LLUUID uuid, + LLAssetType::EType type, + void (*callback)(const char*, + const LLUUID&, + void *, + S32, + LLExtStat), + void *user_data, + BOOL is_priority) { - // check for duplicates here, since we're about to fool the normal duplicate checker - for (request_list_t::iterator iter = mPendingDownloads.begin(); - iter != mPendingDownloads.end(); ) - { - LLAssetRequest* tmp = *iter++; - if (type == tmp->getType() && - uuid == tmp->getUUID() && - legacyGetDataCallback == tmp->mDownCallback && - callback == ((LLLegacyAssetRequest *)tmp->mUserData)->mDownCallback && - user_data == ((LLLegacyAssetRequest *)tmp->mUserData)->mUserData) - { - // this is a duplicate from the same subsystem - throw it away - LL_DEBUGS("AssetStorage") << "Discarding duplicate request for UUID " << uuid << LL_ENDL; - return; - } - } - - - LLLegacyAssetRequest *legacy = new LLLegacyAssetRequest; - - legacy->mDownCallback = callback; - legacy->mUserData = user_data; - - getAssetData(uuid, type, legacyGetDataCallback, (void **)legacy, - is_priority); -} + // check for duplicates here, since we're about to fool the normal duplicate checker + for (request_list_t::iterator iter = mPendingDownloads.begin(); + iter != mPendingDownloads.end(); ) + { + LLAssetRequest* tmp = *iter++; + if (type == tmp->getType() && + uuid == tmp->getUUID() && + legacyGetDataCallback == tmp->mDownCallback && + callback == ((LLLegacyAssetRequest *)tmp->mUserData)->mDownCallback && + user_data == ((LLLegacyAssetRequest *)tmp->mUserData)->mUserData) + { + // this is a duplicate from the same subsystem - throw it away + LL_DEBUGS("AssetStorage") << "Discarding duplicate request for UUID " << uuid << LL_ENDL; + return; + } + } + + + LLLegacyAssetRequest *legacy = new LLLegacyAssetRequest; -// static -void LLAssetStorage::legacyGetDataCallback(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type, void *user_data, S32 status, LLExtStat ext_status) -{ - LLLegacyAssetRequest *legacy = (LLLegacyAssetRequest *)user_data; - std::string filename; - - // Check if the asset is marked toxic, and don't load bad stuff - BOOL toxic = gAssetStorage->isAssetToxic( uuid ); - - if ( !status - && !toxic ) - { - LLVFile file(vfs, uuid, type); - - std::string uuid_str; - - uuid.toString(uuid_str); - filename = llformat("%s.%s",gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_str).c_str(),LLAssetType::lookup(type)); - - LLFILE* fp = LLFile::fopen(filename, "wb"); /* Flawfinder: ignore */ - if (fp) - { - const S32 buf_size = 65536; - U8 copy_buf[buf_size]; - while (file.read(copy_buf, buf_size)) /* Flawfinder: ignore */ - { - if (fwrite(copy_buf, file.getLastBytesRead(), 1, fp) < 1) - { - // return a bad file error if we can't write the whole thing - status = LL_ERR_CANNOT_OPEN_FILE; - } - } - - fclose(fp); - } - else - { - status = LL_ERR_CANNOT_OPEN_FILE; - } - } - - if (status != LL_ERR_NOERR) - { - add(sFailedDownloadCount, 1); - } - legacy->mDownCallback(filename.c_str(), uuid, legacy->mUserData, status, ext_status); - delete legacy; -} - -// this is overridden on the viewer and the sim, so it doesn't really do anything -// virtual -void LLAssetStorage::storeAssetData( - const LLTransactionID& tid, - LLAssetType::EType asset_type, - LLStoreAssetCallback callback, - void* user_data, - bool temp_file, - bool is_priority, - bool store_local, - bool user_waiting, - F64Seconds timeout) -{ - LL_WARNS() << "storeAssetData: wrong version called" << LL_ENDL; - // LLAssetStorage metric: Virtual base call - reportMetric( LLUUID::null, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_BAD_FUNCTION, __FILE__, __LINE__, "Illegal call to base: LLAssetStorage::storeAssetData 1" ); -} - -// virtual -// this does nothing, viewer and sim both override this. -void LLAssetStorage::storeAssetData( - const LLUUID& asset_id, - LLAssetType::EType asset_type, - LLStoreAssetCallback callback, - void* user_data, - bool temp_file , - bool is_priority, - bool store_local, - const LLUUID& requesting_agent_id, - bool user_waiting, - F64Seconds timeout) -{ - LL_WARNS() << "storeAssetData: wrong version called" << LL_ENDL; - // LLAssetStorage metric: Virtual base call - reportMetric( asset_id, asset_type, LLStringUtil::null, requesting_agent_id, 0, MR_BAD_FUNCTION, __FILE__, __LINE__, "Illegal call to base: LLAssetStorage::storeAssetData 2" ); -} + legacy->mDownCallback = callback; + legacy->mUserData = user_data; -// virtual -// this does nothing, viewer and sim both override this. -void LLAssetStorage::storeAssetData( - const std::string& filename, - const LLUUID& asset_id, - LLAssetType::EType asset_type, - LLStoreAssetCallback callback, - void* user_data, - bool temp_file, - bool is_priority, - bool user_waiting, - F64Seconds timeout) -{ - LL_WARNS() << "storeAssetData: wrong version called" << LL_ENDL; - // LLAssetStorage metric: Virtual base call - reportMetric( asset_id, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_BAD_FUNCTION, __FILE__, __LINE__, "Illegal call to base: LLAssetStorage::storeAssetData 3" ); + getAssetData(uuid, type, legacyGetDataCallback, (void **)legacy, + is_priority); } -// virtual -// this does nothing, viewer and sim both override this. -void LLAssetStorage::storeAssetData( - const std::string& filename, - const LLTransactionID &transactoin_id, - LLAssetType::EType asset_type, - LLStoreAssetCallback callback, - void* user_data, - bool temp_file, - bool is_priority, - bool user_waiting, - F64Seconds timeout) -{ - LL_WARNS() << "storeAssetData: wrong version called" << LL_ENDL; - // LLAssetStorage metric: Virtual base call - reportMetric( LLUUID::null, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_BAD_FUNCTION, __FILE__, __LINE__, "Illegal call to base: LLAssetStorage::storeAssetData 4" ); +// static +void LLAssetStorage::legacyGetDataCallback(LLVFS *vfs, + const LLUUID &uuid, + LLAssetType::EType type, + void *user_data, + S32 status, + LLExtStat ext_status) +{ + LLLegacyAssetRequest *legacy = (LLLegacyAssetRequest *)user_data; + std::string filename; + + // Check if the asset is marked toxic, and don't load bad stuff + BOOL toxic = gAssetStorage->isAssetToxic( uuid ); + + if ( !status + && !toxic ) + { + LLVFile file(vfs, uuid, type); + + std::string uuid_str; + + uuid.toString(uuid_str); + filename = llformat("%s.%s",gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_str).c_str(),LLAssetType::lookup(type)); + + LLFILE* fp = LLFile::fopen(filename, "wb"); /* Flawfinder: ignore */ + if (fp) + { + const S32 buf_size = 65536; + U8 copy_buf[buf_size]; + while (file.read(copy_buf, buf_size)) /* Flawfinder: ignore */ + { + if (fwrite(copy_buf, file.getLastBytesRead(), 1, fp) < 1) + { + // return a bad file error if we can't write the whole thing + status = LL_ERR_CANNOT_OPEN_FILE; + } + } + + fclose(fp); + } + else + { + status = LL_ERR_CANNOT_OPEN_FILE; + } + } + + if (status != LL_ERR_NOERR) + { + add(sFailedDownloadCount, 1); + } + legacy->mDownCallback(filename.c_str(), uuid, legacy->mUserData, status, ext_status); + delete legacy; } // static void LLAssetStorage::legacyStoreDataCallback(const LLUUID &uuid, void *user_data, S32 status, LLExtStat ext_status) { - LLLegacyAssetRequest *legacy = (LLLegacyAssetRequest *)user_data; - if (legacy && legacy->mUpCallback) - { - legacy->mUpCallback(uuid, legacy->mUserData, status, ext_status); - } - delete legacy; + LLLegacyAssetRequest *legacy = (LLLegacyAssetRequest *)user_data; + if (legacy && legacy->mUpCallback) + { + legacy->mUpCallback(uuid, legacy->mUserData, status, ext_status); + } + delete legacy; } -// virtual -void LLAssetStorage::addTempAssetData(const LLUUID& asset_id, const LLUUID& agent_id, const std::string& host_name) -{ } - -// virtual -BOOL LLAssetStorage::hasTempAssetData(const LLUUID& texture_id) const -{ return FALSE; } - -// virtual -std::string LLAssetStorage::getTempAssetHostName(const LLUUID& texture_id) const -{ return std::string(); } - -// virtual -LLUUID LLAssetStorage::getTempAssetAgentID(const LLUUID& texture_id) const -{ return LLUUID::null; } - -// virtual -void LLAssetStorage::removeTempAssetData(const LLUUID& asset_id) -{ } - -// virtual -void LLAssetStorage::removeTempAssetDataByAgentID(const LLUUID& agent_id) -{ } - -// virtual -void LLAssetStorage::dumpTempAssetData(const LLUUID& avatar_id) const -{ } - -// virtual -void LLAssetStorage::clearTempAssetData() -{ } - // static void LLAssetStorage::reportMetric( const LLUUID& asset_id, const LLAssetType::EType asset_type, const std::string& in_filename, - const LLUUID& agent_id, S32 asset_size, EMetricResult result, - const char *file, const S32 line, const std::string& in_message ) -{ - if( !metric_recipient ) - { - LL_DEBUGS("AssetStorage") << "Couldn't store LLAssetStoreage::reportMetric - no metrics_recipient" << LL_ENDL; - return; - } - - std::string filename(in_filename); - if (filename.empty()) - filename = ll_safe_string(file); - - // Create revised message - new_message = "in_message :: file:line" - std::stringstream new_message; - new_message << in_message << " :: " << filename << ":" << line; - - // Change always_report to true if debugging... do not check it in this way - static bool always_report = false; - const char *metric_name = "LLAssetStorage::Metrics"; - - bool success = result == MR_OKAY; - - if( (!success) || always_report ) - { - LLSD stats; - stats["asset_id"] = asset_id; - stats["asset_type"] = asset_type; - stats["filename"] = filename; - stats["agent_id"] = agent_id; - stats["asset_size"] = (S32)asset_size; - stats["result"] = (S32)result; - - metric_recipient->recordEventDetails( metric_name, new_message.str(), success, stats); - } - else - { - metric_recipient->recordEvent(metric_name, new_message.str(), success); - } + const LLUUID& agent_id, S32 asset_size, EMetricResult result, + const char *file, const S32 line, const std::string& in_message ) +{ + if( !metric_recipient ) + { + LL_DEBUGS("AssetStorage") << "Couldn't store LLAssetStoreage::reportMetric - no metrics_recipient" << LL_ENDL; + return; + } + + std::string filename(in_filename); + if (filename.empty()) + filename = ll_safe_string(file); + + // Create revised message - new_message = "in_message :: file:line" + std::stringstream new_message; + new_message << in_message << " :: " << filename << ":" << line; + + // Change always_report to true if debugging... do not check it in this way + static bool always_report = false; + const char *metric_name = "LLAssetStorage::Metrics"; + + bool success = result == MR_OKAY; + + if( (!success) || always_report ) + { + LLSD stats; + stats["asset_id"] = asset_id; + stats["asset_type"] = asset_type; + stats["filename"] = filename; + stats["agent_id"] = agent_id; + stats["asset_size"] = (S32)asset_size; + stats["result"] = (S32)result; + + metric_recipient->recordEventDetails( metric_name, new_message.str(), success, stats); + } + else + { + metric_recipient->recordEvent(metric_name, new_message.str(), success); + } } // Check if an asset is in the toxic map. If it is, the entry is updated -BOOL LLAssetStorage::isAssetToxic( const LLUUID& uuid ) +BOOL LLAssetStorage::isAssetToxic( const LLUUID& uuid ) { - BOOL is_toxic = FALSE; - - if ( !uuid.isNull() ) - { - toxic_asset_map_t::iterator iter = mToxicAssetMap.find( uuid ); - if ( iter != mToxicAssetMap.end() ) - { // Found toxic asset - (*iter).second = LLFrameTimer::getTotalTime() + TOXIC_ASSET_LIFETIME; - is_toxic = TRUE; - } - } - return is_toxic; + BOOL is_toxic = FALSE; + + if ( !uuid.isNull() ) + { + toxic_asset_map_t::iterator iter = mToxicAssetMap.find( uuid ); + if ( iter != mToxicAssetMap.end() ) + { // Found toxic asset + (*iter).second = LLFrameTimer::getTotalTime() + TOXIC_ASSET_LIFETIME; + is_toxic = TRUE; + } + } + return is_toxic; } // Clean the toxic asset list, remove old entries -void LLAssetStorage::flushOldToxicAssets( BOOL force_it ) -{ - // Scan and look for old entries - U64 now = LLFrameTimer::getTotalTime(); - toxic_asset_map_t::iterator iter = mToxicAssetMap.begin(); - while ( iter != mToxicAssetMap.end() ) - { - if ( force_it - || (*iter).second < now ) - { // Too old - remove it - mToxicAssetMap.erase( iter++ ); - } - else - { - iter++; - } - } +void LLAssetStorage::flushOldToxicAssets( BOOL force_it ) +{ + // Scan and look for old entries + U64 now = LLFrameTimer::getTotalTime(); + toxic_asset_map_t::iterator iter = mToxicAssetMap.begin(); + while ( iter != mToxicAssetMap.end() ) + { + if ( force_it + || (*iter).second < now ) + { // Too old - remove it + mToxicAssetMap.erase( iter++ ); + } + else + { + iter++; + } + } } // Add an item to the toxic asset map -void LLAssetStorage::markAssetToxic( const LLUUID& uuid ) -{ - if ( !uuid.isNull() ) - { - // Set the value to the current time. Creates a new entry if needed - mToxicAssetMap[ uuid ] = LLFrameTimer::getTotalTime() + TOXIC_ASSET_LIFETIME; - } +void LLAssetStorage::markAssetToxic( const LLUUID& uuid ) +{ + if ( !uuid.isNull() ) + { + // Set the value to the current time. Creates a new entry if needed + mToxicAssetMap[ uuid ] = LLFrameTimer::getTotalTime() + TOXIC_ASSET_LIFETIME; + } } diff --git a/indra/llmessage/llassetstorage.h b/indra/llmessage/llassetstorage.h index 0f23754096..33b88473b9 100644 --- a/indra/llmessage/llassetstorage.h +++ b/indra/llmessage/llassetstorage.h @@ -138,6 +138,7 @@ public: 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; @@ -186,18 +187,9 @@ typedef std::map<LLUUID,U64,lluuid_less> toxic_asset_map_t; // we can use bind and remove the userData parameter. // typedef void (*LLGetAssetCallback)(LLVFS *vfs, const LLUUID &asset_id, - LLAssetType::EType asset_type, void *user_data, S32 status, LLExtStat ext_status); + LLAssetType::EType asset_type, void *user_data, S32 status, LLExtStat ext_status); -class LLTempAssetStorage -{ -public: - virtual ~LLTempAssetStorage() =0; - virtual void addTempAssetData(const LLUUID& asset_id, - const LLUUID& agent_id, - const std::string& host_name) = 0; -}; - -class LLAssetStorage : public LLTempAssetStorage +class LLAssetStorage { public: // VFS member is public because static child methods need it :( @@ -240,12 +232,11 @@ public: void setUpstream(const LLHost &upstream_host); - virtual BOOL hasLocalAsset(const LLUUID &uuid, LLAssetType::EType type); + BOOL hasLocalAsset(const LLUUID &uuid, LLAssetType::EType type); // public interface methods // note that your callback may get called BEFORE the function returns - - virtual void getAssetData(const LLUUID uuid, LLAssetType::EType atype, LLGetAssetCallback cb, void *user_data, BOOL is_priority = FALSE); + void getAssetData(const LLUUID uuid, LLAssetType::EType atype, LLGetAssetCallback cb, void *user_data, BOOL is_priority = FALSE); /* * TransactionID version @@ -260,25 +251,11 @@ public: bool is_priority = false, bool store_local = false, bool user_waiting= false, - F64Seconds timeout=LL_ASSET_STORAGE_TIMEOUT); - - /* - * AssetID version - * Sim needs both store_local and requesting_agent_id. - */ - virtual void storeAssetData( - const LLUUID& asset_id, - LLAssetType::EType asset_type, - LLStoreAssetCallback callback, - void* user_data, - bool temp_file = false, - bool is_priority = false, - bool store_local = false, - const LLUUID& requesting_agent_id = LLUUID::null, - bool user_waiting= false, - F64Seconds timeout=LL_ASSET_STORAGE_TIMEOUT); + F64Seconds timeout=LL_ASSET_STORAGE_TIMEOUT) = 0; - virtual void checkForTimeouts(); + virtual void logAssetStorageInfo() = 0; + + 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, @@ -303,17 +280,17 @@ protected: bool findInStaticVFSAndInvokeCallback(const LLUUID& uuid, LLAssetType::EType type, LLGetAssetCallback callback, void *user_data); - virtual LLSD getPendingDetailsImpl(const request_list_t* requests, - LLAssetType::EType asset_type, - const std::string& detail_prefix) const; + LLSD getPendingDetailsImpl(const request_list_t* requests, + LLAssetType::EType asset_type, + const std::string& detail_prefix) const; - virtual LLSD getPendingRequestImpl(const request_list_t* requests, - LLAssetType::EType asset_type, - const LLUUID& asset_id) const; + LLSD getPendingRequestImpl(const request_list_t* requests, + LLAssetType::EType asset_type, + const LLUUID& asset_id) const; - virtual bool deletePendingRequestImpl(request_list_t* requests, - LLAssetType::EType asset_type, - const LLUUID& asset_id); + bool deletePendingRequestImpl(request_list_t* requests, + LLAssetType::EType asset_type, + const LLUUID& asset_id); public: static const LLAssetRequest* findRequest(const request_list_t* requests, @@ -332,19 +309,23 @@ public: S32 getNumPendingLocalUploads(); S32 getNumPending(ERequestType rt) const; - virtual LLSD getPendingDetails(ERequestType rt, - LLAssetType::EType asset_type, - const std::string& detail_prefix) const; + LLSD getPendingDetails(ERequestType rt, + LLAssetType::EType asset_type, + const std::string& detail_prefix) const; - virtual LLSD getPendingRequest(ERequestType rt, - LLAssetType::EType asset_type, - const LLUUID& asset_id) const; + LLSD getPendingRequest(ERequestType rt, + LLAssetType::EType asset_type, + const LLUUID& asset_id) const; - virtual bool deletePendingRequest(ERequestType rt, - LLAssetType::EType asset_type, - const LLUUID& asset_id); + 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); + // download process callbacks static void downloadCompleteCallback( S32 result, @@ -370,23 +351,10 @@ public: 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); /* - * AssetID version. - */ - virtual void storeAssetData( - const std::string& filename, - const LLUUID& asset_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); - - /* * TransactionID version */ virtual void storeAssetData( @@ -398,23 +366,11 @@ public: bool temp_file = false, bool is_priority = false, bool user_waiting = false, - F64Seconds timeout = LL_ASSET_STORAGE_TIMEOUT); + F64Seconds timeout = LL_ASSET_STORAGE_TIMEOUT) = 0; static void legacyGetDataCallback(LLVFS *vfs, 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); - // Temp assets are stored on sim nodes, they have agent ID and location data associated with them. - // This is a no-op for non-http asset systems - virtual void addTempAssetData(const LLUUID& asset_id, const LLUUID& agent_id, const std::string& host_name); - virtual BOOL hasTempAssetData(const LLUUID& texture_id) const; - virtual std::string getTempAssetHostName(const LLUUID& texture_id) const; - virtual LLUUID getTempAssetAgentID(const LLUUID& texture_id) const; - virtual void removeTempAssetData(const LLUUID& asset_id); - virtual void removeTempAssetDataByAgentID(const LLUUID& agent_id); - // Pass LLUUID::null for all - virtual void dumpTempAssetData(const LLUUID& avatar_id) const; - virtual void clearTempAssetData(); - // add extra methods to handle metadata protected: @@ -424,7 +380,7 @@ protected: virtual void _queueDataRequest(const LLUUID& uuid, LLAssetType::EType type, void (*callback)(LLVFS *vfs, const LLUUID&, LLAssetType::EType, void *, S32, LLExtStat), void *user_data, BOOL duplicate, - BOOL is_priority); + BOOL is_priority) = 0; private: void _init(LLMessageSystem *msg, diff --git a/indra/llmessage/llavatarname.cpp b/indra/llmessage/llavatarname.cpp index d2115ee499..7e1246f885 100644 --- a/indra/llmessage/llavatarname.cpp +++ b/indra/llmessage/llavatarname.cpp @@ -166,10 +166,10 @@ void LLAvatarName::setExpires(F64 expires) mExpires = LLFrameTimer::getTotalSeconds() + expires; } -std::string LLAvatarName::getCompleteName(bool use_parentheses) const +std::string LLAvatarName::getCompleteName(bool use_parentheses, bool force_use_complete_name) const { std::string name; - if (sUseDisplayNames) + if (sUseDisplayNames || force_use_complete_name) { if (mUsername.empty() || mIsDisplayNameDefault) { @@ -180,7 +180,7 @@ std::string LLAvatarName::getCompleteName(bool use_parentheses) const else { name = mDisplayName; - if(sUseUsernames) + if(sUseUsernames || force_use_complete_name) { if(use_parentheses) { @@ -215,9 +215,9 @@ std::string LLAvatarName::getLegacyName() const return name; } -std::string LLAvatarName::getDisplayName() const +std::string LLAvatarName::getDisplayName(bool force_use_display_name) const { - if (sUseDisplayNames) + if (sUseDisplayNames || force_use_display_name) { return mDisplayName; } diff --git a/indra/llmessage/llavatarname.h b/indra/llmessage/llavatarname.h index 192f43f07c..20f7140797 100644 --- a/indra/llmessage/llavatarname.h +++ b/indra/llmessage/llavatarname.h @@ -65,7 +65,7 @@ public: // For normal names, returns "James Linden (james.linden)" // When display names are disabled returns just "James Linden" - std::string getCompleteName(bool use_parentheses = true) const; + 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 @@ -75,7 +75,7 @@ public: // "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() const; + 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 diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp index 004db546b7..5a112b5432 100644 --- a/indra/llmessage/llavatarnamecache.cpp +++ b/indra/llmessage/llavatarnamecache.cpp @@ -755,6 +755,28 @@ void LLAvatarNameCache::insert(const LLUUID& agent_id, const LLAvatarName& av_na sCache[agent_id] = av_name; } +LLUUID LLAvatarNameCache::findIdByName(const std::string& name) +{ + std::map<LLUUID, LLAvatarName>::iterator it; + std::map<LLUUID, LLAvatarName>::iterator end = sCache.end(); + for (it = sCache.begin(); it != end; ++it) + { + if (it->second.getUserName() == name) + { + return it->first; + } + } + + // Legacy method + LLUUID id; + if (gCacheName->getUUID(name, id)) + { + return id; + } + + return LLUUID::null; +} + #if 0 F64 LLAvatarNameCache::nameExpirationFromHeaders(LLCore::HttpHeaders *headers) { diff --git a/indra/llmessage/llavatarnamecache.h b/indra/llmessage/llavatarnamecache.h index bd2715e956..63e067c939 100644 --- a/indra/llmessage/llavatarnamecache.h +++ b/indra/llmessage/llavatarnamecache.h @@ -84,7 +84,15 @@ namespace LLAvatarNameCache void insert(const LLUUID& agent_id, const LLAvatarName& av_name); void erase(const LLUUID& agent_id); - /// Provide some fallback for agents that return errors. + // 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); // Compute name expiration time from HTTP Cache-Control header, diff --git a/indra/llmessage/llcoproceduremanager.h b/indra/llmessage/llcoproceduremanager.h index 497367b80c..7d0e83180c 100644 --- a/indra/llmessage/llcoproceduremanager.h +++ b/indra/llmessage/llcoproceduremanager.h @@ -37,7 +37,8 @@ class LLCoprocedurePool; class LLCoprocedureManager : public LLSingleton < LLCoprocedureManager > { - friend class LLSingleton < LLCoprocedureManager > ; + LLSINGLETON(LLCoprocedureManager); + virtual ~LLCoprocedureManager(); public: typedef boost::function<U32(const std::string &)> SettingQuery_t; @@ -45,9 +46,6 @@ public: typedef boost::function<void(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &, const LLUUID &id)> CoProcedure_t; - LLCoprocedureManager(); - virtual ~LLCoprocedureManager(); - /// Places the coprocedure on the queue for processing. /// /// @param name Is used for debugging and should identify this coroutine. diff --git a/indra/llmessage/llexperiencecache.cpp b/indra/llmessage/llexperiencecache.cpp index 779d1d9d99..aa7b3c1260 100644 --- a/indra/llmessage/llexperiencecache.cpp +++ b/indra/llmessage/llexperiencecache.cpp @@ -540,18 +540,34 @@ void LLExperienceCache::fetchAssociatedExperience(const LLUUID& objectId, const } LLCoprocedureManager::instance().enqueueCoprocedure("ExpCache", "Fetch Associated", - boost::bind(&LLExperienceCache::fetchAssociatedExperienceCoro, this, _1, objectId, itemId, fn)); + boost::bind(&LLExperienceCache::fetchAssociatedExperienceCoro, this, _1, objectId, itemId, std::string(), fn)); } -void LLExperienceCache::fetchAssociatedExperienceCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter, LLUUID objectId, LLUUID itemId, ExperienceGetFn_t fn) +void LLExperienceCache::fetchAssociatedExperience(const LLUUID& objectId, const LLUUID& itemId, std::string url, ExperienceGetFn_t fn) +{ + if (mCapability.empty()) + { + LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL; + return; + } + + LLCoprocedureManager::instance().enqueueCoprocedure("ExpCache", "Fetch Associated", + boost::bind(&LLExperienceCache::fetchAssociatedExperienceCoro, this, _1, objectId, itemId, url, fn)); +} + +void LLExperienceCache::fetchAssociatedExperienceCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter, LLUUID objectId, LLUUID itemId, std::string url, ExperienceGetFn_t fn) { LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest()); - std::string url = mCapability("GetMetadata"); if (url.empty()) { - LL_WARNS("ExperienceCache") << "No Metadata capability." << LL_ENDL; - return; + url = mCapability("GetMetadata"); + + if (url.empty()) + { + LL_WARNS("ExperienceCache") << "No Metadata capability." << LL_ENDL; + return; + } } LLSD fields; diff --git a/indra/llmessage/llexperiencecache.h b/indra/llmessage/llexperiencecache.h index 1002b33f80..f9ff69c2b6 100644 --- a/indra/llmessage/llexperiencecache.h +++ b/indra/llmessage/llexperiencecache.h @@ -43,7 +43,7 @@ class LLUUID; class LLExperienceCache: public LLSingleton < LLExperienceCache > { - friend class LLSingleton < LLExperienceCache > ; + LLSINGLETON(LLExperienceCache); public: typedef boost::function<std::string(const std::string &)> CapabilityQuery_t; @@ -64,6 +64,7 @@ public: //------------------------------------------- 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); @@ -103,7 +104,6 @@ public: static const int PROPERTY_SUSPENDED; // 1 << 7 private: - LLExperienceCache(); virtual ~LLExperienceCache(); virtual void initSingleton(); @@ -149,7 +149,7 @@ private: void requestExperiencesCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &, std::string, RequestQueue_t); void requestExperiences(); - void fetchAssociatedExperienceCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &, LLUUID, LLUUID, ExperienceGetFn_t); + 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); diff --git a/indra/llmessage/llproxy.h b/indra/llmessage/llproxy.h index bd23dd39de..688dff7c83 100644 --- a/indra/llmessage/llproxy.h +++ b/indra/llmessage/llproxy.h @@ -218,14 +218,14 @@ enum LLSocks5AuthType */ class LLProxy: public LLSingleton<LLProxy> { - LOG_CLASS(LLProxy); -public: /*########################################################################################### METHODS THAT DO NOT LOCK mProxyMutex! ###########################################################################################*/ // Constructor, cannot have parameters due to LLSingleton parent class. Call from main thread only. - LLProxy(); + LLSINGLETON(LLProxy); + LOG_CLASS(LLProxy); +public: // Static check for enabled status for UDP packets. Call from main thread only. static bool isSOCKSProxyEnabled() { return sUDPProxyEnabled; } @@ -239,9 +239,11 @@ public: /*########################################################################################### 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(); diff --git a/indra/llmessage/llregionflags.h b/indra/llmessage/llregionflags.h index eb0c4e6d1e..d3791ef4d1 100644 --- a/indra/llmessage/llregionflags.h +++ b/indra/llmessage/llregionflags.h @@ -42,6 +42,9 @@ const U64 REGION_FLAGS_RESET_HOME_ON_TELEPORT = (1 << 3); // Does the sun move? const U64 REGION_FLAGS_SUN_FIXED = (1 << 4); +// Does the estate owner allow private parcels? +const U64 REGION_FLAGS_ALLOW_ACCESS_OVERRIDE = (1 << 5); + // Can't change the terrain heightfield, even on owned parcels, // but can plant trees and grass. const U64 REGION_FLAGS_BLOCK_TERRAFORM = (1 << 6); diff --git a/indra/llmessage/lltemplatemessagereader.cpp b/indra/llmessage/lltemplatemessagereader.cpp index 406afadd2f..4e0c53c37e 100644 --- a/indra/llmessage/lltemplatemessagereader.cpp +++ b/indra/llmessage/lltemplatemessagereader.cpp @@ -499,9 +499,10 @@ BOOL LLTemplateMessageReader::decodeTemplate( } else { - LL_WARNS() << "Message #" << std::hex << num << std::dec - << " received but not registered!" << LL_ENDL; - gMessageSystem->callExceptionFunc(MX_UNREGISTERED_MESSAGE); + // MAINT-7482 - make viewer more tolerant of unknown messages. + LL_WARNS_ONCE() << "Message #" << std::hex << num << std::dec + << " received but not registered!" << LL_ENDL; + //gMessageSystem->callExceptionFunc(MX_UNREGISTERED_MESSAGE); return(FALSE); } diff --git a/indra/llmessage/llxfer_file.cpp b/indra/llmessage/llxfer_file.cpp index 257a13f277..8e2ed890e7 100644 --- a/indra/llmessage/llxfer_file.cpp +++ b/indra/llmessage/llxfer_file.cpp @@ -98,12 +98,12 @@ void LLXfer_File::cleanup () mFp = NULL; } - LLFile::remove(mTempFilename); + LLFile::remove(mTempFilename, ENOENT); if (mDeleteLocalOnCompletion) { LL_DEBUGS() << "Removing file: " << mLocalFilename << LL_ENDL; - LLFile::remove(mLocalFilename); + LLFile::remove(mLocalFilename, ENOENT); } else { @@ -321,7 +321,7 @@ S32 LLXfer_File::processEOF() mCallbackResult = flushval; } - LLFile::remove(mLocalFilename); + LLFile::remove(mLocalFilename, ENOENT); if (!mCallbackResult) { diff --git a/indra/llmessage/llxfermanager.cpp b/indra/llmessage/llxfermanager.cpp index 272dbbc785..2ceb64ce8f 100644 --- a/indra/llmessage/llxfermanager.cpp +++ b/indra/llmessage/llxfermanager.cpp @@ -444,7 +444,7 @@ U64 LLXferManager::requestFile(const std::string& local_filename, && (remote_filename.substr(remote_filename.length()-4) == ".tmp") && gDirUtilp->fileExists(local_filename)) { - LLFile::remove(local_filename); + LLFile::remove(local_filename, ENOENT); } xfer_id = getNextID(); ((LLXfer_File *)xferp)->initializeRequest( diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp index 290b67feb3..6ef4025ab1 100644 --- a/indra/llmessage/message.cpp +++ b/indra/llmessage/message.cpp @@ -76,6 +76,7 @@ #include "v4math.h" #include "lltransfertargetvfile.h" #include "llcorehttputil.h" +#include "llpounceable.h" // Constants //const char* MESSAGE_LOG_FILENAME = "message.log"; @@ -1724,7 +1725,9 @@ std::ostream& operator<<(std::ostream& s, LLMessageSystem &msg) return s; } -LLMessageSystem *gMessageSystem = NULL; +// LLPounceable supports callWhenReady(), to permit clients to queue up (e.g.) +// callback registrations for when gMessageSystem is first assigned +LLPounceable<LLMessageSystem*, LLPounceableStatic> gMessageSystem; // update appropriate ping info void process_complete_ping_check(LLMessageSystem *msgsystem, void** /*user_data*/) @@ -2641,7 +2644,7 @@ void end_messaging_system(bool print_summary) LL_INFOS("Messaging") << str.str().c_str() << LL_ENDL; } - delete gMessageSystem; + delete static_cast<LLMessageSystem*>(gMessageSystem); gMessageSystem = NULL; } } diff --git a/indra/llmessage/message.h b/indra/llmessage/message.h index 133db620e6..f6c5d9e228 100644 --- a/indra/llmessage/message.h +++ b/indra/llmessage/message.h @@ -60,6 +60,7 @@ #include "llstoredmessage.h" #include "boost/function.hpp" +#include "llpounceable.h" const U32 MESSAGE_MAX_STRINGS_LENGTH = 64; const U32 MESSAGE_NUMBER_OF_HASH_BUCKETS = 8192; @@ -68,10 +69,10 @@ const S32 MESSAGE_MAX_PER_FRAME = 400; class LLMessageStringTable : public LLSingleton<LLMessageStringTable> { -public: - LLMessageStringTable(); + LLSINGLETON(LLMessageStringTable); ~LLMessageStringTable(); +public: char *getString(const char *str); U32 mUsed; @@ -832,7 +833,7 @@ private: // external hook into messaging system -extern LLMessageSystem *gMessageSystem; +extern LLPounceable<LLMessageSystem*, LLPounceableStatic> gMessageSystem; // Must specific overall system version, which is used to determine // if a patch is available in the message template checksum verification. diff --git a/indra/llmessage/message_prehash.cpp b/indra/llmessage/message_prehash.cpp index 5c6b3d5fab..1ae8a6ac15 100644 --- a/indra/llmessage/message_prehash.cpp +++ b/indra/llmessage/message_prehash.cpp @@ -618,6 +618,7 @@ char const* const _PREHASH_GroupAccountSummaryRequest = LLMessageStringTable::ge char const* const _PREHASH_GroupVoteHistoryRequest = LLMessageStringTable::getInstance()->getString("GroupVoteHistoryRequest"); char const* const _PREHASH_ParamValue = LLMessageStringTable::getInstance()->getString("ParamValue"); char const* const _PREHASH_MaxAgents = LLMessageStringTable::getInstance()->getString("MaxAgents"); +char const* const _PREHASH_HardMaxAgents = LLMessageStringTable::getInstance()->getString("HardMaxAgents"); char const* const _PREHASH_CreateNewOutfitAttachments = LLMessageStringTable::getInstance()->getString("CreateNewOutfitAttachments"); char const* const _PREHASH_RegionHandle = LLMessageStringTable::getInstance()->getString("RegionHandle"); char const* const _PREHASH_TeleportProgress = LLMessageStringTable::getInstance()->getString("TeleportProgress"); @@ -1372,6 +1373,9 @@ char const* const _PREHASH_OwnerMask = LLMessageStringTable::getInstance()->getS char const* const _PREHASH_TransferInventoryAck = LLMessageStringTable::getInstance()->getString("TransferInventoryAck"); char const* const _PREHASH_RegionDenyAgeUnverified = LLMessageStringTable::getInstance()->getString("RegionDenyAgeUnverified"); char const* const _PREHASH_AgeVerificationBlock = LLMessageStringTable::getInstance()->getString("AgeVerificationBlock"); +char const* const _PREHASH_RegionAllowAccessBlock = LLMessageStringTable::getInstance()->getString("RegionAllowAccessBlock"); +char const* const _PREHASH_RegionAllowAccessOverride = LLMessageStringTable::getInstance()->getString("RegionAllowAccessOverride"); + char const* const _PREHASH_UCoord = LLMessageStringTable::getInstance()->getString("UCoord"); char const* const _PREHASH_VCoord = LLMessageStringTable::getInstance()->getString("VCoord"); char const* const _PREHASH_FaceIndex = LLMessageStringTable::getInstance()->getString("FaceIndex"); diff --git a/indra/llmessage/message_prehash.h b/indra/llmessage/message_prehash.h index e696c3b0ca..7910fde305 100644 --- a/indra/llmessage/message_prehash.h +++ b/indra/llmessage/message_prehash.h @@ -618,6 +618,7 @@ extern char const* const _PREHASH_GroupAccountSummaryRequest; extern char const* const _PREHASH_GroupVoteHistoryRequest; extern char const* const _PREHASH_ParamValue; extern char const* const _PREHASH_MaxAgents; +extern char const* const _PREHASH_HardMaxAgents; extern char const* const _PREHASH_CreateNewOutfitAttachments; extern char const* const _PREHASH_RegionHandle; extern char const* const _PREHASH_TeleportProgress; @@ -1372,6 +1373,8 @@ extern char const* const _PREHASH_OwnerMask; extern char const* const _PREHASH_TransferInventoryAck; extern char const* const _PREHASH_RegionDenyAgeUnverified; extern char const* const _PREHASH_AgeVerificationBlock; +extern char const* const _PREHASH_RegionAllowAccessBlock; +extern char const* const _PREHASH_RegionAllowAccessOverride; extern char const* const _PREHASH_UCoord; extern char const* const _PREHASH_VCoord; extern char const* const _PREHASH_FaceIndex; diff --git a/indra/llmessage/tests/llhttpclient_test.cpp b/indra/llmessage/tests/llhttpclient_test.cpp index a32bfa59ce..9356a14f1f 100644 --- a/indra/llmessage/tests/llhttpclient_test.cpp +++ b/indra/llmessage/tests/llhttpclient_test.cpp @@ -42,6 +42,7 @@ #include "lliosocket.h" #include "stringize.h" +#include "llcleanup.h" namespace tut { @@ -66,7 +67,7 @@ namespace tut ~HTTPClientTestData() { delete mClientPump; - LLProxy::cleanupClass(); + SUBSYSTEM_CLEANUP(LLProxy); apr_pool_destroy(mPool); } diff --git a/indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp b/indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp index 3b04530c1a..e20f61b73f 100644 --- a/indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp +++ b/indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp @@ -31,11 +31,12 @@ #include "llhost.h" #include "message.h" #include "llsd.h" +#include "llpounceable.h" #include "llhost.cpp" // Needed for copy operator #include "net.cpp" // Needed by LLHost. -LLMessageSystem * gMessageSystem = NULL; +LLPounceable<LLMessageSystem*, LLPounceableStatic> gMessageSystem; // sensor test doubles bool gClearRecvWasCalled = false; diff --git a/indra/llmessage/tests/lltrustedmessageservice_test.cpp b/indra/llmessage/tests/lltrustedmessageservice_test.cpp index 55748ad27e..41f982a7e2 100644 --- a/indra/llmessage/tests/lltrustedmessageservice_test.cpp +++ b/indra/llmessage/tests/lltrustedmessageservice_test.cpp @@ -33,8 +33,9 @@ #include "message.h" #include "llmessageconfig.h" #include "llhttpnode_stub.cpp" +#include "llpounceable.h" -LLMessageSystem* gMessageSystem = NULL; +LLPounceable<LLMessageSystem*, LLPounceableStatic> gMessageSystem; LLMessageConfig::SenderTrust LLMessageConfig::getSenderTrustedness(const std::string& msg_name) diff --git a/indra/llmessage/tests/networkio.h b/indra/llmessage/tests/networkio.h index 5eb739393f..5986524342 100644 --- a/indra/llmessage/tests/networkio.h +++ b/indra/llmessage/tests/networkio.h @@ -44,7 +44,7 @@ // init time. Use the lazy, on-demand initialization we get from LLSingleton. class NetworkIO: public LLSingleton<NetworkIO> { -public: + LLSINGLETON(NetworkIO); NetworkIO(): mServicePump(NULL), mDone(false) @@ -69,6 +69,7 @@ public: boost::bind(&NetworkIO::done, this, _1)); } +public: bool pump(F32 timeout=10) { // Reset the done flag so we don't pop out prematurely diff --git a/indra/llmessage/tests/test_llsdmessage_peer.py b/indra/llmessage/tests/test_llsdmessage_peer.py index bac18fa374..9cd2959ea1 100755 --- a/indra/llmessage/tests/test_llsdmessage_peer.py +++ b/indra/llmessage/tests/test_llsdmessage_peer.py @@ -31,7 +31,6 @@ $/LicenseInfo$ import os import sys -from threading import Thread from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler from llbase.fastest_elementtree import parse as xml_parse @@ -155,17 +154,23 @@ class Server(HTTPServer): allow_reuse_address = False if __name__ == "__main__": - # Instantiate a Server(TestHTTPRequestHandler) on the first free port - # in the specified port range. Doing this inline is better than in a - # daemon thread: if it blows up here, we'll get a traceback. If it blew up - # in some other thread, the traceback would get eaten and we'd run the - # subject test program anyway. - httpd, port = freeport(xrange(8000, 8020), - lambda port: Server(('127.0.0.1', port), TestHTTPRequestHandler)) + # function to make a server with specified port + make_server = lambda port: Server(('127.0.0.1', port), TestHTTPRequestHandler) + + if not sys.platform.startswith("win"): + # Instantiate a Server(TestHTTPRequestHandler) on a port chosen by the + # runtime. + httpd = make_server(0) + else: + # "Then there's Windows" + # Instantiate a Server(TestHTTPRequestHandler) on the first free port + # in the specified port range. + httpd, port = freeport(xrange(8000, 8020), make_server) + # Pass the selected port number to the subject test program via the # environment. We don't want to impose requirements on the test program's # command-line parsing -- and anyway, for C++ integration tests, that's # performed in TUT code rather than our own. - os.environ["PORT"] = str(port) - debug("$PORT = %s", port) - sys.exit(run(server=Thread(name="httpd", target=httpd.serve_forever), *sys.argv[1:])) + os.environ["PORT"] = str(httpd.server_port) + debug("$PORT = %s", httpd.server_port) + sys.exit(run(server_inst=httpd, *sys.argv[1:])) diff --git a/indra/llmessage/tests/testrunner.py b/indra/llmessage/tests/testrunner.py index 5b9beb359b..c25945067e 100755 --- a/indra/llmessage/tests/testrunner.py +++ b/indra/llmessage/tests/testrunner.py @@ -27,13 +27,12 @@ Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA $/LicenseInfo$ """ -from __future__ import with_statement - import os import sys import re import errno import socket +import subprocess VERBOSE = os.environ.get("INTEGRATION_TEST_VERBOSE", "0") # default to quiet # Support usage such as INTEGRATION_TEST_VERBOSE=off -- distressing to user if @@ -47,6 +46,9 @@ if VERBOSE: else: debug = lambda *args: None +class Error(Exception): + pass + def freeport(portlist, expr): """ Find a free server port to use. Specifically, evaluate 'expr' (a @@ -141,34 +143,73 @@ def freeport(portlist, expr): raise def run(*args, **kwds): - """All positional arguments collectively form a command line, executed as - a synchronous child process. - In addition, pass server=new_thread_instance as an explicit keyword (to - differentiate it from an additional command-line argument). - new_thread_instance should be an instantiated but not yet started Thread - subclass instance, e.g.: - run("python", "-c", 'print "Hello, world!"', server=TestHTTPServer(name="httpd")) """ - # If there's no server= keyword arg, don't start a server thread: simply - # run a child process. + Run a specified command as a synchronous child process, optionally + launching a server Thread during the run. + + All positional arguments collectively form a command line. The first + positional argument names the program file to execute. + + Returns the termination code of the child process. + + In addition, you may pass keyword-only arguments: + + use_path=True: allow a simple filename as command and search PATH for that + filename. (This argument is retained for backwards compatibility but is + now the default behavior.) + + server_inst: an instance of a subclass of SocketServer.BaseServer. + + When you pass server_inst, run() calls its handle_request() method in a + loop until the child process terminates. + """ + # server= keyword arg is discontinued try: thread = kwds.pop("server") except KeyError: pass else: - # Start server thread. Note that this and all other comm server - # threads should be daemon threads: we'll let them run "forever," - # confident that the whole process will terminate when the main thread - # terminates, which will be when the child process terminates. - thread.setDaemon(True) - thread.start() - # choice of os.spawnv(): - # - [v vs. l] pass a list of args vs. individual arguments, - # - [no p] don't use the PATH because we specifically want to invoke the - # executable passed as our first arg, - # - [no e] child should inherit this process's environment. + raise Error("Obsolete call to testrunner.run(): pass server_inst=, not server=") + debug("Running %s...", " ".join(args)) - rc = os.spawnv(os.P_WAIT, args[0], args) + + try: + server_inst = kwds.pop("server_inst") + except KeyError: + # Without server_inst, this is very simple: just run child process. + rc = subprocess.call(args) + else: + # We're being asked to run a local server while the child process + # runs. We used to launch a daemon thread calling + # server_inst.serve_forever(), then eventually call sys.exit() with + # the daemon thread still running -- but in recent versions of Python + # 2, even when you call sys.exit(0), apparently killing the thread + # causes the Python runtime to force the process termination code + # nonzero. So now we avoid the extra thread altogether. + + # SocketServer.BaseServer.handle_request() honors a 'timeout' + # attribute, if it's set to something other than None. + # We pick 0.5 seconds because that's the default poll timeout for + # BaseServer.serve_forever(), which is what we used to use. + server_inst.timeout = 0.5 + + child = subprocess.Popen(args) + while child.poll() is None: + # Setting server_inst.timeout is what keeps this handle_request() + # call from blocking "forever." Interestingly, looping over + # handle_request() with a timeout is very like the implementation + # of serve_forever(). We just check a different flag to break out. + # It might be interesting if handle_request() returned an + # indication of whether it in fact handled a request or timed out. + # Oddly, it doesn't. We could discover that by overriding + # handle_timeout(), whose default implementation does nothing -- + # but in fact we really don't care. All that matters is that we + # regularly poll both the child process and the server socket. + server_inst.handle_request() + # We don't bother to capture the rc returned by child.poll() because + # poll() is already defined to capture that in its returncode attr. + rc = child.returncode + debug("%s returned %s", args[0], rc) return rc |