PageRenderTime 169ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/llmessage/llassetstorage.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1580 lines | 1174 code | 199 blank | 207 comment | 163 complexity | 4b5f16ab6590d03f7a19aec54381f04f MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llassetstorage.cpp
  3. * @brief Implementation of the base asset storage system.
  4. *
  5. * $LicenseInfo:firstyear=2001&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "linden_common.h"
  27. // system library includes
  28. #include <sys/types.h>
  29. #include <sys/stat.h>
  30. #include "llassetstorage.h"
  31. // linden library includes
  32. #include "llmath.h"
  33. #include "llstring.h"
  34. #include "lldir.h"
  35. #include "llsd.h"
  36. #include "llframetimer.h"
  37. // this library includes
  38. #include "message.h"
  39. #include "llxfermanager.h"
  40. #include "llvfile.h"
  41. #include "llvfs.h"
  42. #include "lldbstrings.h"
  43. #include "lltransfersourceasset.h"
  44. #include "lltransfertargetvfile.h" // For debugging
  45. #include "llmetrics.h"
  46. LLAssetStorage *gAssetStorage = NULL;
  47. LLMetrics *LLAssetStorage::metric_recipient = NULL;
  48. const LLUUID CATEGORIZE_LOST_AND_FOUND_ID(std::string("00000000-0000-0000-0000-000000000010"));
  49. const U64 TOXIC_ASSET_LIFETIME = (120 * 1000000); // microseconds
  50. LLTempAssetStorage::~LLTempAssetStorage()
  51. {
  52. }
  53. ///----------------------------------------------------------------------------
  54. /// LLAssetInfo
  55. ///----------------------------------------------------------------------------
  56. LLAssetInfo::LLAssetInfo( void )
  57. : mDescription(),
  58. mName(),
  59. mUuid(),
  60. mCreatorID(),
  61. mType( LLAssetType::AT_NONE )
  62. { }
  63. LLAssetInfo::LLAssetInfo( const LLUUID& object_id, const LLUUID& creator_id,
  64. LLAssetType::EType type, const char* name,
  65. const char* desc )
  66. : mUuid( object_id ),
  67. mCreatorID( creator_id ),
  68. mType( type )
  69. {
  70. setName( name );
  71. setDescription( desc );
  72. }
  73. LLAssetInfo::LLAssetInfo( const LLNameValue& nv )
  74. {
  75. setFromNameValue( nv );
  76. }
  77. // make sure the name is short enough, and strip all pipes since they
  78. // are reserved characters in our inventory tracking system.
  79. void LLAssetInfo::setName( const std::string& name )
  80. {
  81. if( !name.empty() )
  82. {
  83. mName.assign( name, 0, llmin((U32)name.size(), (U32)DB_INV_ITEM_NAME_STR_LEN) );
  84. mName.erase( std::remove(mName.begin(), mName.end(), '|'),
  85. mName.end() );
  86. }
  87. }
  88. // make sure the name is short enough, and strip all pipes since they
  89. // are reserved characters in our inventory tracking system.
  90. void LLAssetInfo::setDescription( const std::string& desc )
  91. {
  92. if( !desc.empty() )
  93. {
  94. mDescription.assign( desc, 0, llmin((U32)desc.size(),
  95. (U32)DB_INV_ITEM_DESC_STR_LEN) );
  96. mDescription.erase( std::remove(mDescription.begin(),
  97. mDescription.end(), '|'),
  98. mDescription.end() );
  99. }
  100. }
  101. // Assets (aka potential inventory items) can be applied to an
  102. // object in the world. We'll store that as a string name value
  103. // pair where the name encodes part of asset info, and the value
  104. // the rest. LLAssetInfo objects will be responsible for parsing
  105. // the meaning out froman LLNameValue object. See the inventory
  106. // design docs for details. Briefly:
  107. // name=<inv_type>|<uuid>
  108. // value=<creatorid>|<name>|<description>|
  109. void LLAssetInfo::setFromNameValue( const LLNameValue& nv )
  110. {
  111. std::string str;
  112. std::string buf;
  113. std::string::size_type pos1;
  114. std::string::size_type pos2;
  115. // convert the name to useful information
  116. str.assign( nv.mName );
  117. pos1 = str.find('|');
  118. buf.assign( str, 0, pos1++ );
  119. mType = LLAssetType::lookup( buf );
  120. buf.assign( str, pos1, std::string::npos );
  121. mUuid.set( buf );
  122. // convert the value to useful information
  123. str.assign( nv.getAsset() );
  124. pos1 = str.find('|');
  125. buf.assign( str, 0, pos1++ );
  126. mCreatorID.set( buf );
  127. pos2 = str.find( '|', pos1 );
  128. buf.assign( str, pos1, (pos2++) - pos1 );
  129. setName( buf );
  130. buf.assign( str, pos2, std::string::npos );
  131. setDescription( buf );
  132. LL_DEBUGS("AssetStorage") << "uuid: " << mUuid << llendl;
  133. LL_DEBUGS("AssetStorage") << "creator: " << mCreatorID << llendl;
  134. }
  135. ///----------------------------------------------------------------------------
  136. /// LLAssetRequest
  137. ///----------------------------------------------------------------------------
  138. LLAssetRequest::LLAssetRequest(const LLUUID &uuid, const LLAssetType::EType type)
  139. : mUUID(uuid),
  140. mType(type),
  141. mDownCallback( NULL ),
  142. mUpCallback( NULL ),
  143. mInfoCallback( NULL ),
  144. mUserData( NULL ),
  145. mHost(),
  146. mIsTemp( FALSE ),
  147. mIsLocal(FALSE),
  148. mIsUserWaiting(FALSE),
  149. mTimeout(LL_ASSET_STORAGE_TIMEOUT),
  150. mIsPriority(FALSE),
  151. mDataSentInFirstPacket(FALSE),
  152. mDataIsInVFS( FALSE )
  153. {
  154. // Need to guarantee that this time is up to date, we may be creating a circuit even though we haven't been
  155. // running a message system loop.
  156. mTime = LLMessageSystem::getMessageTimeSeconds(TRUE);
  157. }
  158. // virtual
  159. LLAssetRequest::~LLAssetRequest()
  160. {
  161. }
  162. // virtual
  163. LLSD LLAssetRequest::getTerseDetails() const
  164. {
  165. LLSD sd;
  166. sd["asset_id"] = getUUID();
  167. sd["type_long"] = LLAssetType::lookupHumanReadable(getType());
  168. sd["type"] = LLAssetType::lookup(getType());
  169. sd["time"] = mTime;
  170. time_t timestamp = (time_t) mTime;
  171. std::ostringstream time_string;
  172. time_string << ctime(&timestamp);
  173. sd["time_string"] = time_string.str();
  174. return sd;
  175. }
  176. // virtual
  177. LLSD LLAssetRequest::getFullDetails() const
  178. {
  179. LLSD sd = getTerseDetails();
  180. sd["host"] = mHost.getIPandPort();
  181. sd["requesting_agent"] = mRequestingAgentID;
  182. sd["is_temp"] = mIsTemp;
  183. sd["is_local"] = mIsLocal;
  184. sd["is_priority"] = mIsPriority;
  185. sd["data_send_in_first_packet"] = mDataSentInFirstPacket;
  186. sd["data_is_in_vfs"] = mDataIsInVFS;
  187. return sd;
  188. }
  189. ///----------------------------------------------------------------------------
  190. /// LLInvItemRequest
  191. ///----------------------------------------------------------------------------
  192. LLInvItemRequest::LLInvItemRequest(const LLUUID &uuid, const LLAssetType::EType type)
  193. : mUUID(uuid),
  194. mType(type),
  195. mDownCallback( NULL ),
  196. mUserData( NULL ),
  197. mHost(),
  198. mIsTemp( FALSE ),
  199. mIsPriority(FALSE),
  200. mDataSentInFirstPacket(FALSE),
  201. mDataIsInVFS( FALSE )
  202. {
  203. // Need to guarantee that this time is up to date, we may be creating a circuit even though we haven't been
  204. // running a message system loop.
  205. mTime = LLMessageSystem::getMessageTimeSeconds(TRUE);
  206. }
  207. LLInvItemRequest::~LLInvItemRequest()
  208. {
  209. }
  210. ///----------------------------------------------------------------------------
  211. /// LLEstateAssetRequest
  212. ///----------------------------------------------------------------------------
  213. LLEstateAssetRequest::LLEstateAssetRequest(const LLUUID &uuid, const LLAssetType::EType atype,
  214. EstateAssetType etype)
  215. : mUUID(uuid),
  216. mAType(atype),
  217. mEstateAssetType(etype),
  218. mDownCallback( NULL ),
  219. mUserData( NULL ),
  220. mHost(),
  221. mIsTemp( FALSE ),
  222. mIsPriority(FALSE),
  223. mDataSentInFirstPacket(FALSE),
  224. mDataIsInVFS( FALSE )
  225. {
  226. // Need to guarantee that this time is up to date, we may be creating a circuit even though we haven't been
  227. // running a message system loop.
  228. mTime = LLMessageSystem::getMessageTimeSeconds(TRUE);
  229. }
  230. LLEstateAssetRequest::~LLEstateAssetRequest()
  231. {
  232. }
  233. ///----------------------------------------------------------------------------
  234. /// LLAssetStorage
  235. ///----------------------------------------------------------------------------
  236. // since many of these functions are called by the messaging and xfer systems,
  237. // they are declared as static and are passed a "this" handle
  238. // it's a C/C++ mish-mash!
  239. // TODO: permissions on modifications - maybe don't allow at all?
  240. // TODO: verify that failures get propogated down
  241. // TODO: rework tempfile handling?
  242. LLAssetStorage::LLAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, LLVFS *vfs, LLVFS *static_vfs, const LLHost &upstream_host)
  243. {
  244. _init(msg, xfer, vfs, static_vfs, upstream_host);
  245. }
  246. LLAssetStorage::LLAssetStorage(LLMessageSystem *msg, LLXferManager *xfer,
  247. LLVFS *vfs, LLVFS *static_vfs)
  248. {
  249. _init(msg, xfer, vfs, static_vfs, LLHost::invalid);
  250. }
  251. void LLAssetStorage::_init(LLMessageSystem *msg,
  252. LLXferManager *xfer,
  253. LLVFS *vfs,
  254. LLVFS *static_vfs,
  255. const LLHost &upstream_host)
  256. {
  257. mShutDown = FALSE;
  258. mMessageSys = msg;
  259. mXferManager = xfer;
  260. mVFS = vfs;
  261. mStaticVFS = static_vfs;
  262. setUpstream(upstream_host);
  263. msg->setHandlerFuncFast(_PREHASH_AssetUploadComplete, processUploadComplete, (void **)this);
  264. }
  265. LLAssetStorage::~LLAssetStorage()
  266. {
  267. mShutDown = TRUE;
  268. _cleanupRequests(TRUE, LL_ERR_CIRCUIT_GONE);
  269. if (gMessageSystem)
  270. {
  271. // Warning! This won't work if there's more than one asset storage.
  272. // unregister our callbacks with the message system
  273. gMessageSystem->setHandlerFuncFast(_PREHASH_AssetUploadComplete, NULL, NULL);
  274. }
  275. // Clear the toxic asset map
  276. mToxicAssetMap.clear();
  277. }
  278. void LLAssetStorage::setUpstream(const LLHost &upstream_host)
  279. {
  280. LL_DEBUGS("AppInit") << "AssetStorage: Setting upstream provider to " << upstream_host << LL_ENDL;
  281. mUpstreamHost = upstream_host;
  282. }
  283. void LLAssetStorage::checkForTimeouts()
  284. {
  285. _cleanupRequests(FALSE, LL_ERR_TCP_TIMEOUT);
  286. }
  287. void LLAssetStorage::_cleanupRequests(BOOL all, S32 error)
  288. {
  289. F64 mt_secs = LLMessageSystem::getMessageTimeSeconds();
  290. request_list_t timed_out;
  291. S32 rt;
  292. for (rt = 0; rt < RT_COUNT; rt++)
  293. {
  294. request_list_t* requests = getRequestList((ERequestType)rt);
  295. for (request_list_t::iterator iter = requests->begin();
  296. iter != requests->end(); )
  297. {
  298. request_list_t::iterator curiter = iter++;
  299. LLAssetRequest* tmp = *curiter;
  300. // if all is true, we want to clean up everything
  301. // otherwise just check for timed out requests
  302. // EXCEPT for upload timeouts
  303. if (all
  304. || ((RT_DOWNLOAD == rt)
  305. && LL_ASSET_STORAGE_TIMEOUT < (mt_secs - tmp->mTime)))
  306. {
  307. llwarns << "Asset " << getRequestName((ERequestType)rt) << " request "
  308. << (all ? "aborted" : "timed out") << " for "
  309. << tmp->getUUID() << "."
  310. << LLAssetType::lookup(tmp->getType()) << llendl;
  311. timed_out.push_front(tmp);
  312. iter = requests->erase(curiter);
  313. }
  314. }
  315. }
  316. LLAssetInfo info;
  317. for (request_list_t::iterator iter = timed_out.begin();
  318. iter != timed_out.end(); )
  319. {
  320. request_list_t::iterator curiter = iter++;
  321. LLAssetRequest* tmp = *curiter;
  322. if (tmp->mUpCallback)
  323. {
  324. tmp->mUpCallback(tmp->getUUID(), tmp->mUserData, error, LL_EXSTAT_NONE);
  325. }
  326. if (tmp->mDownCallback)
  327. {
  328. tmp->mDownCallback(mVFS, tmp->getUUID(), tmp->getType(), tmp->mUserData, error, LL_EXSTAT_NONE);
  329. }
  330. if (tmp->mInfoCallback)
  331. {
  332. tmp->mInfoCallback(&info, tmp->mUserData, error);
  333. }
  334. delete tmp;
  335. }
  336. }
  337. BOOL LLAssetStorage::hasLocalAsset(const LLUUID &uuid, const LLAssetType::EType type)
  338. {
  339. return mStaticVFS->getExists(uuid, type) || mVFS->getExists(uuid, type);
  340. }
  341. bool LLAssetStorage::findInStaticVFSAndInvokeCallback(const LLUUID& uuid, LLAssetType::EType type,
  342. LLGetAssetCallback callback, void *user_data)
  343. {
  344. if (user_data)
  345. {
  346. // The *user_data should not be passed without a callback to clean it up.
  347. llassert(callback != NULL)
  348. }
  349. BOOL exists = mStaticVFS->getExists(uuid, type);
  350. if (exists)
  351. {
  352. LLVFile file(mStaticVFS, uuid, type);
  353. U32 size = file.getSize();
  354. if (size > 0)
  355. {
  356. // we've already got the file
  357. if (callback)
  358. {
  359. callback(mStaticVFS, uuid, type, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED);
  360. }
  361. return true;
  362. }
  363. else
  364. {
  365. llwarns << "Asset vfile " << uuid << ":" << type
  366. << " found in static cache with bad size " << file.getSize() << ", ignoring" << llendl;
  367. }
  368. }
  369. return false;
  370. }
  371. ///////////////////////////////////////////////////////////////////////////
  372. // GET routines
  373. ///////////////////////////////////////////////////////////////////////////
  374. // IW - uuid is passed by value to avoid side effects, please don't re-add &
  375. void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, LLGetAssetCallback callback, void *user_data, BOOL is_priority)
  376. {
  377. LL_DEBUGS("AssetStorage") << "LLAssetStorage::getAssetData() - " << uuid << "," << LLAssetType::lookup(type) << llendl;
  378. LL_DEBUGS("AssetStorage") << "ASSET_TRACE requesting " << uuid << " type " << LLAssetType::lookup(type) << llendl;
  379. if (user_data)
  380. {
  381. // The *user_data should not be passed without a callback to clean it up.
  382. llassert(callback != NULL)
  383. }
  384. if (mShutDown)
  385. {
  386. LL_DEBUGS("AssetStorage") << "ASSET_TRACE cancelled " << uuid << " type " << LLAssetType::lookup(type) << " shutting down" << llendl;
  387. if (callback)
  388. {
  389. callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_FAILED, LL_EXSTAT_NONE);
  390. }
  391. return;
  392. }
  393. if (uuid.isNull())
  394. {
  395. // Special case early out for NULL uuid and for shutting down
  396. if (callback)
  397. {
  398. callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LL_EXSTAT_NULL_UUID);
  399. }
  400. return;
  401. }
  402. // Try static VFS first.
  403. if (findInStaticVFSAndInvokeCallback(uuid,type,callback,user_data))
  404. {
  405. LL_DEBUGS("AssetStorage") << "ASSET_TRACE asset " << uuid << " found in static VFS" << llendl;
  406. return;
  407. }
  408. BOOL exists = mVFS->getExists(uuid, type);
  409. LLVFile file(mVFS, uuid, type);
  410. U32 size = exists ? file.getSize() : 0;
  411. if (size > 0)
  412. {
  413. // we've already got the file
  414. // theoretically, partial files w/o a pending request shouldn't happen
  415. // unless there's a weird error
  416. if (callback)
  417. {
  418. callback(mVFS, uuid, type, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED);
  419. }
  420. LL_DEBUGS("AssetStorage") << "ASSET_TRACE asset " << uuid << " found in VFS" << llendl;
  421. }
  422. else
  423. {
  424. if (exists)
  425. {
  426. llwarns << "Asset vfile " << uuid << ":" << type << " found with bad size " << file.getSize() << ", removing" << llendl;
  427. file.remove();
  428. }
  429. BOOL duplicate = FALSE;
  430. // check to see if there's a pending download of this uuid already
  431. for (request_list_t::iterator iter = mPendingDownloads.begin();
  432. iter != mPendingDownloads.end(); ++iter )
  433. {
  434. LLAssetRequest *tmp = *iter;
  435. if ((type == tmp->getType()) && (uuid == tmp->getUUID()))
  436. {
  437. if (callback == tmp->mDownCallback && user_data == tmp->mUserData)
  438. {
  439. // this is a duplicate from the same subsystem - throw it away
  440. llwarns << "Discarding duplicate request for asset " << uuid
  441. << "." << LLAssetType::lookup(type) << llendl;
  442. return;
  443. }
  444. // this is a duplicate request
  445. // queue the request, but don't actually ask for it again
  446. duplicate = TRUE;
  447. }
  448. }
  449. if (duplicate)
  450. {
  451. LL_DEBUGS("AssetStorage") << "Adding additional non-duplicate request for asset " << uuid
  452. << "." << LLAssetType::lookup(type) << llendl;
  453. }
  454. // This can be overridden by subclasses
  455. _queueDataRequest(uuid, type, callback, user_data, duplicate, is_priority);
  456. }
  457. }
  458. //
  459. // *NOTE: Logic here is replicated in LLViewerAssetStorage::_queueDataRequest.
  460. // Changes here may need to be replicated in the viewer's derived class.
  461. //
  462. void LLAssetStorage::_queueDataRequest(const LLUUID& uuid, LLAssetType::EType atype,
  463. LLGetAssetCallback callback,
  464. void *user_data, BOOL duplicate,
  465. BOOL is_priority)
  466. {
  467. if (mUpstreamHost.isOk())
  468. {
  469. // stash the callback info so we can find it after we get the response message
  470. LLAssetRequest *req = new LLAssetRequest(uuid, atype);
  471. req->mDownCallback = callback;
  472. req->mUserData = user_data;
  473. req->mIsPriority = is_priority;
  474. mPendingDownloads.push_back(req);
  475. if (!duplicate)
  476. {
  477. // send request message to our upstream data provider
  478. // Create a new asset transfer.
  479. LLTransferSourceParamsAsset spa;
  480. spa.setAsset(uuid, atype);
  481. // Set our destination file, and the completion callback.
  482. LLTransferTargetParamsVFile tpvf;
  483. tpvf.setAsset(uuid, atype);
  484. tpvf.setCallback(downloadCompleteCallback, req);
  485. //llinfos << "Starting transfer for " << uuid << llendl;
  486. LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(mUpstreamHost, LLTCT_ASSET);
  487. ttcp->requestTransfer(spa, tpvf, 100.f + (is_priority ? 1.f : 0.f));
  488. }
  489. }
  490. else
  491. {
  492. // uh-oh, we shouldn't have gotten here
  493. llwarns << "Attempt to move asset data request upstream w/o valid upstream provider" << llendl;
  494. if (callback)
  495. {
  496. callback(mVFS, uuid, atype, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM);
  497. }
  498. }
  499. }
  500. void LLAssetStorage::downloadCompleteCallback(
  501. S32 result,
  502. const LLUUID& file_id,
  503. LLAssetType::EType file_type,
  504. void* user_data, LLExtStat ext_status)
  505. {
  506. LL_DEBUGS("AssetStorage") << "ASSET_TRACE asset " << file_id << " downloadCompleteCallback" << llendl;
  507. LL_DEBUGS("AssetStorage") << "LLAssetStorage::downloadCompleteCallback() for " << file_id
  508. << "," << LLAssetType::lookup(file_type) << llendl;
  509. LLAssetRequest* req = (LLAssetRequest*)user_data;
  510. if(!req)
  511. {
  512. llwarns << "LLAssetStorage::downloadCompleteCallback called without"
  513. "a valid request." << llendl;
  514. return;
  515. }
  516. if (!gAssetStorage)
  517. {
  518. llwarns << "LLAssetStorage::downloadCompleteCallback called without any asset system, aborting!" << llendl;
  519. return;
  520. }
  521. // Inefficient since we're doing a find through a list that may have thousands of elements.
  522. // This is due for refactoring; we will probably change mPendingDownloads into a set.
  523. request_list_t::iterator download_iter = std::find(gAssetStorage->mPendingDownloads.begin(),
  524. gAssetStorage->mPendingDownloads.end(),
  525. req);
  526. // If the LLAssetRequest doesn't exist in the downloads queue, then it either has already been deleted
  527. // by _cleanupRequests, or it's a transfer.
  528. if (download_iter != gAssetStorage->mPendingDownloads.end())
  529. {
  530. req->setUUID(file_id);
  531. req->setType(file_type);
  532. }
  533. if (LL_ERR_NOERR == result)
  534. {
  535. // we might have gotten a zero-size file
  536. LLVFile vfile(gAssetStorage->mVFS, req->getUUID(), req->getType());
  537. if (vfile.getSize() <= 0)
  538. {
  539. llwarns << "downloadCompleteCallback has non-existent or zero-size asset " << req->getUUID() << llendl;
  540. result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE;
  541. vfile.remove();
  542. }
  543. }
  544. // find and callback ALL pending requests for this UUID
  545. // SJB: We process the callbacks in reverse order, I do not know if this is important,
  546. // but I didn't want to mess with it.
  547. request_list_t requests;
  548. for (request_list_t::iterator iter = gAssetStorage->mPendingDownloads.begin();
  549. iter != gAssetStorage->mPendingDownloads.end(); )
  550. {
  551. request_list_t::iterator curiter = iter++;
  552. LLAssetRequest* tmp = *curiter;
  553. if ((tmp->getUUID() == file_id) && (tmp->getType()== file_type))
  554. {
  555. requests.push_front(tmp);
  556. iter = gAssetStorage->mPendingDownloads.erase(curiter);
  557. }
  558. }
  559. for (request_list_t::iterator iter = requests.begin();
  560. iter != requests.end(); )
  561. {
  562. request_list_t::iterator curiter = iter++;
  563. LLAssetRequest* tmp = *curiter;
  564. if (tmp->mDownCallback)
  565. {
  566. tmp->mDownCallback(gAssetStorage->mVFS, req->getUUID(), req->getType(), tmp->mUserData, result, ext_status);
  567. }
  568. delete tmp;
  569. }
  570. }
  571. void LLAssetStorage::getEstateAsset(const LLHost &object_sim, const LLUUID &agent_id, const LLUUID &session_id,
  572. const LLUUID &asset_id, LLAssetType::EType atype, EstateAssetType etype,
  573. LLGetAssetCallback callback, void *user_data, BOOL is_priority)
  574. {
  575. lldebugs << "LLAssetStorage::getEstateAsset() - " << asset_id << "," << LLAssetType::lookup(atype) << ", estatetype " << etype << llendl;
  576. //
  577. // Probably will get rid of this early out?
  578. //
  579. if (asset_id.isNull())
  580. {
  581. // Special case early out for NULL uuid
  582. if (callback)
  583. {
  584. callback(mVFS, asset_id, atype, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LL_EXSTAT_NULL_UUID);
  585. }
  586. return;
  587. }
  588. // Try static VFS first.
  589. if (findInStaticVFSAndInvokeCallback(asset_id,atype,callback,user_data))
  590. {
  591. return;
  592. }
  593. BOOL exists = mVFS->getExists(asset_id, atype);
  594. LLVFile file(mVFS, asset_id, atype);
  595. U32 size = exists ? file.getSize() : 0;
  596. if (size > 0)
  597. {
  598. // we've already got the file
  599. // theoretically, partial files w/o a pending request shouldn't happen
  600. // unless there's a weird error
  601. if (callback)
  602. {
  603. callback(mVFS, asset_id, atype, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED);
  604. }
  605. }
  606. else
  607. {
  608. if (exists)
  609. {
  610. llwarns << "Asset vfile " << asset_id << ":" << atype << " found with bad size " << file.getSize() << ", removing" << llendl;
  611. file.remove();
  612. }
  613. // See whether we should talk to the object's originating sim, or the upstream provider.
  614. LLHost source_host;
  615. if (object_sim.isOk())
  616. {
  617. source_host = object_sim;
  618. }
  619. else
  620. {
  621. source_host = mUpstreamHost;
  622. }
  623. if (source_host.isOk())
  624. {
  625. // stash the callback info so we can find it after we get the response message
  626. LLEstateAssetRequest *req = new LLEstateAssetRequest(asset_id, atype, etype);
  627. req->mDownCallback = callback;
  628. req->mUserData = user_data;
  629. req->mIsPriority = is_priority;
  630. // send request message to our upstream data provider
  631. // Create a new asset transfer.
  632. LLTransferSourceParamsEstate spe;
  633. spe.setAgentSession(agent_id, session_id);
  634. spe.setEstateAssetType(etype);
  635. // Set our destination file, and the completion callback.
  636. LLTransferTargetParamsVFile tpvf;
  637. tpvf.setAsset(asset_id, atype);
  638. tpvf.setCallback(downloadEstateAssetCompleteCallback, req);
  639. LL_DEBUGS("AssetStorage") << "Starting transfer for " << asset_id << llendl;
  640. LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(source_host, LLTCT_ASSET);
  641. ttcp->requestTransfer(spe, tpvf, 100.f + (is_priority ? 1.f : 0.f));
  642. }
  643. else
  644. {
  645. // uh-oh, we shouldn't have gotten here
  646. llwarns << "Attempt to move asset data request upstream w/o valid upstream provider" << llendl;
  647. if (callback)
  648. {
  649. callback(mVFS, asset_id, atype, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM);
  650. }
  651. }
  652. }
  653. }
  654. void LLAssetStorage::downloadEstateAssetCompleteCallback(
  655. S32 result,
  656. const LLUUID& file_id,
  657. LLAssetType::EType file_type,
  658. void* user_data,
  659. LLExtStat ext_status)
  660. {
  661. LLEstateAssetRequest *req = (LLEstateAssetRequest*)user_data;
  662. if(!req)
  663. {
  664. llwarns << "LLAssetStorage::downloadEstateAssetCompleteCallback called"
  665. " without a valid request." << llendl;
  666. return;
  667. }
  668. if (!gAssetStorage)
  669. {
  670. llwarns << "LLAssetStorage::downloadEstateAssetCompleteCallback called"
  671. " without any asset system, aborting!" << llendl;
  672. return;
  673. }
  674. req->setUUID(file_id);
  675. req->setType(file_type);
  676. if (LL_ERR_NOERR == result)
  677. {
  678. // we might have gotten a zero-size file
  679. LLVFile vfile(gAssetStorage->mVFS, req->getUUID(), req->getAType());
  680. if (vfile.getSize() <= 0)
  681. {
  682. llwarns << "downloadCompleteCallback has non-existent or zero-size asset!" << llendl;
  683. result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE;
  684. vfile.remove();
  685. }
  686. }
  687. req->mDownCallback(gAssetStorage->mVFS, req->getUUID(), req->getAType(), req->mUserData, result, ext_status);
  688. }
  689. void LLAssetStorage::getInvItemAsset(const LLHost &object_sim, const LLUUID &agent_id, const LLUUID &session_id,
  690. const LLUUID &owner_id, const LLUUID &task_id, const LLUUID &item_id,
  691. const LLUUID &asset_id, LLAssetType::EType atype,
  692. LLGetAssetCallback callback, void *user_data, BOOL is_priority)
  693. {
  694. lldebugs << "LLAssetStorage::getInvItemAsset() - " << asset_id << "," << LLAssetType::lookup(atype) << llendl;
  695. //
  696. // Probably will get rid of this early out?
  697. //
  698. //if (asset_id.isNull())
  699. //{
  700. // // Special case early out for NULL uuid
  701. // if (callback)
  702. // {
  703. // callback(mVFS, asset_id, atype, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE);
  704. // }
  705. // return;
  706. //}
  707. bool exists = false;
  708. U32 size = 0;
  709. if(asset_id.notNull())
  710. {
  711. // Try static VFS first.
  712. if (findInStaticVFSAndInvokeCallback( asset_id, atype, callback, user_data))
  713. {
  714. return;
  715. }
  716. exists = mVFS->getExists(asset_id, atype);
  717. LLVFile file(mVFS, asset_id, atype);
  718. size = exists ? file.getSize() : 0;
  719. if(exists && size < 1)
  720. {
  721. llwarns << "Asset vfile " << asset_id << ":" << atype << " found with bad size " << file.getSize() << ", removing" << llendl;
  722. file.remove();
  723. }
  724. }
  725. if (size > 0)
  726. {
  727. // we've already got the file
  728. // theoretically, partial files w/o a pending request shouldn't happen
  729. // unless there's a weird error
  730. if (callback)
  731. {
  732. callback(mVFS, asset_id, atype, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED);
  733. }
  734. }
  735. else
  736. {
  737. // See whether we should talk to the object's originating sim,
  738. // or the upstream provider.
  739. LLHost source_host;
  740. if (object_sim.isOk())
  741. {
  742. source_host = object_sim;
  743. }
  744. else
  745. {
  746. source_host = mUpstreamHost;
  747. }
  748. if (source_host.isOk())
  749. {
  750. // stash the callback info so we can find it after we get the response message
  751. LLInvItemRequest *req = new LLInvItemRequest(asset_id, atype);
  752. req->mDownCallback = callback;
  753. req->mUserData = user_data;
  754. req->mIsPriority = is_priority;
  755. // send request message to our upstream data provider
  756. // Create a new asset transfer.
  757. LLTransferSourceParamsInvItem spi;
  758. spi.setAgentSession(agent_id, session_id);
  759. spi.setInvItem(owner_id, task_id, item_id);
  760. spi.setAsset(asset_id, atype);
  761. // Set our destination file, and the completion callback.
  762. LLTransferTargetParamsVFile tpvf;
  763. tpvf.setAsset(asset_id, atype);
  764. tpvf.setCallback(downloadInvItemCompleteCallback, req);
  765. LL_DEBUGS("AssetStorage") << "Starting transfer for inventory asset "
  766. << item_id << " owned by " << owner_id << "," << task_id
  767. << llendl;
  768. LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(source_host, LLTCT_ASSET);
  769. ttcp->requestTransfer(spi, tpvf, 100.f + (is_priority ? 1.f : 0.f));
  770. }
  771. else
  772. {
  773. // uh-oh, we shouldn't have gotten here
  774. llwarns << "Attempt to move asset data request upstream w/o valid upstream provider" << llendl;
  775. if (callback)
  776. {
  777. callback(mVFS, asset_id, atype, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM);
  778. }
  779. }
  780. }
  781. }
  782. void LLAssetStorage::downloadInvItemCompleteCallback(
  783. S32 result,
  784. const LLUUID& file_id,
  785. LLAssetType::EType file_type,
  786. void* user_data,
  787. LLExtStat ext_status)
  788. {
  789. LLInvItemRequest *req = (LLInvItemRequest*)user_data;
  790. if(!req)
  791. {
  792. llwarns << "LLAssetStorage::downloadEstateAssetCompleteCallback called"
  793. " without a valid request." << llendl;
  794. return;
  795. }
  796. if (!gAssetStorage)
  797. {
  798. llwarns << "LLAssetStorage::downloadCompleteCallback called without any asset system, aborting!" << llendl;
  799. return;
  800. }
  801. req->setUUID(file_id);
  802. req->setType(file_type);
  803. if (LL_ERR_NOERR == result)
  804. {
  805. // we might have gotten a zero-size file
  806. LLVFile vfile(gAssetStorage->mVFS, req->getUUID(), req->getType());
  807. if (vfile.getSize() <= 0)
  808. {
  809. llwarns << "downloadCompleteCallback has non-existent or zero-size asset!" << llendl;
  810. result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE;
  811. vfile.remove();
  812. }
  813. }
  814. req->mDownCallback(gAssetStorage->mVFS, req->getUUID(), req->getType(), req->mUserData, result, ext_status);
  815. }
  816. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  817. // Store routines
  818. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  819. // static
  820. void LLAssetStorage::uploadCompleteCallback(const LLUUID& uuid, void *user_data, S32 result, LLExtStat ext_status) // StoreAssetData callback (fixed)
  821. {
  822. if (!gAssetStorage)
  823. {
  824. llwarns << "LLAssetStorage::uploadCompleteCallback has no gAssetStorage!" << llendl;
  825. return;
  826. }
  827. LLAssetRequest *req = (LLAssetRequest *)user_data;
  828. BOOL success = TRUE;
  829. if (result)
  830. {
  831. llwarns << "LLAssetStorage::uploadCompleteCallback " << result << ":" << getErrorString(result) << " trying to upload file to upstream provider" << llendl;
  832. success = FALSE;
  833. }
  834. // we're done grabbing the file, tell the client
  835. gAssetStorage->mMessageSys->newMessageFast(_PREHASH_AssetUploadComplete);
  836. gAssetStorage->mMessageSys->nextBlockFast(_PREHASH_AssetBlock);
  837. gAssetStorage->mMessageSys->addUUIDFast(_PREHASH_UUID, uuid);
  838. gAssetStorage->mMessageSys->addS8Fast(_PREHASH_Type, req->getType());
  839. gAssetStorage->mMessageSys->addBOOLFast(_PREHASH_Success, success);
  840. gAssetStorage->mMessageSys->sendReliable(req->mHost);
  841. delete req;
  842. }
  843. void LLAssetStorage::processUploadComplete(LLMessageSystem *msg, void **user_data)
  844. {
  845. LLAssetStorage *this_ptr = (LLAssetStorage *)user_data;
  846. LLUUID uuid;
  847. S8 asset_type_s8;
  848. LLAssetType::EType asset_type;
  849. BOOL success = FALSE;
  850. msg->getUUIDFast(_PREHASH_AssetBlock, _PREHASH_UUID, uuid);
  851. msg->getS8Fast(_PREHASH_AssetBlock, _PREHASH_Type, asset_type_s8);
  852. msg->getBOOLFast(_PREHASH_AssetBlock, _PREHASH_Success, success);
  853. asset_type = (LLAssetType::EType)asset_type_s8;
  854. this_ptr->_callUploadCallbacks(uuid, asset_type, success, LL_EXSTAT_NONE);
  855. }
  856. void LLAssetStorage::_callUploadCallbacks(const LLUUID &uuid, LLAssetType::EType asset_type, BOOL success, LLExtStat ext_status )
  857. {
  858. // SJB: We process the callbacks in reverse order, I do not know if this is important,
  859. // but I didn't want to mess with it.
  860. request_list_t requests;
  861. for (request_list_t::iterator iter = mPendingUploads.begin();
  862. iter != mPendingUploads.end(); )
  863. {
  864. request_list_t::iterator curiter = iter++;
  865. LLAssetRequest* req = *curiter;
  866. if ((req->getUUID() == uuid) && (req->getType() == asset_type))
  867. {
  868. requests.push_front(req);
  869. iter = mPendingUploads.erase(curiter);
  870. }
  871. }
  872. for (request_list_t::iterator iter = mPendingLocalUploads.begin();
  873. iter != mPendingLocalUploads.end(); )
  874. {
  875. request_list_t::iterator curiter = iter++;
  876. LLAssetRequest* req = *curiter;
  877. if ((req->getUUID() == uuid) && (req->getType() == asset_type))
  878. {
  879. requests.push_front(req);
  880. iter = mPendingLocalUploads.erase(curiter);
  881. }
  882. }
  883. for (request_list_t::iterator iter = requests.begin();
  884. iter != requests.end(); )
  885. {
  886. request_list_t::iterator curiter = iter++;
  887. LLAssetRequest* req = *curiter;
  888. if (req->mUpCallback)
  889. {
  890. req->mUpCallback(uuid, req->mUserData, (success ? LL_ERR_NOERR : LL_ERR_ASSET_REQUEST_FAILED ), ext_status );
  891. }
  892. delete req;
  893. }
  894. }
  895. LLAssetStorage::request_list_t* LLAssetStorage::getRequestList(LLAssetStorage::ERequestType rt)
  896. {
  897. switch (rt)
  898. {
  899. case RT_DOWNLOAD:
  900. return &mPendingDownloads;
  901. case RT_UPLOAD:
  902. return &mPendingUploads;
  903. case RT_LOCALUPLOAD:
  904. return &mPendingLocalUploads;
  905. default:
  906. llwarns << "Unable to find request list for request type '" << rt << "'" << llendl;
  907. return NULL;
  908. }
  909. }
  910. const LLAssetStorage::request_list_t* LLAssetStorage::getRequestList(LLAssetStorage::ERequestType rt) const
  911. {
  912. switch (rt)
  913. {
  914. case RT_DOWNLOAD:
  915. return &mPendingDownloads;
  916. case RT_UPLOAD:
  917. return &mPendingUploads;
  918. case RT_LOCALUPLOAD:
  919. return &mPendingLocalUploads;
  920. default:
  921. llwarns << "Unable to find request list for request type '" << rt << "'" << llendl;
  922. return NULL;
  923. }
  924. }
  925. // static
  926. std::string LLAssetStorage::getRequestName(LLAssetStorage::ERequestType rt)
  927. {
  928. switch (rt)
  929. {
  930. case RT_DOWNLOAD:
  931. return "download";
  932. case RT_UPLOAD:
  933. return "upload";
  934. case RT_LOCALUPLOAD:
  935. return "localupload";
  936. default:
  937. llwarns << "Unable to find request name for request type '" << rt << "'" << llendl;
  938. return "";
  939. }
  940. }
  941. S32 LLAssetStorage::getNumPending(LLAssetStorage::ERequestType rt) const
  942. {
  943. const request_list_t* requests = getRequestList(rt);
  944. S32 num_pending = -1;
  945. if (requests)
  946. {
  947. num_pending = requests->size();
  948. }
  949. return num_pending;
  950. }
  951. S32 LLAssetStorage::getNumPendingDownloads() const
  952. {
  953. return getNumPending(RT_DOWNLOAD);
  954. }
  955. S32 LLAssetStorage::getNumPendingUploads() const
  956. {
  957. return getNumPending(RT_UPLOAD);
  958. }
  959. S32 LLAssetStorage::getNumPendingLocalUploads()
  960. {
  961. return getNumPending(RT_LOCALUPLOAD);
  962. }
  963. // virtual
  964. LLSD LLAssetStorage::getPendingDetails(LLAssetStorage::ERequestType rt,
  965. LLAssetType::EType asset_type,
  966. const std::string& detail_prefix) const
  967. {
  968. const request_list_t* requests = getRequestList(rt);
  969. LLSD sd;
  970. sd["requests"] = getPendingDetailsImpl(requests, asset_type, detail_prefix);
  971. return sd;
  972. }
  973. // virtual
  974. LLSD LLAssetStorage::getPendingDetailsImpl(const LLAssetStorage::request_list_t* requests,
  975. LLAssetType::EType asset_type,
  976. const std::string& detail_prefix) const
  977. {
  978. LLSD details;
  979. if (requests)
  980. {
  981. request_list_t::const_iterator it = requests->begin();
  982. request_list_t::const_iterator end = requests->end();
  983. for ( ; it != end; ++it)
  984. {
  985. LLAssetRequest* req = *it;
  986. if ( (LLAssetType::AT_NONE == asset_type)
  987. || (req->getType() == asset_type) )
  988. {
  989. LLSD row = req->getTerseDetails();
  990. std::ostringstream detail;
  991. detail << detail_prefix << "/" << LLAssetType::lookup(req->getType())
  992. << "/" << req->getUUID();
  993. row["detail"] = LLURI(detail.str());
  994. details.append(row);
  995. }
  996. }
  997. }
  998. return details;
  999. }
  1000. // static
  1001. const LLAssetRequest* LLAssetStorage::findRequest(const LLAssetStorage::request_list_t* requests,
  1002. LLAssetType::EType asset_type,
  1003. const LLUUID& asset_id)
  1004. {
  1005. if (requests)
  1006. {
  1007. // Search the requests list for the asset.
  1008. request_list_t::const_iterator iter = requests->begin();
  1009. request_list_t::const_iterator end = requests->end();
  1010. for (; iter != end; ++iter)
  1011. {
  1012. const LLAssetRequest* req = *iter;
  1013. if (asset_type == req->getType() &&
  1014. asset_id == req->getUUID() )
  1015. {
  1016. return req;
  1017. }
  1018. }
  1019. }
  1020. return NULL;
  1021. }
  1022. // static
  1023. LLAssetRequest* LLAssetStorage::findRequest(LLAssetStorage::request_list_t* requests,
  1024. LLAssetType::EType asset_type,
  1025. const LLUUID& asset_id)
  1026. {
  1027. if (requests)
  1028. {
  1029. // Search the requests list for the asset.
  1030. request_list_t::iterator iter = requests->begin();
  1031. request_list_t::iterator end = requests->end();
  1032. for (; iter != end; ++iter)
  1033. {
  1034. LLAssetRequest* req = *iter;
  1035. if (asset_type == req->getType() &&
  1036. asset_id == req->getUUID() )
  1037. {
  1038. return req;
  1039. }
  1040. }
  1041. }
  1042. return NULL;
  1043. }
  1044. // virtual
  1045. LLSD LLAssetStorage::getPendingRequest(LLAssetStorage::ERequestType rt,
  1046. LLAssetType::EType asset_type,
  1047. const LLUUID& asset_id) const
  1048. {
  1049. const request_list_t* requests = getRequestList(rt);
  1050. return getPendingRequestImpl(requests, asset_type, asset_id);
  1051. }
  1052. // virtual
  1053. LLSD LLAssetStorage::getPendingRequestImpl(const LLAssetStorage::request_list_t* requests,
  1054. LLAssetType::EType asset_type,
  1055. const LLUUID& asset_id) const
  1056. {
  1057. LLSD sd;
  1058. const LLAssetRequest* req = findRequest(requests, asset_type, asset_id);
  1059. if (req)
  1060. {
  1061. sd = req->getFullDetails();
  1062. }
  1063. return sd;
  1064. }
  1065. // virtual
  1066. bool LLAssetStorage::deletePendingRequest(LLAssetStorage::ERequestType rt,
  1067. LLAssetType::EType asset_type,
  1068. const LLUUID& asset_id)
  1069. {
  1070. request_list_t* requests = getRequestList(rt);
  1071. if (deletePendingRequestImpl(requests, asset_type, asset_id))
  1072. {
  1073. LL_DEBUGS("AssetStorage") << "Asset " << getRequestName(rt) << " request for "
  1074. << asset_id << "." << LLAssetType::lookup(asset_type)
  1075. << " removed from pending queue." << llendl;
  1076. return true;
  1077. }
  1078. return false;
  1079. }
  1080. // virtual
  1081. bool LLAssetStorage::deletePendingRequestImpl(LLAssetStorage::request_list_t* requests,
  1082. LLAssetType::EType asset_type,
  1083. const LLUUID& asset_id)
  1084. {
  1085. LLAssetRequest* req = findRequest(requests, asset_type, asset_id);
  1086. if (req)
  1087. {
  1088. // Remove the request from this list.
  1089. requests->remove(req);
  1090. S32 error = LL_ERR_TCP_TIMEOUT;
  1091. // Run callbacks.
  1092. if (req->mUpCallback)
  1093. {
  1094. req->mUpCallback(req->getUUID(), req->mUserData, error, LL_EXSTAT_REQUEST_DROPPED);
  1095. }
  1096. if (req->mDownCallback)
  1097. {
  1098. req->mDownCallback(mVFS, req->getUUID(), req->getType(), req->mUserData, error, LL_EXSTAT_REQUEST_DROPPED);
  1099. }
  1100. if (req->mInfoCallback)
  1101. {
  1102. LLAssetInfo info;
  1103. req->mInfoCallback(&info, req->mUserData, error);
  1104. }
  1105. delete req;
  1106. return true;
  1107. }
  1108. return false;
  1109. }
  1110. // static
  1111. const char* LLAssetStorage::getErrorString(S32 status)
  1112. {
  1113. switch( status )
  1114. {
  1115. case LL_ERR_NOERR:
  1116. return "No error";
  1117. case LL_ERR_ASSET_REQUEST_FAILED:
  1118. return "Asset request: failed";
  1119. case LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE:
  1120. return "Asset request: non-existent file";
  1121. case LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE:
  1122. return "Asset request: asset not found in database";
  1123. case LL_ERR_EOF:
  1124. return "End of file";
  1125. case LL_ERR_CANNOT_OPEN_FILE:
  1126. return "Cannot open file";
  1127. case LL_ERR_FILE_NOT_FOUND:
  1128. return "File not found";
  1129. case LL_ERR_TCP_TIMEOUT:
  1130. return "File transfer timeout";
  1131. case LL_ERR_CIRCUIT_GONE:
  1132. return "Circuit gone";
  1133. case LL_ERR_PRICE_MISMATCH:
  1134. return "Viewer and server do not agree on price";
  1135. default:
  1136. return "Unknown status";
  1137. }
  1138. }
  1139. void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, void (*callback)(const char*, const LLUUID&, void *, S32, LLExtStat), void *user_data, BOOL is_priority)
  1140. {
  1141. // check for duplicates here, since we're about to fool the normal duplicate checker
  1142. for (request_list_t::iterator iter = mPendingDownloads.begin();
  1143. iter != mPendingDownloads.end(); )
  1144. {
  1145. LLAssetRequest* tmp = *iter++;
  1146. if (type == tmp->getType() &&
  1147. uuid == tmp->getUUID() &&
  1148. legacyGetDataCallback == tmp->mDownCallback &&
  1149. callback == ((LLLegacyAssetRequest *)tmp->mUserData)->mDownCallback &&
  1150. user_data == ((LLLegacyAssetRequest *)tmp->mUserData)->mUserData)
  1151. {
  1152. // this is a duplicate from the same subsystem - throw it away
  1153. LL_DEBUGS("AssetStorage") << "Discarding duplicate request for UUID " << uuid << llendl;
  1154. return;
  1155. }
  1156. }
  1157. LLLegacyAssetRequest *legacy = new LLLegacyAssetRequest;
  1158. legacy->mDownCallback = callback;
  1159. legacy->mUserData = user_data;
  1160. getAssetData(uuid, type, legacyGetDataCallback, (void **)legacy,
  1161. is_priority);
  1162. }
  1163. // static
  1164. void LLAssetStorage::legacyGetDataCallback(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type, void *user_data, S32 status, LLExtStat ext_status)
  1165. {
  1166. LLLegacyAssetRequest *legacy = (LLLegacyAssetRequest *)user_data;
  1167. std::string filename;
  1168. // Check if the asset is marked toxic, and don't load bad stuff
  1169. BOOL toxic = gAssetStorage->isAssetToxic( uuid );
  1170. if ( !status
  1171. && !toxic )
  1172. {
  1173. LLVFile file(vfs, uuid, type);
  1174. std::string uuid_str;
  1175. uuid.toString(uuid_str);
  1176. filename = llformat("%s.%s",gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_str).c_str(),LLAssetType::lookup(type));
  1177. LLFILE* fp = LLFile::fopen(filename, "wb"); /* Flawfinder: ignore */
  1178. if (fp)
  1179. {
  1180. const S32 buf_size = 65536;
  1181. U8 copy_buf[buf_size];
  1182. while (file.read(copy_buf, buf_size)) /* Flawfinder: ignore */
  1183. {
  1184. if (fwrite(copy_buf, file.getLastBytesRead(), 1, fp) < 1)
  1185. {
  1186. // return a bad file error if we can't write the whole thing
  1187. status = LL_ERR_CANNOT_OPEN_FILE;
  1188. }
  1189. }
  1190. fclose(fp);
  1191. }
  1192. else
  1193. {
  1194. status = LL_ERR_CANNOT_OPEN_FILE;
  1195. }
  1196. }
  1197. legacy->mDownCallback(filename.c_str(), uuid, legacy->mUserData, status, ext_status);
  1198. delete legacy;
  1199. }
  1200. // this is overridden on the viewer and the sim, so it doesn't really do anything
  1201. // virtual
  1202. void LLAssetStorage::storeAssetData(
  1203. const LLTransactionID& tid,
  1204. LLAssetType::EType asset_type,
  1205. LLStoreAssetCallback callback,
  1206. void* user_data,
  1207. bool temp_file,
  1208. bool is_priority,
  1209. bool store_local,
  1210. bool user_waiting,
  1211. F64 timeout)
  1212. {
  1213. llwarns << "storeAssetData: wrong version called" << llendl;
  1214. // LLAssetStorage metric: Virtual base call
  1215. reportMetric( LLUUID::null, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_BAD_FUNCTION, __FILE__, __LINE__, "Illegal call to base: LLAssetStorage::storeAssetData 1" );
  1216. }
  1217. // virtual
  1218. // this does nothing, viewer and sim both override this.
  1219. void LLAssetStorage::storeAssetData(
  1220. const LLUUID& asset_id,
  1221. LLAssetType::EType asset_type,
  1222. LLStoreAssetCallback callback,
  1223. void* user_data,
  1224. bool temp_file ,
  1225. bool is_priority,
  1226. bool store_local,
  1227. const LLUUID& requesting_agent_id,
  1228. bool user_waiting,
  1229. F64 timeout)
  1230. {
  1231. llwarns << "storeAssetData: wrong version called" << llendl;
  1232. // LLAssetStorage metric: Virtual base call
  1233. reportMetric( asset_id, asset_type, LLStringUtil::null, requesting_agent_id, 0, MR_BAD_FUNCTION, __FILE__, __LINE__, "Illegal call to base: LLAssetStorage::storeAssetData 2" );
  1234. }
  1235. // virtual
  1236. // this does nothing, viewer and sim both override this.
  1237. void LLAssetStorage::storeAssetData(
  1238. const std::string& filename,
  1239. const LLUUID& asset_id,
  1240. LLAssetType::EType asset_type,
  1241. LLStoreAssetCallback callback,
  1242. void* user_data,
  1243. bool temp_file,
  1244. bool is_priority,
  1245. bool user_waiting,
  1246. F64 timeout)
  1247. {
  1248. llwarns << "storeAssetData: wrong version called" << llendl;
  1249. // LLAssetStorage metric: Virtual base call
  1250. reportMetric( asset_id, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_BAD_FUNCTION, __FILE__, __LINE__, "Illegal call to base: LLAssetStorage::storeAssetData 3" );
  1251. }
  1252. // virtual
  1253. // this does nothing, viewer and sim both override this.
  1254. void LLAssetStorage::storeAssetData(
  1255. const std::string& filename,
  1256. const LLTransactionID &transactoin_id,
  1257. LLAssetType::EType asset_type,
  1258. LLStoreAssetCallback callback,
  1259. void* user_data,
  1260. bool temp_file,
  1261. bool is_priority,
  1262. bool user_waiting,
  1263. F64 timeout)
  1264. {
  1265. llwarns << "storeAssetData: wrong version called" << llendl;
  1266. // LLAssetStorage metric: Virtual base call
  1267. reportMetric( LLUUID::null, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_BAD_FUNCTION, __FILE__, __LINE__, "Illegal call to base: LLAssetStorage::storeAssetData 4" );
  1268. }
  1269. // static
  1270. void LLAssetStorage::legacyStoreDataCallback(const LLUUID &uuid, void *user_data, S32 status, LLExtStat ext_status)
  1271. {
  1272. LLLegacyAssetRequest *legacy = (LLLegacyAssetRequest *)user_data;
  1273. if (legacy && legacy->mUpCallback)
  1274. {
  1275. legacy->mUpCallback(uuid, legacy->mUserData, status, ext_status);
  1276. }
  1277. delete legacy;
  1278. }
  1279. // virtual
  1280. void LLAssetStorage::addTempAssetData(const LLUUID& asset_id, const LLUUID& agent_id, const std::string& host_name)
  1281. { }
  1282. // virtual
  1283. BOOL LLAssetStorage::hasTempAssetData(const LLUUID& texture_id) const
  1284. { return FALSE; }
  1285. // virtual
  1286. std::string LLAssetStorage::getTempAssetHostName(const LLUUID& texture_id) const
  1287. { return std::string(); }
  1288. // virtual
  1289. LLUUID LLAssetStorage::getTempAssetAgentID(const LLUUID& texture_id) const
  1290. { return LLUUID::null; }
  1291. // virtual
  1292. void LLAssetStorage::removeTempAssetData(const LLUUID& asset_id)
  1293. { }
  1294. // virtual
  1295. void LLAssetStorage::removeTempAssetDataByAgentID(const LLUUID& agent_id)
  1296. { }
  1297. // virtual
  1298. void LLAssetStorage::dumpTempAssetData(const LLUUID& avatar_id) const
  1299. { }
  1300. // virtual
  1301. void LLAssetStorage::clearTempAssetData()
  1302. { }
  1303. // static
  1304. void LLAssetStorage::reportMetric( const LLUUID& asset_id, const LLAssetType::EType asset_type, const std::string& in_filename,
  1305. const LLUUID& agent_id, S32 asset_size, EMetricResult result,
  1306. const char *file, const S32 line, const std::string& in_message )
  1307. {
  1308. if( !metric_recipient )
  1309. {
  1310. LL_DEBUGS("AssetStorage") << "Couldn't store LLAssetStoreage::reportMetric - no metrics_recipient" << llendl;
  1311. return;
  1312. }
  1313. std::string filename(in_filename);
  1314. if (filename.empty())
  1315. filename = ll_safe_string(file);
  1316. // Create revised message - new_message = "in_message :: file:line"
  1317. std::stringstream new_message;
  1318. new_message << in_message << " :: " << filename << ":" << line;
  1319. // Change always_report to true if debugging... do not check it in this way
  1320. static bool always_report = false;
  1321. const char *metric_name = "LLAssetStorage::Metrics";
  1322. bool success = result == MR_OKAY;
  1323. if( (!success) || always_report )
  1324. {
  1325. LLSD stats;
  1326. stats["asset_id"] = asset_id;
  1327. stats["asset_type"] = asset_type;
  1328. stats["filename"] = filename;
  1329. stats["agent_id"] = agent_id;
  1330. stats["asset_size"] = (S32)asset_size;
  1331. stats["result"] = (S32)result;
  1332. metric_recipient->recordEventDetails( metric_name, new_message.str(), success, stats);
  1333. }
  1334. else
  1335. {
  1336. metric_recipient->recordEvent(metric_name, new_message.str(), success);
  1337. }
  1338. }
  1339. // Check if an asset is in the toxic map. If it is, the entry is updated
  1340. BOOL LLAssetStorage::isAssetToxic( const LLUUID& uuid )
  1341. {
  1342. BOOL is_toxic = FALSE;
  1343. if ( !uuid.isNull() )
  1344. {
  1345. toxic_asset_map_t::iterator iter = mToxicAssetMap.find( uuid );
  1346. if ( iter != mToxicAssetMap.end() )
  1347. { // Found toxic asset
  1348. (*iter).second = LLFrameTimer::getTotalTime() + TOXIC_ASSET_LIFETIME;
  1349. is_toxic = TRUE;
  1350. }
  1351. }
  1352. return is_toxic;
  1353. }
  1354. // Clean the toxic asset list, remove old entries
  1355. void LLAssetStorage::flushOldToxicAssets( BOOL force_it )
  1356. {
  1357. // Scan and look for old entries
  1358. U64 now = LLFrameTimer::getTotalTime();
  1359. toxic_asset_map_t::iterator iter = mToxicAssetMap.begin();
  1360. while ( iter != mToxicAssetMap.end() )
  1361. {
  1362. if ( force_it
  1363. || (*iter).second < now )
  1364. { // Too old - remove it
  1365. mToxicAssetMap.erase( iter++ );
  1366. }
  1367. else
  1368. {
  1369. iter++;
  1370. }
  1371. }
  1372. }
  1373. // Add an item to the toxic asset map
  1374. void LLAssetStorage::markAssetToxic( const LLUUID& uuid )
  1375. {
  1376. if ( !uuid.isNull() )
  1377. {
  1378. // Set the value to the current time. Creates a new entry if needed
  1379. mToxicAssetMap[ uuid ] = LLFrameTimer::getTotalTime() + TOXIC_ASSET_LIFETIME;
  1380. }
  1381. }