00001
00032 #include "linden_common.h"
00033
00034
00035 #include <sys/types.h>
00036 #include <sys/stat.h>
00037
00038 #include "llassetstorage.h"
00039
00040
00041 #include "llmath.h"
00042 #include "llstring.h"
00043 #include "lldir.h"
00044 #include "llsd.h"
00045
00046
00047 #include "message.h"
00048 #include "llxfermanager.h"
00049 #include "llvfile.h"
00050 #include "llvfs.h"
00051 #include "lldbstrings.h"
00052
00053 #include "lltransfersourceasset.h"
00054 #include "lltransfertargetvfile.h"
00055
00056 LLAssetStorage *gAssetStorage = NULL;
00057
00058 const LLUUID CATEGORIZE_LOST_AND_FOUND_ID("00000000-0000-0000-0000-000000000010");
00059
00063
00064 LLAssetInfo::LLAssetInfo( void )
00065 : mDescription(),
00066 mName(),
00067 mUuid(),
00068 mCreatorID(),
00069 mType( LLAssetType::AT_NONE )
00070 { }
00071
00072 LLAssetInfo::LLAssetInfo( const LLUUID& object_id, const LLUUID& creator_id,
00073 LLAssetType::EType type, const char* name,
00074 const char* desc )
00075 : mUuid( object_id ),
00076 mCreatorID( creator_id ),
00077 mType( type )
00078 {
00079 setName( name );
00080 setDescription( desc );
00081 }
00082
00083 LLAssetInfo::LLAssetInfo( const LLNameValue& nv )
00084 {
00085 setFromNameValue( nv );
00086 }
00087
00088
00089
00090 void LLAssetInfo::setName( const std::string& name )
00091 {
00092 if( !name.empty() )
00093 {
00094 mName.assign( name, 0, llmin((U32)name.size(), (U32)DB_INV_ITEM_NAME_STR_LEN) );
00095 mName.erase( std::remove(mName.begin(), mName.end(), '|'),
00096 mName.end() );
00097 }
00098 }
00099
00100
00101
00102 void LLAssetInfo::setDescription( const std::string& desc )
00103 {
00104 if( !desc.empty() )
00105 {
00106 mDescription.assign( desc, 0, llmin((U32)desc.size(),
00107 (U32)DB_INV_ITEM_DESC_STR_LEN) );
00108 mDescription.erase( std::remove(mDescription.begin(),
00109 mDescription.end(), '|'),
00110 mDescription.end() );
00111 }
00112 }
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122 void LLAssetInfo::setFromNameValue( const LLNameValue& nv )
00123 {
00124 std::string str;
00125 std::string buf;
00126 std::string::size_type pos1;
00127 std::string::size_type pos2;
00128
00129
00130 str.assign( nv.mName );
00131 pos1 = str.find('|');
00132 buf.assign( str, 0, pos1++ );
00133 mType = LLAssetType::lookup( buf.c_str() );
00134 buf.assign( str, pos1, std::string::npos );
00135 mUuid.set( buf.c_str() );
00136
00137
00138 str.assign( nv.getAsset() );
00139 pos1 = str.find('|');
00140 buf.assign( str, 0, pos1++ );
00141 mCreatorID.set( buf.c_str() );
00142 pos2 = str.find( '|', pos1 );
00143 buf.assign( str, pos1, (pos2++) - pos1 );
00144 setName( buf.c_str() );
00145 buf.assign( str, pos2, std::string::npos );
00146 setDescription( buf.c_str() );
00147 llinfos << "uuid: " << mUuid << llendl;
00148 llinfos << "creator: " << mCreatorID << llendl;
00149 }
00150
00154
00155 LLAssetRequest::LLAssetRequest(const LLUUID &uuid, const LLAssetType::EType type)
00156 : mUUID(uuid),
00157 mType(type),
00158 mDownCallback( NULL ),
00159 mUpCallback( NULL ),
00160 mInfoCallback( NULL ),
00161 mUserData( NULL ),
00162 mHost(),
00163 mIsTemp( FALSE ),
00164 mIsLocal(FALSE),
00165 mIsUserWaiting(FALSE),
00166 mTimeout(LL_ASSET_STORAGE_TIMEOUT),
00167 mIsPriority(FALSE),
00168 mDataSentInFirstPacket(FALSE),
00169 mDataIsInVFS( FALSE )
00170 {
00171
00172
00173 mTime = LLMessageSystem::getMessageTimeSeconds(TRUE);
00174 }
00175
00176
00177 LLAssetRequest::~LLAssetRequest()
00178 {
00179 }
00180
00181
00182 LLSD LLAssetRequest::getTerseDetails() const
00183 {
00184 LLSD sd;
00185 sd["asset_id"] = getUUID();
00186 sd["type_long"] = LLAssetType::lookupHumanReadable(getType());
00187 sd["type"] = LLAssetType::lookup(getType());
00188 sd["time"] = mTime;
00189 time_t timestamp = (time_t) mTime;
00190 std::ostringstream time_string;
00191 time_string << ctime(×tamp);
00192 sd["time_string"] = time_string.str();
00193 return sd;
00194 }
00195
00196
00197 LLSD LLAssetRequest::getFullDetails() const
00198 {
00199 LLSD sd = getTerseDetails();
00200 sd["host"] = mHost.getIPandPort();
00201 sd["requesting_agent"] = mRequestingAgentID;
00202 sd["is_temp"] = mIsTemp;
00203 sd["is_local"] = mIsLocal;
00204 sd["is_priority"] = mIsPriority;
00205 sd["data_send_in_first_packet"] = mDataSentInFirstPacket;
00206 sd["data_is_in_vfs"] = mDataIsInVFS;
00207
00208 return sd;
00209 }
00210
00214
00215 LLInvItemRequest::LLInvItemRequest(const LLUUID &uuid, const LLAssetType::EType type)
00216 : mUUID(uuid),
00217 mType(type),
00218 mDownCallback( NULL ),
00219 mUserData( NULL ),
00220 mHost(),
00221 mIsTemp( FALSE ),
00222 mIsPriority(FALSE),
00223 mDataSentInFirstPacket(FALSE),
00224 mDataIsInVFS( FALSE )
00225 {
00226
00227
00228 mTime = LLMessageSystem::getMessageTimeSeconds(TRUE);
00229 }
00230
00231 LLInvItemRequest::~LLInvItemRequest()
00232 {
00233 }
00234
00238
00239 LLEstateAssetRequest::LLEstateAssetRequest(const LLUUID &uuid, const LLAssetType::EType atype,
00240 EstateAssetType etype)
00241 : mUUID(uuid),
00242 mAType(atype),
00243 mEstateAssetType(etype),
00244 mDownCallback( NULL ),
00245 mUserData( NULL ),
00246 mHost(),
00247 mIsTemp( FALSE ),
00248 mIsPriority(FALSE),
00249 mDataSentInFirstPacket(FALSE),
00250 mDataIsInVFS( FALSE )
00251 {
00252
00253
00254 mTime = LLMessageSystem::getMessageTimeSeconds(TRUE);
00255 }
00256
00257 LLEstateAssetRequest::~LLEstateAssetRequest()
00258 {
00259 }
00260
00261
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275 LLAssetStorage::LLAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, LLVFS *vfs, const LLHost &upstream_host)
00276 {
00277 _init(msg, xfer, vfs, upstream_host);
00278 }
00279
00280
00281 LLAssetStorage::LLAssetStorage(LLMessageSystem *msg, LLXferManager *xfer,
00282 LLVFS *vfs)
00283 {
00284 _init(msg, xfer, vfs, LLHost::invalid);
00285 }
00286
00287
00288 void LLAssetStorage::_init(LLMessageSystem *msg,
00289 LLXferManager *xfer,
00290 LLVFS *vfs,
00291 const LLHost &upstream_host)
00292 {
00293 mShutDown = FALSE;
00294 mMessageSys = msg;
00295 mXferManager = xfer;
00296 mVFS = vfs;
00297
00298 setUpstream(upstream_host);
00299 msg->setHandlerFuncFast(_PREHASH_AssetUploadComplete, processUploadComplete, (void **)this);
00300 }
00301
00302 LLAssetStorage::~LLAssetStorage()
00303 {
00304 mShutDown = TRUE;
00305
00306 _cleanupRequests(TRUE, LL_ERR_CIRCUIT_GONE);
00307
00308 if (gMessageSystem)
00309 {
00310
00311
00312 gMessageSystem->setHandlerFuncFast(_PREHASH_AssetUploadComplete, NULL, NULL);
00313 }
00314 }
00315
00316 void LLAssetStorage::setUpstream(const LLHost &upstream_host)
00317 {
00318 llinfos << "AssetStorage: Setting upstream provider to " << upstream_host << llendl;
00319
00320 mUpstreamHost = upstream_host;
00321 }
00322
00323 void LLAssetStorage::checkForTimeouts()
00324 {
00325 _cleanupRequests(FALSE, LL_ERR_TCP_TIMEOUT);
00326 }
00327
00328 void LLAssetStorage::_cleanupRequests(BOOL all, S32 error)
00329 {
00330 F64 mt_secs = LLMessageSystem::getMessageTimeSeconds();
00331
00332 request_list_t timed_out;
00333 S32 rt;
00334 for (rt = 0; rt < RT_COUNT; rt++)
00335 {
00336 request_list_t* requests = getRequestList((ERequestType)rt);
00337 for (request_list_t::iterator iter = requests->begin();
00338 iter != requests->end(); )
00339 {
00340 request_list_t::iterator curiter = iter++;
00341 LLAssetRequest* tmp = *curiter;
00342
00343
00344
00345 if (all
00346 || ((RT_DOWNLOAD == rt)
00347 && LL_ASSET_STORAGE_TIMEOUT < (mt_secs - tmp->mTime)))
00348 {
00349 llwarns << "Asset " << getRequestName((ERequestType)rt) << " request "
00350 << (all ? "aborted" : "timed out") << " for "
00351 << tmp->getUUID() << "."
00352 << LLAssetType::lookup(tmp->getType()) << llendl;
00353
00354 timed_out.push_front(tmp);
00355 iter = requests->erase(curiter);
00356 }
00357 }
00358 }
00359
00360 LLAssetInfo info;
00361 for (request_list_t::iterator iter = timed_out.begin();
00362 iter != timed_out.end(); )
00363 {
00364 request_list_t::iterator curiter = iter++;
00365 LLAssetRequest* tmp = *curiter;
00366 if (tmp->mUpCallback)
00367 {
00368 tmp->mUpCallback(tmp->getUUID(), tmp->mUserData, error, LL_EXSTAT_NONE);
00369 }
00370 if (tmp->mDownCallback)
00371 {
00372 tmp->mDownCallback(mVFS, tmp->getUUID(), tmp->getType(), tmp->mUserData, error, LL_EXSTAT_NONE);
00373 }
00374 if (tmp->mInfoCallback)
00375 {
00376 tmp->mInfoCallback(&info, tmp->mUserData, error);
00377 }
00378 delete tmp;
00379 }
00380
00381 }
00382
00383 BOOL LLAssetStorage::hasLocalAsset(const LLUUID &uuid, const LLAssetType::EType type)
00384 {
00385 return mVFS->getExists(uuid, type);
00386 }
00387
00389
00391
00392
00393 void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, void (*callback)(LLVFS *vfs, const LLUUID&, LLAssetType::EType, void *, S32, LLExtStat), void *user_data, BOOL is_priority)
00394 {
00395 lldebugs << "LLAssetStorage::getAssetData() - " << uuid << "," << LLAssetType::lookup(type) << llendl;
00396
00397 if (mShutDown)
00398 {
00399 return;
00400 }
00401
00402 if (uuid.isNull())
00403 {
00404
00405 if (callback)
00406 {
00407 callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LL_EXSTAT_NULL_UUID);
00408 }
00409 return;
00410 }
00411
00412 BOOL exists = mVFS->getExists(uuid, type);
00413 LLVFile file(mVFS, uuid, type);
00414 U32 size = exists ? file.getSize() : 0;
00415
00416 if (size < 1)
00417 {
00418 if (exists)
00419 {
00420 llwarns << "Asset vfile " << uuid << ":" << type << " found with bad size " << file.getSize() << ", removing" << llendl;
00421 file.remove();
00422 }
00423
00424 BOOL duplicate = FALSE;
00425
00426
00427 for (request_list_t::iterator iter = mPendingDownloads.begin();
00428 iter != mPendingDownloads.end(); ++iter )
00429 {
00430 LLAssetRequest *tmp = *iter;
00431 if ((type == tmp->getType()) && (uuid == tmp->getUUID()))
00432 {
00433 if (callback == tmp->mDownCallback && user_data == tmp->mUserData)
00434 {
00435
00436 llwarns << "Discarding duplicate request for asset " << uuid
00437 << "." << LLAssetType::lookup(type) << llendl;
00438 return;
00439 }
00440
00441
00442
00443 duplicate = TRUE;
00444 }
00445 }
00446 if (duplicate)
00447 {
00448 llinfos << "Adding additional non-duplicate request for asset " << uuid
00449 << "." << LLAssetType::lookup(type) << llendl;
00450 }
00451
00452
00453 _queueDataRequest(uuid, type, callback, user_data, duplicate, is_priority);
00454 }
00455 else
00456 {
00457
00458
00459
00460 if (callback)
00461 {
00462 callback(mVFS, uuid, type, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED);
00463 }
00464 }
00465 }
00466
00467 void LLAssetStorage::_queueDataRequest(const LLUUID& uuid, LLAssetType::EType atype,
00468 LLGetAssetCallback callback,
00469 void *user_data, BOOL duplicate,
00470 BOOL is_priority)
00471 {
00472 if (mUpstreamHost.isOk())
00473 {
00474
00475 LLAssetRequest *req = new LLAssetRequest(uuid, atype);
00476 req->mDownCallback = callback;
00477 req->mUserData = user_data;
00478 req->mIsPriority = is_priority;
00479
00480 mPendingDownloads.push_back(req);
00481
00482 if (!duplicate)
00483 {
00484
00485
00486 LLTransferSourceParamsAsset spa;
00487 spa.setAsset(uuid, atype);
00488
00489
00490 LLTransferTargetParamsVFile tpvf;
00491 tpvf.setAsset(uuid, atype);
00492 tpvf.setCallback(downloadCompleteCallback, req);
00493
00494 llinfos << "Starting transfer for " << uuid << llendl;
00495 LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(mUpstreamHost, LLTCT_ASSET);
00496 ttcp->requestTransfer(spa, tpvf, 100.f + (is_priority ? 1.f : 0.f));
00497 }
00498 }
00499 else
00500 {
00501
00502 llwarns << "Attempt to move asset data request upstream w/o valid upstream provider" << llendl;
00503 if (callback)
00504 {
00505 callback(mVFS, uuid, atype, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM);
00506 }
00507 }
00508 }
00509
00510
00511 void LLAssetStorage::downloadCompleteCallback(
00512 S32 result,
00513 const LLUUID& file_id,
00514 LLAssetType::EType file_type,
00515 void* user_data, LLExtStat ext_status)
00516 {
00517 lldebugs << "LLAssetStorage::downloadCompleteCallback() for " << file_id
00518 << "," << LLAssetType::lookup(file_type) << llendl;
00519 LLAssetRequest* req = (LLAssetRequest*)user_data;
00520 if(!req)
00521 {
00522 llwarns << "LLAssetStorage::downloadCompleteCallback called without"
00523 "a valid request." << llendl;
00524 return;
00525 }
00526 if (!gAssetStorage)
00527 {
00528 llwarns << "LLAssetStorage::downloadCompleteCallback called without any asset system, aborting!" << llendl;
00529 return;
00530 }
00531
00532 req->setUUID(file_id);
00533 req->setType(file_type);
00534 if (LL_ERR_NOERR == result)
00535 {
00536
00537 LLVFile vfile(gAssetStorage->mVFS, req->getUUID(), req->getType());
00538 if (vfile.getSize() <= 0)
00539 {
00540 llwarns << "downloadCompleteCallback has non-existent or zero-size asset " << req->getUUID() << llendl;
00541
00542 result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE;
00543 vfile.remove();
00544 }
00545 }
00546
00547
00548
00549
00550 request_list_t requests;
00551 for (request_list_t::iterator iter = gAssetStorage->mPendingDownloads.begin();
00552 iter != gAssetStorage->mPendingDownloads.end(); )
00553 {
00554 request_list_t::iterator curiter = iter++;
00555 LLAssetRequest* tmp = *curiter;
00556 if ((tmp->getUUID() == req->getUUID()) && (tmp->getType()== req->getType()))
00557 {
00558 requests.push_front(tmp);
00559 iter = gAssetStorage->mPendingDownloads.erase(curiter);
00560 }
00561 }
00562 for (request_list_t::iterator iter = requests.begin();
00563 iter != requests.end(); )
00564 {
00565 request_list_t::iterator curiter = iter++;
00566 LLAssetRequest* tmp = *curiter;
00567 if (tmp->mDownCallback)
00568 {
00569 tmp->mDownCallback(gAssetStorage->mVFS, req->getUUID(), req->getType(), tmp->mUserData, result, ext_status);
00570 }
00571 delete tmp;
00572 }
00573 }
00574
00575 void LLAssetStorage::getEstateAsset(const LLHost &object_sim, const LLUUID &agent_id, const LLUUID &session_id,
00576 const LLUUID &asset_id, LLAssetType::EType atype, EstateAssetType etype,
00577 LLGetAssetCallback callback, void *user_data, BOOL is_priority)
00578 {
00579 lldebugs << "LLAssetStorage::getEstateAsset() - " << asset_id << "," << LLAssetType::lookup(atype) << ", estatetype " << etype << llendl;
00580
00581
00582
00583
00584 if (asset_id.isNull())
00585 {
00586
00587 if (callback)
00588 {
00589 callback(mVFS, asset_id, atype, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LL_EXSTAT_NULL_UUID);
00590 }
00591 return;
00592 }
00593
00594 BOOL exists = mVFS->getExists(asset_id, atype);
00595 LLVFile file(mVFS, asset_id, atype);
00596 U32 size = exists ? file.getSize() : 0;
00597
00598 if (size < 1)
00599 {
00600 if (exists)
00601 {
00602 llwarns << "Asset vfile " << asset_id << ":" << atype << " found with bad size " << file.getSize() << ", removing" << llendl;
00603 file.remove();
00604 }
00605
00606
00607 LLHost source_host;
00608 if (object_sim.isOk())
00609 {
00610 source_host = object_sim;
00611 }
00612 else
00613 {
00614 source_host = mUpstreamHost;
00615 }
00616 if (source_host.isOk())
00617 {
00618
00619 LLEstateAssetRequest *req = new LLEstateAssetRequest(asset_id, atype, etype);
00620 req->mDownCallback = callback;
00621 req->mUserData = user_data;
00622 req->mIsPriority = is_priority;
00623
00624
00625
00626 LLTransferSourceParamsEstate spe;
00627 spe.setAgentSession(agent_id, session_id);
00628 spe.setEstateAssetType(etype);
00629
00630
00631 LLTransferTargetParamsVFile tpvf;
00632 tpvf.setAsset(asset_id, atype);
00633 tpvf.setCallback(downloadEstateAssetCompleteCallback, req);
00634
00635 llinfos << "Starting transfer for " << asset_id << llendl;
00636 LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(source_host, LLTCT_ASSET);
00637 ttcp->requestTransfer(spe, tpvf, 100.f + (is_priority ? 1.f : 0.f));
00638 }
00639 else
00640 {
00641
00642 llwarns << "Attempt to move asset data request upstream w/o valid upstream provider" << llendl;
00643 if (callback)
00644 {
00645 callback(mVFS, asset_id, atype, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM);
00646 }
00647 }
00648 }
00649 else
00650 {
00651
00652
00653
00654 if (callback)
00655 {
00656 callback(mVFS, asset_id, atype, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED);
00657 }
00658 }
00659 }
00660
00661 void LLAssetStorage::downloadEstateAssetCompleteCallback(
00662 S32 result,
00663 const LLUUID& file_id,
00664 LLAssetType::EType file_type,
00665 void* user_data,
00666 LLExtStat ext_status)
00667 {
00668 LLEstateAssetRequest *req = (LLEstateAssetRequest*)user_data;
00669 if(!req)
00670 {
00671 llwarns << "LLAssetStorage::downloadEstateAssetCompleteCallback called"
00672 " without a valid request." << llendl;
00673 return;
00674 }
00675 if (!gAssetStorage)
00676 {
00677 llwarns << "LLAssetStorage::downloadEstateAssetCompleteCallback called"
00678 " without any asset system, aborting!" << llendl;
00679 return;
00680 }
00681
00682 req->setUUID(file_id);
00683 req->setType(file_type);
00684 if (LL_ERR_NOERR == result)
00685 {
00686
00687 LLVFile vfile(gAssetStorage->mVFS, req->getUUID(), req->getAType());
00688 if (vfile.getSize() <= 0)
00689 {
00690 llwarns << "downloadCompleteCallback has non-existent or zero-size asset!" << llendl;
00691
00692 result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE;
00693 vfile.remove();
00694 }
00695 }
00696
00697 req->mDownCallback(gAssetStorage->mVFS, req->getUUID(), req->getAType(), req->mUserData, result, ext_status);
00698 }
00699
00700 void LLAssetStorage::getInvItemAsset(const LLHost &object_sim, const LLUUID &agent_id, const LLUUID &session_id,
00701 const LLUUID &owner_id, const LLUUID &task_id, const LLUUID &item_id,
00702 const LLUUID &asset_id, LLAssetType::EType atype,
00703 LLGetAssetCallback callback, void *user_data, BOOL is_priority)
00704 {
00705 lldebugs << "LLAssetStorage::getInvItemAsset() - " << asset_id << "," << LLAssetType::lookup(atype) << llendl;
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720 bool exists = false;
00721 U32 size = 0;
00722
00723 if(asset_id.notNull())
00724 {
00725 exists = mVFS->getExists(asset_id, atype);
00726 LLVFile file(mVFS, asset_id, atype);
00727 size = exists ? file.getSize() : 0;
00728 if(exists && size < 1)
00729 {
00730 llwarns << "Asset vfile " << asset_id << ":" << atype << " found with bad size " << file.getSize() << ", removing" << llendl;
00731 file.remove();
00732 }
00733
00734 }
00735
00736 if (size < 1)
00737 {
00738
00739
00740 LLHost source_host;
00741 if (object_sim.isOk())
00742 {
00743 source_host = object_sim;
00744 }
00745 else
00746 {
00747 source_host = mUpstreamHost;
00748 }
00749 if (source_host.isOk())
00750 {
00751
00752 LLInvItemRequest *req = new LLInvItemRequest(asset_id, atype);
00753 req->mDownCallback = callback;
00754 req->mUserData = user_data;
00755 req->mIsPriority = is_priority;
00756
00757
00758
00759 LLTransferSourceParamsInvItem spi;
00760 spi.setAgentSession(agent_id, session_id);
00761 spi.setInvItem(owner_id, task_id, item_id);
00762 spi.setAsset(asset_id, atype);
00763
00764
00765 LLTransferTargetParamsVFile tpvf;
00766 tpvf.setAsset(asset_id, atype);
00767 tpvf.setCallback(downloadInvItemCompleteCallback, req);
00768
00769 llinfos << "Starting transfer for inventory asset "
00770 << item_id << " owned by " << owner_id << "," << task_id
00771 << llendl;
00772 LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(source_host, LLTCT_ASSET);
00773 ttcp->requestTransfer(spi, tpvf, 100.f + (is_priority ? 1.f : 0.f));
00774 }
00775 else
00776 {
00777
00778 llwarns << "Attempt to move asset data request upstream w/o valid upstream provider" << llendl;
00779 if (callback)
00780 {
00781 callback(mVFS, asset_id, atype, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM);
00782 }
00783 }
00784 }
00785 else
00786 {
00787
00788
00789
00790 if (callback)
00791 {
00792 callback(mVFS, asset_id, atype, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED);
00793 }
00794 }
00795 }
00796
00797
00798 void LLAssetStorage::downloadInvItemCompleteCallback(
00799 S32 result,
00800 const LLUUID& file_id,
00801 LLAssetType::EType file_type,
00802 void* user_data,
00803 LLExtStat ext_status)
00804 {
00805 LLInvItemRequest *req = (LLInvItemRequest*)user_data;
00806 if(!req)
00807 {
00808 llwarns << "LLAssetStorage::downloadEstateAssetCompleteCallback called"
00809 " without a valid request." << llendl;
00810 return;
00811 }
00812 if (!gAssetStorage)
00813 {
00814 llwarns << "LLAssetStorage::downloadCompleteCallback called without any asset system, aborting!" << llendl;
00815 return;
00816 }
00817
00818 req->setUUID(file_id);
00819 req->setType(file_type);
00820 if (LL_ERR_NOERR == result)
00821 {
00822
00823 LLVFile vfile(gAssetStorage->mVFS, req->getUUID(), req->getType());
00824 if (vfile.getSize() <= 0)
00825 {
00826 llwarns << "downloadCompleteCallback has non-existent or zero-size asset!" << llendl;
00827
00828 result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE;
00829 vfile.remove();
00830 }
00831 }
00832
00833 req->mDownCallback(gAssetStorage->mVFS, req->getUUID(), req->getType(), req->mUserData, result, ext_status);
00834 }
00835
00837
00839
00840
00841 void LLAssetStorage::uploadCompleteCallback(const LLUUID& uuid, void *user_data, S32 result, LLExtStat ext_status)
00842 {
00843 if (!gAssetStorage)
00844 {
00845 llwarns << "LLAssetStorage::uploadCompleteCallback has no gAssetStorage!" << llendl;
00846 return;
00847 }
00848 LLAssetRequest *req = (LLAssetRequest *)user_data;
00849 BOOL success = TRUE;
00850
00851 if (result)
00852 {
00853 llwarns << "LLAssetStorage::uploadCompleteCallback " << result << ":" << getErrorString(result) << " trying to upload file to upstream provider" << llendl;
00854 success = FALSE;
00855 }
00856
00857
00858 gAssetStorage->mMessageSys->newMessageFast(_PREHASH_AssetUploadComplete);
00859 gAssetStorage->mMessageSys->nextBlockFast(_PREHASH_AssetBlock);
00860 gAssetStorage->mMessageSys->addUUIDFast(_PREHASH_UUID, uuid);
00861 gAssetStorage->mMessageSys->addS8Fast(_PREHASH_Type, req->getType());
00862 gAssetStorage->mMessageSys->addBOOLFast(_PREHASH_Success, success);
00863 gAssetStorage->mMessageSys->sendReliable(req->mHost);
00864
00865 delete req;
00866 }
00867
00868 void LLAssetStorage::processUploadComplete(LLMessageSystem *msg, void **user_data)
00869 {
00870 LLAssetStorage *this_ptr = (LLAssetStorage *)user_data;
00871 LLUUID uuid;
00872 S8 asset_type_s8;
00873 LLAssetType::EType asset_type;
00874 BOOL success = FALSE;
00875
00876 msg->getUUIDFast(_PREHASH_AssetBlock, _PREHASH_UUID, uuid);
00877 msg->getS8Fast(_PREHASH_AssetBlock, _PREHASH_Type, asset_type_s8);
00878 msg->getBOOLFast(_PREHASH_AssetBlock, _PREHASH_Success, success);
00879
00880 asset_type = (LLAssetType::EType)asset_type_s8;
00881 this_ptr->_callUploadCallbacks(uuid, asset_type, success, LL_EXSTAT_NONE);
00882 }
00883
00884 void LLAssetStorage::_callUploadCallbacks(const LLUUID &uuid, LLAssetType::EType asset_type, BOOL success, LLExtStat ext_status )
00885 {
00886
00887
00888 request_list_t requests;
00889 for (request_list_t::iterator iter = mPendingUploads.begin();
00890 iter != mPendingUploads.end(); )
00891 {
00892 request_list_t::iterator curiter = iter++;
00893 LLAssetRequest* req = *curiter;
00894 if ((req->getUUID() == uuid) && (req->getType() == asset_type))
00895 {
00896 requests.push_front(req);
00897 iter = mPendingUploads.erase(curiter);
00898 }
00899 }
00900 for (request_list_t::iterator iter = mPendingLocalUploads.begin();
00901 iter != mPendingLocalUploads.end(); )
00902 {
00903 request_list_t::iterator curiter = iter++;
00904 LLAssetRequest* req = *curiter;
00905 if ((req->getUUID() == uuid) && (req->getType() == asset_type))
00906 {
00907 requests.push_front(req);
00908 iter = mPendingLocalUploads.erase(curiter);
00909 }
00910 }
00911 for (request_list_t::iterator iter = requests.begin();
00912 iter != requests.end(); )
00913 {
00914 request_list_t::iterator curiter = iter++;
00915 LLAssetRequest* req = *curiter;
00916 if (req->mUpCallback)
00917 {
00918 req->mUpCallback(uuid, req->mUserData, (success ? LL_ERR_NOERR : LL_ERR_ASSET_REQUEST_FAILED ), ext_status );
00919 }
00920 delete req;
00921 }
00922 }
00923
00924 LLAssetStorage::request_list_t* LLAssetStorage::getRequestList(LLAssetStorage::ERequestType rt)
00925 {
00926 switch (rt)
00927 {
00928 case RT_DOWNLOAD:
00929 return &mPendingDownloads;
00930 case RT_UPLOAD:
00931 return &mPendingUploads;
00932 case RT_LOCALUPLOAD:
00933 return &mPendingLocalUploads;
00934 default:
00935 llwarns << "Unable to find request list for request type '" << rt << "'" << llendl;
00936 return NULL;
00937 }
00938 }
00939
00940 const LLAssetStorage::request_list_t* LLAssetStorage::getRequestList(LLAssetStorage::ERequestType rt) const
00941 {
00942 switch (rt)
00943 {
00944 case RT_DOWNLOAD:
00945 return &mPendingDownloads;
00946 case RT_UPLOAD:
00947 return &mPendingUploads;
00948 case RT_LOCALUPLOAD:
00949 return &mPendingLocalUploads;
00950 default:
00951 llwarns << "Unable to find request list for request type '" << rt << "'" << llendl;
00952 return NULL;
00953 }
00954 }
00955
00956
00957 std::string LLAssetStorage::getRequestName(LLAssetStorage::ERequestType rt)
00958 {
00959 switch (rt)
00960 {
00961 case RT_DOWNLOAD:
00962 return "download";
00963 case RT_UPLOAD:
00964 return "upload";
00965 case RT_LOCALUPLOAD:
00966 return "localupload";
00967 default:
00968 llwarns << "Unable to find request name for request type '" << rt << "'" << llendl;
00969 return "";
00970 }
00971 }
00972
00973 S32 LLAssetStorage::getNumPending(LLAssetStorage::ERequestType rt) const
00974 {
00975 const request_list_t* requests = getRequestList(rt);
00976 S32 num_pending = -1;
00977 if (requests)
00978 {
00979 num_pending = requests->size();
00980 }
00981 return num_pending;
00982 }
00983
00984 S32 LLAssetStorage::getNumPendingDownloads() const
00985 {
00986 return getNumPending(RT_DOWNLOAD);
00987 }
00988
00989 S32 LLAssetStorage::getNumPendingUploads() const
00990 {
00991 return getNumPending(RT_UPLOAD);
00992 }
00993
00994 S32 LLAssetStorage::getNumPendingLocalUploads()
00995 {
00996 return getNumPending(RT_LOCALUPLOAD);
00997 }
00998
00999
01000 LLSD LLAssetStorage::getPendingDetails(LLAssetStorage::ERequestType rt,
01001 LLAssetType::EType asset_type,
01002 const std::string& detail_prefix) const
01003 {
01004 const request_list_t* requests = getRequestList(rt);
01005 LLSD sd;
01006 sd["requests"] = getPendingDetails(requests, asset_type, detail_prefix);
01007 return sd;
01008 }
01009
01010
01011 LLSD LLAssetStorage::getPendingDetails(const LLAssetStorage::request_list_t* requests,
01012 LLAssetType::EType asset_type,
01013 const std::string& detail_prefix) const
01014 {
01015 LLSD details;
01016 if (requests)
01017 {
01018 request_list_t::const_iterator it = requests->begin();
01019 request_list_t::const_iterator end = requests->end();
01020 for ( ; it != end; ++it)
01021 {
01022 LLAssetRequest* req = *it;
01023 if ( (LLAssetType::AT_NONE == asset_type)
01024 || (req->getType() == asset_type) )
01025 {
01026 LLSD row = req->getTerseDetails();
01027
01028 std::ostringstream detail;
01029 detail << detail_prefix << "/" << LLAssetType::lookup(req->getType())
01030 << "/" << req->getUUID();
01031 row["detail"] = LLURI(detail.str());
01032
01033 details.append(row);
01034 }
01035 }
01036 }
01037 return details;
01038 }
01039
01040
01041
01042 const LLAssetRequest* LLAssetStorage::findRequest(const LLAssetStorage::request_list_t* requests,
01043 LLAssetType::EType asset_type,
01044 const LLUUID& asset_id)
01045 {
01046 if (requests)
01047 {
01048
01049 request_list_t::const_iterator iter = requests->begin();
01050 request_list_t::const_iterator end = requests->end();
01051 for (; iter != end; ++iter)
01052 {
01053 const LLAssetRequest* req = *iter;
01054 if (asset_type == req->getType() &&
01055 asset_id == req->getUUID() )
01056 {
01057 return req;
01058 }
01059 }
01060 }
01061 return NULL;
01062 }
01063
01064
01065 LLAssetRequest* LLAssetStorage::findRequest(LLAssetStorage::request_list_t* requests,
01066 LLAssetType::EType asset_type,
01067 const LLUUID& asset_id)
01068 {
01069 if (requests)
01070 {
01071
01072 request_list_t::iterator iter = requests->begin();
01073 request_list_t::iterator end = requests->end();
01074 for (; iter != end; ++iter)
01075 {
01076 LLAssetRequest* req = *iter;
01077 if (asset_type == req->getType() &&
01078 asset_id == req->getUUID() )
01079 {
01080 return req;
01081 }
01082 }
01083 }
01084 return NULL;
01085 }
01086
01087
01088
01089 LLSD LLAssetStorage::getPendingRequest(LLAssetStorage::ERequestType rt,
01090 LLAssetType::EType asset_type,
01091 const LLUUID& asset_id) const
01092 {
01093 const request_list_t* requests = getRequestList(rt);
01094 return getPendingRequest(requests, asset_type, asset_id);
01095 }
01096
01097
01098 LLSD LLAssetStorage::getPendingRequest(const LLAssetStorage::request_list_t* requests,
01099 LLAssetType::EType asset_type,
01100 const LLUUID& asset_id) const
01101 {
01102 LLSD sd;
01103 const LLAssetRequest* req = findRequest(requests, asset_type, asset_id);
01104 if (req)
01105 {
01106 sd = req->getFullDetails();
01107 }
01108 return sd;
01109 }
01110
01111
01112 bool LLAssetStorage::deletePendingRequest(LLAssetStorage::ERequestType rt,
01113 LLAssetType::EType asset_type,
01114 const LLUUID& asset_id)
01115 {
01116 request_list_t* requests = getRequestList(rt);
01117 if (deletePendingRequest(requests, asset_type, asset_id))
01118 {
01119 llinfos << "Asset " << getRequestName(rt) << " request for "
01120 << asset_id << "." << LLAssetType::lookup(asset_type)
01121 << " removed from pending queue." << llendl;
01122 return true;
01123 }
01124 return false;
01125 }
01126
01127
01128 bool LLAssetStorage::deletePendingRequest(LLAssetStorage::request_list_t* requests,
01129 LLAssetType::EType asset_type,
01130 const LLUUID& asset_id)
01131 {
01132 LLAssetRequest* req = findRequest(requests, asset_type, asset_id);
01133 if (req)
01134 {
01135
01136 requests->remove(req);
01137 S32 error = LL_ERR_TCP_TIMEOUT;
01138
01139 if (req->mUpCallback)
01140 {
01141 req->mUpCallback(req->getUUID(), req->mUserData, error, LL_EXSTAT_REQUEST_DROPPED);
01142 }
01143 if (req->mDownCallback)
01144 {
01145 req->mDownCallback(mVFS, req->getUUID(), req->getType(), req->mUserData, error, LL_EXSTAT_REQUEST_DROPPED);
01146 }
01147 if (req->mInfoCallback)
01148 {
01149 LLAssetInfo info;
01150 req->mInfoCallback(&info, req->mUserData, error);
01151 }
01152 delete req;
01153 return true;
01154 }
01155
01156 return false;
01157 }
01158
01159
01160 const char* LLAssetStorage::getErrorString(S32 status)
01161 {
01162 switch( status )
01163 {
01164 case LL_ERR_NOERR:
01165 return "No error";
01166
01167 case LL_ERR_ASSET_REQUEST_FAILED:
01168 return "Asset request: failed";
01169
01170 case LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE:
01171 return "Asset request: non-existent file";
01172
01173 case LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE:
01174 return "Asset request: asset not found in database";
01175
01176 case LL_ERR_EOF:
01177 return "End of file";
01178
01179 case LL_ERR_CANNOT_OPEN_FILE:
01180 return "Cannot open file";
01181
01182 case LL_ERR_FILE_NOT_FOUND:
01183 return "File not found";
01184
01185 case LL_ERR_TCP_TIMEOUT:
01186 return "File transfer timeout";
01187
01188 case LL_ERR_CIRCUIT_GONE:
01189 return "Circuit gone";
01190
01191 default:
01192 return "Unknown status";
01193 }
01194 }
01195
01196
01197
01198 void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, void (*callback)(const char*, const LLUUID&, void *, S32, LLExtStat), void *user_data, BOOL is_priority)
01199 {
01200
01201 for (request_list_t::iterator iter = mPendingDownloads.begin();
01202 iter != mPendingDownloads.end(); )
01203 {
01204 LLAssetRequest* tmp = *iter++;
01205 if (type == tmp->getType() &&
01206 uuid == tmp->getUUID() &&
01207 legacyGetDataCallback == tmp->mDownCallback &&
01208 callback == ((LLLegacyAssetRequest *)tmp->mUserData)->mDownCallback &&
01209 user_data == ((LLLegacyAssetRequest *)tmp->mUserData)->mUserData)
01210 {
01211
01212 llinfos << "Discarding duplicate request for UUID " << uuid << llendl;
01213 return;
01214 }
01215 }
01216
01217
01218 LLLegacyAssetRequest *legacy = new LLLegacyAssetRequest;
01219
01220 legacy->mDownCallback = callback;
01221 legacy->mUserData = user_data;
01222
01223 getAssetData(uuid, type, legacyGetDataCallback, (void **)legacy,
01224 is_priority);
01225 }
01226
01227
01228 void LLAssetStorage::legacyGetDataCallback(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type, void *user_data, S32 status, LLExtStat ext_status)
01229 {
01230 LLLegacyAssetRequest *legacy = (LLLegacyAssetRequest *)user_data;
01231 char filename[LL_MAX_PATH] = "";
01232
01233 if (! status)
01234 {
01235 LLVFile file(vfs, uuid, type);
01236
01237 char uuid_str[UUID_STR_LENGTH];
01238
01239 uuid.toString(uuid_str);
01240 snprintf(filename,sizeof(filename),"%s.%s",gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_str).c_str(),LLAssetType::lookup(type));
01241
01242 FILE* fp = LLFile::fopen(filename, "wb");
01243 if (fp)
01244 {
01245 const S32 buf_size = 65536;
01246 U8 copy_buf[buf_size];
01247 while (file.read(copy_buf, buf_size))
01248 {
01249 if (fwrite(copy_buf, file.getLastBytesRead(), 1, fp) < 1)
01250 {
01251
01252 status = LL_ERR_CANNOT_OPEN_FILE;
01253 }
01254 }
01255
01256 fclose(fp);
01257 }
01258 else
01259 {
01260 status = LL_ERR_CANNOT_OPEN_FILE;
01261 }
01262 }
01263
01264 legacy->mDownCallback(filename, uuid, legacy->mUserData, status, ext_status);
01265 delete legacy;
01266 }
01267
01268
01269
01270 void LLAssetStorage::storeAssetData(
01271 const LLTransactionID& tid,
01272 LLAssetType::EType asset_type,
01273 LLStoreAssetCallback callback,
01274 void* user_data,
01275 bool temp_file,
01276 bool is_priority,
01277 bool store_local,
01278 bool user_waiting,
01279 F64 timeout)
01280 {
01281 llwarns << "storeAssetData: wrong version called" << llendl;
01282 }
01283
01284
01285
01286 void LLAssetStorage::storeAssetData(
01287 const LLUUID& asset_id,
01288 LLAssetType::EType asset_type,
01289 LLStoreAssetCallback callback,
01290 void* user_data,
01291 bool temp_file ,
01292 bool is_priority,
01293 bool store_local,
01294 const LLUUID& requesting_agent_id,
01295 bool user_waiting,
01296 F64 timeout)
01297 {
01298 llwarns << "storeAssetData: wrong version called" << llendl;
01299 }
01300
01301
01302
01303 void LLAssetStorage::storeAssetData(
01304 const char* filename,
01305 const LLUUID& asset_id,
01306 LLAssetType::EType asset_type,
01307 LLStoreAssetCallback callback,
01308 void* user_data,
01309 bool temp_file,
01310 bool is_priority,
01311 bool user_waiting,
01312 F64 timeout)
01313 {
01314 llwarns << "storeAssetData: wrong version called" << llendl;
01315 }
01316
01317
01318
01319 void LLAssetStorage::storeAssetData(
01320 const char* filename,
01321 const LLTransactionID &transactoin_id,
01322 LLAssetType::EType asset_type,
01323 LLStoreAssetCallback callback,
01324 void* user_data,
01325 bool temp_file,
01326 bool is_priority,
01327 bool user_waiting,
01328 F64 timeout)
01329 {
01330 llwarns << "storeAssetData: wrong version called" << llendl;
01331 }
01332
01333
01334 void LLAssetStorage::legacyStoreDataCallback(const LLUUID &uuid, void *user_data, S32 status, LLExtStat ext_status)
01335 {
01336 LLLegacyAssetRequest *legacy = (LLLegacyAssetRequest *)user_data;
01337 if (legacy && legacy->mUpCallback)
01338 {
01339 legacy->mUpCallback(uuid, legacy->mUserData, status, ext_status);
01340 }
01341 delete legacy;
01342 }
01343
01344
01345 void LLAssetStorage::addTempAssetData(const LLUUID& asset_id, const LLUUID& agent_id, const std::string& host_name)
01346 { }
01347
01348
01349 BOOL LLAssetStorage::hasTempAssetData(const LLUUID& texture_id) const
01350 { return FALSE; }
01351
01352
01353 std::string LLAssetStorage::getTempAssetHostName(const LLUUID& texture_id) const
01354 { return std::string(); }
01355
01356
01357 LLUUID LLAssetStorage::getTempAssetAgentID(const LLUUID& texture_id) const
01358 { return LLUUID::null; }
01359
01360
01361 void LLAssetStorage::removeTempAssetData(const LLUUID& asset_id)
01362 { }
01363
01364
01365 void LLAssetStorage::removeTempAssetDataByAgentID(const LLUUID& agent_id)
01366 { }
01367
01368
01369 void LLAssetStorage::dumpTempAssetData(const LLUUID& avatar_id) const
01370 { }
01371
01372
01373 void LLAssetStorage::clearTempAssetData()
01374 { }