llassetstorage.cpp 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381
  1. /**
  2. * @file llassetstorage.cpp
  3. * @brief Implementation of the base asset storage system.
  4. *
  5. * $LicenseInfo:firstyear=2001&license=viewergpl$
  6. *
  7. * Copyright (c) 2001-2009, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #include "linden_common.h"
  33. #include <sys/types.h>
  34. #include <sys/stat.h>
  35. #include "llassetstorage.h"
  36. #include "lldbstrings.h"
  37. #include "lldir.h"
  38. #include "llfilesystem.h"
  39. #include "llframetimer.h"
  40. #include "llmath.h"
  41. #include "llsd.h"
  42. #include "llstring.h"
  43. #include "lltransfertargetvfile.h"
  44. #include "llxfermanager.h"
  45. #include "llmessage.h"
  46. LLAssetStorage* gAssetStoragep = NULL;
  47. const LLUUID CATEGORIZE_LOST_AND_FOUND_ID(std::string("00000000-0000-0000-0000-000000000010"));
  48. constexpr U64 TOXIC_ASSET_LIFETIME = 120 * 1000000; // In microseconds
  49. //-----------------------------------------------------------------------------
  50. // LLAssetInfo class
  51. //-----------------------------------------------------------------------------
  52. LLAssetInfo::LLAssetInfo()
  53. : mDescription(),
  54. mName(),
  55. mUuid(),
  56. mCreatorID(),
  57. mType(LLAssetType::AT_NONE)
  58. {
  59. }
  60. LLAssetInfo::LLAssetInfo(const LLUUID& object_id, const LLUUID& creator_id,
  61. LLAssetType::EType type, const char* name,
  62. const char* desc)
  63. : mUuid(object_id),
  64. mCreatorID(creator_id),
  65. mType(type)
  66. {
  67. setName(name);
  68. setDescription(desc);
  69. }
  70. LLAssetInfo::LLAssetInfo(const LLNameValue& nv)
  71. {
  72. setFromNameValue(nv);
  73. }
  74. // Make sure the name is short enough, and strip all pipes since they are
  75. // reserved characters in our inventory tracking system.
  76. void LLAssetInfo::setName(const std::string& name)
  77. {
  78. if (!name.empty())
  79. {
  80. mName.assign(name, 0, llmin((U32)name.size(),
  81. (U32)DB_INV_ITEM_NAME_STR_LEN));
  82. mName.erase(std::remove(mName.begin(), mName.end(), '|'), mName.end());
  83. }
  84. }
  85. // Make sure the name is short enough, and strip all pipes since they are
  86. // reserved characters in our inventory tracking system.
  87. void LLAssetInfo::setDescription(const std::string& desc)
  88. {
  89. if (!desc.empty())
  90. {
  91. mDescription.assign(desc, 0, llmin((U32)desc.size(),
  92. (U32)DB_INV_ITEM_DESC_STR_LEN));
  93. mDescription.erase(std::remove(mDescription.begin(),
  94. mDescription.end(), '|'),
  95. mDescription.end());
  96. }
  97. }
  98. // Assets (aka potential inventory items) can be applied to an object in the
  99. // world. We'll store that as a string name value pair where the name encodes
  100. // part of asset info, and the value the rest. LLAssetInfo objects will be
  101. // responsible for parsing the meaning out froman LLNameValue object. See the
  102. // inventory design docs for details. Briefly:
  103. // name=<inv_type>|<uuid>
  104. // value=<creatorid>|<name>|<description>|
  105. void LLAssetInfo::setFromNameValue(const LLNameValue& nv)
  106. {
  107. std::string str;
  108. std::string buf;
  109. std::string::size_type pos1;
  110. std::string::size_type pos2;
  111. // convert the name to useful information
  112. str.assign(nv.mName);
  113. pos1 = str.find('|');
  114. buf.assign(str, 0, pos1++);
  115. mType = LLAssetType::lookup(buf);
  116. buf.assign(str, pos1, std::string::npos);
  117. mUuid.set(buf);
  118. // convert the value to useful information
  119. str.assign(nv.getAsset());
  120. pos1 = str.find('|');
  121. buf.assign(str, 0, pos1++);
  122. mCreatorID.set(buf);
  123. pos2 = str.find('|', pos1);
  124. buf.assign(str, pos1, (pos2++) - pos1);
  125. setName(buf);
  126. buf.assign(str, pos2, std::string::npos);
  127. setDescription(buf);
  128. llinfos << "uuid: " << mUuid << " - creator: " << mCreatorID << llendl;
  129. }
  130. //-----------------------------------------------------------------------------
  131. // LLBaseDownloadRequest class
  132. //-----------------------------------------------------------------------------
  133. LLBaseDownloadRequest::LLBaseDownloadRequest(const LLUUID& uuid,
  134. const LLAssetType::EType type)
  135. : mUUID(uuid),
  136. mType(type),
  137. mDownCallback(NULL),
  138. mUserData(NULL),
  139. mHost(),
  140. mIsTemp(false),
  141. mIsPriority(false),
  142. mDataSentInFirstPacket(false),
  143. mDataIsInCache(false)
  144. {
  145. // Need to guarantee that this time is up to date, we may be creating a
  146. // circuit even though we haven't been running a message system loop.
  147. mTime = LLMessageSystem::getMessageTimeSeconds(true);
  148. }
  149. //virtual
  150. LLBaseDownloadRequest* LLBaseDownloadRequest::getCopy()
  151. {
  152. return new LLBaseDownloadRequest(*this);
  153. }
  154. //-----------------------------------------------------------------------------
  155. // LLAssetRequest class
  156. //-----------------------------------------------------------------------------
  157. LLAssetRequest::LLAssetRequest(const LLUUID& uuid,
  158. const LLAssetType::EType type)
  159. : LLBaseDownloadRequest(uuid, type),
  160. mUpCallback(NULL),
  161. mInfoCallback(NULL),
  162. mIsLocal(false),
  163. mTimeout(LL_ASSET_STORAGE_TIMEOUT)
  164. {
  165. }
  166. //virtual
  167. LLSD LLAssetRequest::getTerseDetails() const
  168. {
  169. LLSD sd;
  170. sd["asset_id"] = getUUID();
  171. sd["type_long"] = LLAssetType::lookupHumanReadable(getType());
  172. sd["type"] = LLAssetType::lookup(getType());
  173. sd["time"] = mTime;
  174. time_t timestamp = (time_t)mTime;
  175. std::ostringstream time_string;
  176. time_string << ctime(&timestamp);
  177. sd["time_string"] = time_string.str();
  178. return sd;
  179. }
  180. //virtual
  181. LLSD LLAssetRequest::getFullDetails() const
  182. {
  183. LLSD sd = getTerseDetails();
  184. sd["host"] = mHost.getIPandPort();
  185. sd["requesting_agent"] = mRequestingAgentID;
  186. sd["is_temp"] = mIsTemp;
  187. sd["is_local"] = mIsLocal;
  188. sd["is_priority"] = mIsPriority;
  189. sd["data_send_in_first_packet"] = mDataSentInFirstPacket;
  190. // Note: cannot change this (easily) for "data_is_in_cache" since it is
  191. // consumed by server...
  192. sd["data_is_in_vfs"] = mDataIsInCache;
  193. return sd;
  194. }
  195. //virtual
  196. LLBaseDownloadRequest* LLAssetRequest::getCopy()
  197. {
  198. return new LLAssetRequest(*this);
  199. }
  200. //-----------------------------------------------------------------------------
  201. // LLInvItemRequest class
  202. //-----------------------------------------------------------------------------
  203. LLInvItemRequest::LLInvItemRequest(const LLUUID& uuid,
  204. const LLAssetType::EType type)
  205. : LLBaseDownloadRequest(uuid, type)
  206. {
  207. }
  208. //virtual
  209. LLBaseDownloadRequest* LLInvItemRequest::getCopy()
  210. {
  211. return new LLInvItemRequest(*this);
  212. }
  213. //-----------------------------------------------------------------------------
  214. // LLEstateAssetRequest class
  215. //-----------------------------------------------------------------------------
  216. LLEstateAssetRequest::LLEstateAssetRequest(const LLUUID& uuid,
  217. const LLAssetType::EType atype,
  218. EstateAssetType etype)
  219. : LLBaseDownloadRequest(uuid, atype),
  220. mEstateAssetType(etype)
  221. {
  222. }
  223. LLBaseDownloadRequest* LLEstateAssetRequest::getCopy()
  224. {
  225. return new LLEstateAssetRequest(*this);
  226. }
  227. //-----------------------------------------------------------------------------
  228. // LLAssetStorage class
  229. //-----------------------------------------------------------------------------
  230. // Since many of these functions are called by the messaging and xfer systems,
  231. // they are declared as static and are passed a "this" handle it's a C/C++
  232. // mish-mash !
  233. // *TODO: permissions on modifications: maybe do not allow at all ?
  234. // *TODO: verify that failures get propogated down
  235. // *TODO: rework tempfile handling ?
  236. LLAssetStorage::LLAssetStorage(LLMessageSystem* msg, LLXferManager* xfer,
  237. const LLHost& upstream_host)
  238. {
  239. init(msg, xfer, upstream_host);
  240. }
  241. LLAssetStorage::LLAssetStorage(LLMessageSystem* msg, LLXferManager* xfer)
  242. {
  243. init(msg, xfer, LLHost());
  244. }
  245. void LLAssetStorage::init(LLMessageSystem* msg, LLXferManager* xfer,
  246. const LLHost& upstream_host)
  247. {
  248. mShutDown = false;
  249. mMessageSys = msg;
  250. mXferManager = xfer;
  251. setUpstream(upstream_host);
  252. msg->setHandlerFuncFast(_PREHASH_AssetUploadComplete,
  253. processUploadComplete, (void **)this);
  254. }
  255. LLAssetStorage::~LLAssetStorage()
  256. {
  257. mShutDown = true;
  258. cleanupRequests(true, LL_ERR_CIRCUIT_GONE);
  259. if (gMessageSystemp)
  260. {
  261. // Unregister our callbacks with the message system. Warning: this
  262. // would not work if there is more than one asset storage !
  263. gMessageSystemp->setHandlerFuncFast(_PREHASH_AssetUploadComplete, NULL,
  264. NULL);
  265. }
  266. // Clear the toxic asset map
  267. mToxicAssetMap.clear();
  268. }
  269. void LLAssetStorage::setUpstream(const LLHost &upstream_host)
  270. {
  271. LL_DEBUGS("AppInit") << "AssetStorage: Setting upstream provider to "
  272. << upstream_host << LL_ENDL;
  273. mUpstreamHost = upstream_host;
  274. }
  275. //virtual
  276. void LLAssetStorage::checkForTimeouts()
  277. {
  278. cleanupRequests(false, LL_ERR_TCP_TIMEOUT);
  279. }
  280. void LLAssetStorage::cleanupRequests(bool all, S32 error)
  281. {
  282. F64 mt_secs = LLMessageSystem::getMessageTimeSeconds();
  283. request_list_t timed_out;
  284. for (S32 rt = 0; rt < RT_COUNT; ++rt)
  285. {
  286. request_list_t* requests = getRequestList((ERequestType)rt);
  287. for (request_list_t::iterator iter = requests->begin(),
  288. end = requests->end();
  289. iter != end; )
  290. {
  291. request_list_t::iterator curiter = iter++;
  292. LLAssetRequest* tmp = *curiter;
  293. // If all is true, we want to clean up everything otherwise just
  294. // check for timed out requests EXCEPT for upload timeouts
  295. if (all ||
  296. (rt == RT_DOWNLOAD &&
  297. LL_ASSET_STORAGE_TIMEOUT < mt_secs - tmp->mTime))
  298. {
  299. llwarns << "Asset " << getRequestName((ERequestType)rt)
  300. << " request " << (all ? "aborted" : "timed out")
  301. << " for " << tmp->getUUID() << "."
  302. << LLAssetType::lookup(tmp->getType())
  303. << llendl;
  304. timed_out.push_front(tmp);
  305. requests->erase(curiter);
  306. }
  307. }
  308. }
  309. LLAssetInfo info;
  310. for (request_list_t::iterator iter = timed_out.begin(),
  311. end = timed_out.end();
  312. iter != end; ++iter)
  313. {
  314. LLAssetRequest* tmp = *iter;
  315. if (tmp->mUpCallback)
  316. {
  317. tmp->mUpCallback(tmp->getUUID(), tmp->mUserData, error,
  318. LLExtStat::NONE);
  319. }
  320. if (tmp->mDownCallback)
  321. {
  322. tmp->mDownCallback(tmp->getUUID(), tmp->getType(), tmp->mUserData,
  323. error, LLExtStat::NONE);
  324. }
  325. if (tmp->mInfoCallback)
  326. {
  327. tmp->mInfoCallback(&info, tmp->mUserData, error);
  328. }
  329. delete tmp;
  330. }
  331. }
  332. bool LLAssetStorage::hasLocalAsset(const LLUUID& uuid, LLAssetType::EType)
  333. {
  334. return LLFileSystem::getExists(uuid);
  335. }
  336. // UUID is passed by value to avoid side effects, please do not re-add &
  337. void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type,
  338. LLGetAssetCallback callback,
  339. void* user_data, bool is_priority)
  340. {
  341. LL_DEBUGS("AssetStorage") << "Called for asset: " << uuid << "."
  342. << LLAssetType::lookup(type) << LL_ENDL;
  343. if (user_data)
  344. {
  345. // The *user_data should not be passed without a callback to clean it
  346. // up.
  347. llassert(callback != NULL);
  348. }
  349. if (mShutDown)
  350. {
  351. LL_DEBUGS("AssetStorage") << "ASSET_TRACE cancelled (shutting down)"
  352. << LL_ENDL;
  353. if (callback)
  354. {
  355. callback(uuid, type, user_data, LL_ERR_ASSET_REQUEST_FAILED,
  356. LLExtStat::NONE);
  357. }
  358. return;
  359. }
  360. if (uuid.isNull())
  361. {
  362. // Special case early out for NULL uuid and for shutting down
  363. if (callback)
  364. {
  365. callback(uuid, type, user_data,
  366. LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE,
  367. LLExtStat::NULL_UUID);
  368. }
  369. return;
  370. }
  371. LLFileSystem file(uuid);
  372. if (file.getSize() > 0)
  373. {
  374. // We have already got the file. Theoretically, partial files without a
  375. // pending request should not happen unless there is a weird error.
  376. if (callback)
  377. {
  378. callback(uuid, type, user_data, LL_ERR_NOERR,
  379. LLExtStat::CACHE_CACHED);
  380. }
  381. return;
  382. }
  383. if (file.exists())
  384. {
  385. llwarns << "Asset cache file " << file.getName()
  386. << " found with zero size, removing." << llendl;
  387. file.remove();
  388. }
  389. // Check to see if there is a pending download of this uuid already
  390. bool duplicate = false;
  391. for (request_list_t::iterator iter = mPendingDownloads.begin(),
  392. end = mPendingDownloads.end();
  393. iter != end; ++iter)
  394. {
  395. LLAssetRequest* tmp = *iter;
  396. if (type == tmp->getType() && uuid == tmp->getUUID())
  397. {
  398. if (callback == tmp->mDownCallback && user_data == tmp->mUserData)
  399. {
  400. // This is a duplicate from the same subsystem - throw it away
  401. llwarns << "Discarding duplicate request for asset " << uuid
  402. << "." << LLAssetType::lookup(type) << llendl;
  403. return;
  404. }
  405. // This is a duplicate request queue the request, but do not
  406. // actually ask for it again
  407. duplicate = true;
  408. }
  409. }
  410. if (duplicate)
  411. {
  412. llinfos_once << "Adding additional non-duplicate request for asset "
  413. << uuid << "." << LLAssetType::lookup(type) << llendl;
  414. }
  415. queueDataRequest(uuid, type, callback, user_data, duplicate, is_priority);
  416. }
  417. // Finds and calls back ALL pending requests for passed UUID
  418. //static
  419. void LLAssetStorage::removeAndCallbackPendingDownloads(const LLUUID& file_id,
  420. LLAssetType::EType file_type,
  421. const LLUUID& callback_id,
  422. LLAssetType::EType callback_type,
  423. S32 result_code,
  424. LLExtStat ext_status)
  425. {
  426. request_list_t requests;
  427. for (request_list_t::iterator iter = gAssetStoragep->mPendingDownloads.begin();
  428. iter != gAssetStoragep->mPendingDownloads.end(); )
  429. {
  430. request_list_t::iterator curiter = iter++;
  431. LLAssetRequest* tmp = *curiter;
  432. if (tmp && tmp->getUUID() == file_id && tmp->getType() == file_type)
  433. {
  434. if (tmp->mDownCallback)
  435. {
  436. requests.push_front(tmp);
  437. }
  438. iter = gAssetStoragep->mPendingDownloads.erase(curiter);
  439. }
  440. }
  441. for (request_list_t::iterator iter = requests.begin(),
  442. end = requests.end();
  443. iter != end; ++iter)
  444. {
  445. LLAssetRequest* tmp = *iter;
  446. if (tmp->mDownCallback)
  447. {
  448. tmp->mDownCallback(callback_id, callback_type, tmp->mUserData,
  449. result_code, ext_status);
  450. }
  451. delete tmp;
  452. }
  453. }
  454. void LLAssetStorage::downloadCompleteCallback(S32 result,
  455. const LLUUID& file_id,
  456. LLAssetType::EType file_type,
  457. LLBaseDownloadRequest* user_data,
  458. LLExtStat ext_status)
  459. {
  460. LL_DEBUGS("AssetStorage") << "Download complete callback for " << file_id
  461. << "." << LLAssetType::lookup(file_type)
  462. << LL_ENDL;
  463. LLAssetRequest* req = (LLAssetRequest*)user_data;
  464. if (!req)
  465. {
  466. llwarns << "Call done without a valid request." << llendl;
  467. return;
  468. }
  469. if (!gAssetStoragep)
  470. {
  471. llwarns << "Call done without any asset system, aborting !" << llendl;
  472. return;
  473. }
  474. LLUUID callback_id;
  475. LLAssetType::EType callback_type;
  476. // Inefficient since we're doing a find through a list that may have
  477. // thousands of elements. This is due for refactoring; we will probably
  478. // change mPendingDownloads into a set.
  479. request_list_t::iterator pending_begin, pending_end, iter;
  480. pending_begin = gAssetStoragep->mPendingDownloads.begin();
  481. pending_end = gAssetStoragep->mPendingDownloads.end();
  482. iter = std::find(pending_begin, pending_end, req);
  483. if (iter != pending_end)
  484. {
  485. callback_id = file_id;
  486. callback_type = file_type;
  487. }
  488. else
  489. {
  490. // Either has already been deleted by cleanupRequests() or it is a
  491. // transfer.
  492. callback_id = req->getUUID();
  493. callback_type = req->getType();
  494. }
  495. if (result == LL_ERR_NOERR)
  496. {
  497. LLFileSystem vfile(callback_id);
  498. // We might have gotten a zero-size file
  499. if (vfile.getSize() <= 0)
  500. {
  501. llwarns << "Non-existent or zero-size asset " << callback_id
  502. << llendl;
  503. result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE;
  504. vfile.remove();
  505. }
  506. }
  507. removeAndCallbackPendingDownloads(file_id, file_type, callback_id,
  508. callback_type, result, ext_status);
  509. }
  510. void LLAssetStorage::getEstateAsset(const LLHost& object_sim,
  511. const LLUUID& agent_id,
  512. const LLUUID& session_id,
  513. const LLUUID& asset_id,
  514. LLAssetType::EType atype,
  515. EstateAssetType etype,
  516. LLGetAssetCallback callback,
  517. void* user_data,
  518. bool is_priority)
  519. {
  520. LL_DEBUGS("AssetStorage") << "Asset: " << asset_id << "."
  521. << LLAssetType::lookup(atype)
  522. << " - estate type: " << etype << LL_ENDL;
  523. //
  524. // Probably will get rid of this early out?
  525. //
  526. if (asset_id.isNull())
  527. {
  528. // Special case early out for NULL uuid
  529. if (callback)
  530. {
  531. callback(asset_id, atype, user_data,
  532. LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE,
  533. LLExtStat::NULL_UUID);
  534. }
  535. return;
  536. }
  537. LLFileSystem file(asset_id);
  538. if (file.getSize() > 0)
  539. {
  540. // We have already got the file. Theoretically, partial files without a
  541. // pending request should not happen unless there is a weird error.
  542. if (callback)
  543. {
  544. callback(asset_id, atype, user_data, LL_ERR_NOERR,
  545. LLExtStat::CACHE_CACHED);
  546. }
  547. return;
  548. }
  549. if (file.exists())
  550. {
  551. llwarns << "Asset cache file " << file.getName()
  552. << " found with zero size, removing." << llendl;
  553. file.remove();
  554. }
  555. // See whether we should talk to the object's originating sim, or the
  556. // upstream provider.
  557. LLHost source_host;
  558. if (object_sim.isOk())
  559. {
  560. source_host = object_sim;
  561. }
  562. else
  563. {
  564. source_host = mUpstreamHost;
  565. }
  566. if (source_host.isOk())
  567. {
  568. // Stash the callback info so we can find it after we get the response
  569. // message
  570. LLEstateAssetRequest req(asset_id, atype, etype);
  571. req.mDownCallback = callback;
  572. req.mUserData = user_data;
  573. req.mIsPriority = is_priority;
  574. // Send request message to our upstream data provider. Create a new
  575. // asset transfer.
  576. LLTransferSourceParamsEstate spe;
  577. spe.setAgentSession(agent_id, session_id);
  578. spe.setEstateAssetType(etype);
  579. // Set our destination file, and the completion callback.
  580. LLTransferTargetParamsVFile tpvf;
  581. tpvf.setAsset(asset_id, atype);
  582. tpvf.setCallback(downloadEstateAssetCompleteCallback, req);
  583. LL_DEBUGS("AssetStorage") << "Starting transfer for " << asset_id
  584. << LL_ENDL;
  585. LLTransferTargetChannel* ttcp =
  586. gTransferManager.getTargetChannel(source_host, LLTCT_ASSET);
  587. ttcp->requestTransfer(spe, tpvf, 100.f + (is_priority ? 1.f : 0.f));
  588. }
  589. else
  590. {
  591. // Uh-oh, we should not have gotten here
  592. llwarns << "Attempt to move asset data request upstream without valid upstream provider"
  593. << llendl;
  594. if (callback)
  595. {
  596. callback(asset_id, atype, user_data, LL_ERR_CIRCUIT_GONE,
  597. LLExtStat::NO_UPSTREAM);
  598. }
  599. }
  600. }
  601. void LLAssetStorage::downloadEstateAssetCompleteCallback(S32 result,
  602. const LLUUID& file_id,
  603. LLAssetType::EType file_type,
  604. LLBaseDownloadRequest* user_data,
  605. LLExtStat ext_status)
  606. {
  607. LLEstateAssetRequest* req = (LLEstateAssetRequest*)user_data;
  608. if (!req)
  609. {
  610. llwarns << "Call done without a valid request." << llendl;
  611. return;
  612. }
  613. if (!gAssetStoragep)
  614. {
  615. llwarns << "Call done without any asset system, aborting." << llendl;
  616. return;
  617. }
  618. req->setUUID(file_id);
  619. req->setType(file_type);
  620. if (LL_ERR_NOERR == result)
  621. {
  622. // We might have gotten a zero-size file
  623. LLFileSystem vfile(req->getUUID());
  624. if (vfile.getSize() <= 0)
  625. {
  626. llwarns << "Non-existent or zero-size asset found !" << llendl;
  627. result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE;
  628. vfile.remove();
  629. }
  630. }
  631. req->mDownCallback(req->getUUID(), req->getAType(), req->mUserData, result,
  632. ext_status);
  633. }
  634. void LLAssetStorage::getInvItemAsset(const LLHost& object_sim,
  635. const LLUUID& agent_id,
  636. const LLUUID& session_id,
  637. const LLUUID& owner_id,
  638. const LLUUID& task_id,
  639. const LLUUID& item_id,
  640. const LLUUID& asset_id,
  641. LLAssetType::EType atype,
  642. LLGetAssetCallback callback,
  643. void* user_data,
  644. bool is_priority)
  645. {
  646. LL_DEBUGS("AssetStorage") << "Asset: " << asset_id << "."
  647. << LLAssetType::lookup(atype) << LL_ENDL;
  648. #if 0
  649. // Probably will get rid of this early out?
  650. if (asset_id.isNull())
  651. {
  652. // Special case early out for NULL uuid
  653. if (callback)
  654. {
  655. callback(asset_id, atype, user_data,
  656. LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE);
  657. }
  658. return;
  659. }
  660. #endif
  661. bool exists = false;
  662. U32 size = 0;
  663. if (asset_id.notNull())
  664. {
  665. LLFileSystem file(asset_id);
  666. exists = file.exists();
  667. size = file.getSize();
  668. if (exists && !size)
  669. {
  670. llwarns << "Asset cache file " << file.getName()
  671. << " found with zero size, removing." << llendl;
  672. file.remove();
  673. }
  674. }
  675. if (size > 0)
  676. {
  677. // We have already got the file. Theoretically, partial files without a
  678. // pending request should not happen unless there is a weird error.
  679. if (callback)
  680. {
  681. callback(asset_id, atype, user_data, LL_ERR_NOERR,
  682. LLExtStat::CACHE_CACHED);
  683. }
  684. return;
  685. }
  686. // See whether we should talk to the object's originating sim, or the
  687. // upstream provider.
  688. LLHost source_host;
  689. if (object_sim.isOk())
  690. {
  691. source_host = object_sim;
  692. }
  693. else
  694. {
  695. source_host = mUpstreamHost;
  696. }
  697. if (source_host.isOk())
  698. {
  699. // Stash the callback info so we can find it after we get the response
  700. // message
  701. LLInvItemRequest req(asset_id, atype);
  702. req.mDownCallback = callback;
  703. req.mUserData = user_data;
  704. req.mIsPriority = is_priority;
  705. // Send request message to our upstream data provider. Create a new
  706. // asset transfer.
  707. LLTransferSourceParamsInvItem spi;
  708. spi.setAgentSession(agent_id, session_id);
  709. spi.setInvItem(owner_id, task_id, item_id);
  710. spi.setAsset(asset_id, atype);
  711. // Set our destination file, and the completion callback.
  712. LLTransferTargetParamsVFile tpvf;
  713. tpvf.setAsset(asset_id, atype);
  714. tpvf.setCallback(downloadInvItemCompleteCallback, req);
  715. LL_DEBUGS("AssetStorage") << "Starting transfer for inventory asset "
  716. << item_id << " - owned by: " << owner_id
  717. << " - task id:" << task_id << LL_ENDL;
  718. LLTransferTargetChannel* ttcp =
  719. gTransferManager.getTargetChannel(source_host, LLTCT_ASSET);
  720. ttcp->requestTransfer(spi, tpvf, 100.f + (is_priority ? 1.f : 0.f));
  721. }
  722. else
  723. {
  724. // Uh-oh, we should not have gotten here
  725. llwarns << "Attempt to move asset data request upstream without valid upstream provider"
  726. << llendl;
  727. if (callback)
  728. {
  729. callback(asset_id, atype, user_data, LL_ERR_CIRCUIT_GONE,
  730. LLExtStat::NO_UPSTREAM);
  731. }
  732. }
  733. }
  734. void LLAssetStorage::downloadInvItemCompleteCallback(S32 result,
  735. const LLUUID& file_id,
  736. LLAssetType::EType file_type,
  737. LLBaseDownloadRequest* user_data,
  738. LLExtStat ext_status)
  739. {
  740. LLInvItemRequest* req = (LLInvItemRequest*)user_data;
  741. if (!req)
  742. {
  743. llwarns << "Call done without a valid request." << llendl;
  744. return;
  745. }
  746. if (!gAssetStoragep)
  747. {
  748. llwarns << "Call done without any asset system, aborting." << llendl;
  749. return;
  750. }
  751. req->setUUID(file_id);
  752. req->setType(file_type);
  753. if (LL_ERR_NOERR == result)
  754. {
  755. // We might have gotten a zero-size file
  756. LLFileSystem vfile(req->getUUID());
  757. if (vfile.getSize() <= 0)
  758. {
  759. llwarns << "Non-existent or zero-size asset found !" << llendl;
  760. result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE;
  761. vfile.remove();
  762. }
  763. }
  764. req->mDownCallback(req->getUUID(), req->getType(), req->mUserData, result,
  765. ext_status);
  766. }
  767. ///////////////////////////////////////////////////////////////////////////////
  768. // Store routines
  769. ///////////////////////////////////////////////////////////////////////////////
  770. // StoreAssetData callback (fixed)
  771. //static
  772. void LLAssetStorage::uploadCompleteCallback(const LLUUID& uuid,
  773. void* user_data,
  774. S32 result,
  775. LLExtStat ext_status)
  776. {
  777. if (!gAssetStoragep)
  778. {
  779. llwarns << "No asset storage !" << llendl;
  780. return;
  781. }
  782. LLAssetRequest* req = (LLAssetRequest*)user_data;
  783. bool success = true;
  784. if (result)
  785. {
  786. llwarns << "Upload complete callback: " << result << " - "
  787. << getErrorString(result)
  788. << ". Trying to upload file to upstream provider" << llendl;
  789. success = false;
  790. }
  791. // We are done grabbing the file, tell the client
  792. gAssetStoragep->mMessageSys->newMessageFast(_PREHASH_AssetUploadComplete);
  793. gAssetStoragep->mMessageSys->nextBlockFast(_PREHASH_AssetBlock);
  794. gAssetStoragep->mMessageSys->addUUIDFast(_PREHASH_UUID, uuid);
  795. gAssetStoragep->mMessageSys->addS8Fast(_PREHASH_Type, req->getType());
  796. gAssetStoragep->mMessageSys->addBoolFast(_PREHASH_Success, success);
  797. gAssetStoragep->mMessageSys->sendReliable(req->mHost);
  798. delete req;
  799. }
  800. void LLAssetStorage::processUploadComplete(LLMessageSystem* msg,
  801. void** user_data)
  802. {
  803. LLAssetStorage* this_ptr = (LLAssetStorage*)user_data;
  804. LLUUID uuid;
  805. S8 asset_type_s8;
  806. LLAssetType::EType asset_type;
  807. bool success = false;
  808. msg->getUUIDFast(_PREHASH_AssetBlock, _PREHASH_UUID, uuid);
  809. msg->getS8Fast(_PREHASH_AssetBlock, _PREHASH_Type, asset_type_s8);
  810. msg->getBoolFast(_PREHASH_AssetBlock, _PREHASH_Success, success);
  811. asset_type = (LLAssetType::EType)asset_type_s8;
  812. this_ptr->callUploadCallbacks(uuid, asset_type, success, LLExtStat::NONE);
  813. }
  814. void LLAssetStorage::callUploadCallbacks(const LLUUID& uuid,
  815. LLAssetType::EType asset_type,
  816. bool success, LLExtStat ext_status)
  817. {
  818. // SJB: we process the callbacks in reverse order, I do not know if this is
  819. // important, but I did not want to mess with it.
  820. request_list_t requests;
  821. for (request_list_t::iterator iter = mPendingUploads.begin(),
  822. end = mPendingUploads.end();
  823. iter != end; )
  824. {
  825. request_list_t::iterator curiter = iter++;
  826. LLAssetRequest* req = *curiter;
  827. if (req->getUUID() == uuid && req->getType() == asset_type)
  828. {
  829. requests.push_front(req);
  830. mPendingUploads.erase(curiter);
  831. }
  832. }
  833. for (request_list_t::iterator iter = mPendingLocalUploads.begin(),
  834. end = mPendingLocalUploads.end();
  835. iter != end; )
  836. {
  837. request_list_t::iterator curiter = iter++;
  838. LLAssetRequest* req = *curiter;
  839. if (req->getUUID() == uuid && req->getType() == asset_type)
  840. {
  841. requests.push_front(req);
  842. mPendingLocalUploads.erase(curiter);
  843. }
  844. }
  845. for (request_list_t::iterator iter = requests.begin(),
  846. end = requests.end();
  847. iter != end; ++iter)
  848. {
  849. LLAssetRequest* req = *iter;
  850. if (req->mUpCallback)
  851. {
  852. req->mUpCallback(uuid, req->mUserData,
  853. success ? LL_ERR_NOERR
  854. : LL_ERR_ASSET_REQUEST_FAILED,
  855. ext_status);
  856. }
  857. delete req;
  858. }
  859. }
  860. LLAssetStorage::request_list_t* LLAssetStorage::getRequestList(LLAssetStorage::ERequestType rt)
  861. {
  862. switch (rt)
  863. {
  864. case RT_DOWNLOAD:
  865. return &mPendingDownloads;
  866. case RT_UPLOAD:
  867. return &mPendingUploads;
  868. case RT_LOCALUPLOAD:
  869. return &mPendingLocalUploads;
  870. default:
  871. llwarns << "Unable to find request list for request type: " << rt
  872. << llendl;
  873. return NULL;
  874. }
  875. }
  876. const LLAssetStorage::request_list_t* LLAssetStorage::getRequestList(LLAssetStorage::ERequestType rt) const
  877. {
  878. switch (rt)
  879. {
  880. case RT_DOWNLOAD:
  881. return &mPendingDownloads;
  882. case RT_UPLOAD:
  883. return &mPendingUploads;
  884. case RT_LOCALUPLOAD:
  885. return &mPendingLocalUploads;
  886. default:
  887. llwarns << "Unable to find request list for request type: " << rt
  888. << llendl;
  889. return NULL;
  890. }
  891. }
  892. //static
  893. std::string LLAssetStorage::getRequestName(LLAssetStorage::ERequestType rt)
  894. {
  895. switch (rt)
  896. {
  897. case RT_DOWNLOAD:
  898. return "download";
  899. case RT_UPLOAD:
  900. return "upload";
  901. case RT_LOCALUPLOAD:
  902. return "localupload";
  903. default:
  904. llwarns << "Unable to find request name for request type: " << rt
  905. << llendl;
  906. return "";
  907. }
  908. }
  909. S32 LLAssetStorage::getNumPending(LLAssetStorage::ERequestType rt) const
  910. {
  911. const request_list_t* requests = getRequestList(rt);
  912. return requests ? (S32)requests->size() : -1;
  913. }
  914. S32 LLAssetStorage::getNumPendingDownloads() const
  915. {
  916. return getNumPending(RT_DOWNLOAD);
  917. }
  918. S32 LLAssetStorage::getNumPendingUploads() const
  919. {
  920. return getNumPending(RT_UPLOAD);
  921. }
  922. S32 LLAssetStorage::getNumPendingLocalUploads()
  923. {
  924. return getNumPending(RT_LOCALUPLOAD);
  925. }
  926. LLSD LLAssetStorage::getPendingDetails(LLAssetStorage::ERequestType rt,
  927. LLAssetType::EType asset_type,
  928. const std::string& detail_prefix) const
  929. {
  930. const request_list_t* requests = getRequestList(rt);
  931. LLSD sd;
  932. sd["requests"] = getPendingDetailsImpl(requests, asset_type,
  933. detail_prefix);
  934. return sd;
  935. }
  936. LLSD LLAssetStorage::getPendingDetailsImpl(const LLAssetStorage::request_list_t* requests,
  937. LLAssetType::EType asset_type,
  938. const std::string& detail_prefix) const
  939. {
  940. LLSD details;
  941. if (requests)
  942. {
  943. for (request_list_t::const_iterator it = requests->begin(),
  944. end = requests->end();
  945. it != end; ++it)
  946. {
  947. LLAssetRequest* req = *it;
  948. if (asset_type == LLAssetType::AT_NONE ||
  949. asset_type == req->getType())
  950. {
  951. LLSD row = req->getTerseDetails();
  952. std::ostringstream detail;
  953. detail << detail_prefix << "/"
  954. << LLAssetType::lookup(req->getType()) << "/"
  955. << req->getUUID();
  956. row["detail"] = LLURI(detail.str());
  957. details.append(row);
  958. }
  959. }
  960. }
  961. return details;
  962. }
  963. //static
  964. const LLAssetRequest* LLAssetStorage::findRequest(const LLAssetStorage::request_list_t* requests,
  965. LLAssetType::EType asset_type,
  966. const LLUUID& asset_id)
  967. {
  968. if (requests)
  969. {
  970. // Search the requests list for the asset.
  971. for (request_list_t::const_iterator iter = requests->begin(),
  972. end = requests->end();
  973. iter != end; ++iter)
  974. {
  975. const LLAssetRequest* req = *iter;
  976. if (asset_type == req->getType() && asset_id == req->getUUID())
  977. {
  978. return req;
  979. }
  980. }
  981. }
  982. return NULL;
  983. }
  984. //static
  985. LLAssetRequest* LLAssetStorage::findRequest(LLAssetStorage::request_list_t* requests,
  986. LLAssetType::EType asset_type,
  987. const LLUUID& asset_id)
  988. {
  989. if (requests)
  990. {
  991. // Search the requests list for the asset.
  992. for (request_list_t::iterator iter = requests->begin(),
  993. end = requests->end();
  994. iter != end; ++iter)
  995. {
  996. LLAssetRequest* req = *iter;
  997. if (asset_type == req->getType() && asset_id == req->getUUID())
  998. {
  999. return req;
  1000. }
  1001. }
  1002. }
  1003. return NULL;
  1004. }
  1005. LLSD LLAssetStorage::getPendingRequest(LLAssetStorage::ERequestType rt,
  1006. LLAssetType::EType asset_type,
  1007. const LLUUID& asset_id) const
  1008. {
  1009. const request_list_t* requests = getRequestList(rt);
  1010. return getPendingRequestImpl(requests, asset_type, asset_id);
  1011. }
  1012. LLSD LLAssetStorage::getPendingRequestImpl(const LLAssetStorage::request_list_t* requests,
  1013. LLAssetType::EType asset_type,
  1014. const LLUUID& asset_id) const
  1015. {
  1016. LLSD sd;
  1017. const LLAssetRequest* req = findRequest(requests, asset_type, asset_id);
  1018. if (req)
  1019. {
  1020. sd = req->getFullDetails();
  1021. }
  1022. return sd;
  1023. }
  1024. bool LLAssetStorage::deletePendingRequest(LLAssetStorage::ERequestType rt,
  1025. LLAssetType::EType asset_type,
  1026. const LLUUID& asset_id)
  1027. {
  1028. request_list_t* requests = getRequestList(rt);
  1029. if (deletePendingRequestImpl(requests, asset_type, asset_id))
  1030. {
  1031. llinfos << "Asset " << getRequestName(rt) << " request for "
  1032. << asset_id << "." << LLAssetType::lookup(asset_type)
  1033. << " removed from pending queue." << llendl;
  1034. return true;
  1035. }
  1036. return false;
  1037. }
  1038. bool LLAssetStorage::deletePendingRequestImpl(LLAssetStorage::request_list_t* requests,
  1039. LLAssetType::EType asset_type,
  1040. const LLUUID& asset_id)
  1041. {
  1042. LLAssetRequest* req = findRequest(requests, asset_type, asset_id);
  1043. if (req)
  1044. {
  1045. // Remove the request from this list.
  1046. requests->remove(req);
  1047. S32 error = LL_ERR_TCP_TIMEOUT;
  1048. // Run callbacks.
  1049. if (req->mUpCallback)
  1050. {
  1051. req->mUpCallback(req->getUUID(), req->mUserData, error,
  1052. LLExtStat::REQUEST_DROPPED);
  1053. }
  1054. if (req->mDownCallback)
  1055. {
  1056. req->mDownCallback(req->getUUID(), req->getType(), req->mUserData,
  1057. error, LLExtStat::REQUEST_DROPPED);
  1058. }
  1059. if (req->mInfoCallback)
  1060. {
  1061. LLAssetInfo info;
  1062. req->mInfoCallback(&info, req->mUserData, error);
  1063. }
  1064. delete req;
  1065. return true;
  1066. }
  1067. return false;
  1068. }
  1069. //static
  1070. const char* LLAssetStorage::getErrorString(S32 status)
  1071. {
  1072. switch (status)
  1073. {
  1074. case LL_ERR_NOERR:
  1075. return "No error";
  1076. case LL_ERR_ASSET_REQUEST_FAILED:
  1077. return "Asset request: failed";
  1078. case LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE:
  1079. return "Asset request: non-existent file";
  1080. case LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE:
  1081. return "Asset request: asset not found in database";
  1082. case LL_ERR_EOF:
  1083. return "End of file";
  1084. case LL_ERR_CANNOT_OPEN_FILE:
  1085. return "Cannot open file";
  1086. case LL_ERR_FILE_NOT_FOUND:
  1087. return "File not found";
  1088. case LL_ERR_TCP_TIMEOUT:
  1089. return "File transfer timeout";
  1090. case LL_ERR_CIRCUIT_GONE:
  1091. return "Circuit gone";
  1092. case LL_ERR_PRICE_MISMATCH:
  1093. return "Viewer and server do not agree on price";
  1094. default:
  1095. return "Unknown status";
  1096. }
  1097. }
  1098. void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type,
  1099. void (*callback)(const char*, const LLUUID&,
  1100. void*, S32, LLExtStat),
  1101. void* user_data, bool is_priority)
  1102. {
  1103. // Check for duplicates here, since we're about to fool the normal
  1104. // duplicate checker
  1105. for (request_list_t::iterator iter = mPendingDownloads.begin(),
  1106. end = mPendingDownloads.end();
  1107. iter != end; ++iter)
  1108. {
  1109. LLAssetRequest* tmp = *iter;
  1110. if (type == tmp->getType() && uuid == tmp->getUUID() &&
  1111. legacyGetDataCallback == tmp->mDownCallback &&
  1112. callback == ((LLLegacyAssetRequest*)tmp->mUserData)->mDownCallback &&
  1113. user_data == ((LLLegacyAssetRequest*)tmp->mUserData)->mUserData)
  1114. {
  1115. // this is a duplicate from the same subsystem - throw it away
  1116. llinfos << "Discarding duplicate request for UUID " << uuid
  1117. << llendl;
  1118. return;
  1119. }
  1120. }
  1121. LLLegacyAssetRequest* legacy = new LLLegacyAssetRequest;
  1122. legacy->mDownCallback = callback;
  1123. legacy->mUserData = user_data;
  1124. getAssetData(uuid, type, legacyGetDataCallback, (void**)legacy,
  1125. is_priority);
  1126. }
  1127. //static
  1128. void LLAssetStorage::legacyGetDataCallback(const LLUUID& uuid,
  1129. LLAssetType::EType type,
  1130. void* user_data, S32 status,
  1131. LLExtStat ext_status)
  1132. {
  1133. if (!gAssetStoragep)
  1134. {
  1135. llwarns << "No asset storage !" << llendl;
  1136. return;
  1137. }
  1138. std::string filename;
  1139. // Check if the asset is marked toxic, and don't load bad stuff
  1140. bool toxic = gAssetStoragep->isAssetToxic(uuid);
  1141. if (!status && !toxic)
  1142. {
  1143. LLFileSystem file(uuid);
  1144. std::string uuid_str;
  1145. uuid.toString(uuid_str);
  1146. filename = llformat("%s.%s",
  1147. gDirUtil.getFullPath(LL_PATH_CACHE,
  1148. uuid_str).c_str(),
  1149. LLAssetType::lookup(type));
  1150. LLFILE* fp = LLFile::open(filename, "wb");
  1151. if (fp)
  1152. {
  1153. constexpr S32 BUF_SIZE = 65536;
  1154. U8 copy_buf[BUF_SIZE];
  1155. while (file.read(copy_buf, BUF_SIZE))
  1156. {
  1157. if (fwrite(copy_buf, file.getLastBytesRead(), 1, fp) < 1)
  1158. {
  1159. // Return a bad file error if we cannot write the whole
  1160. // thing
  1161. status = LL_ERR_CANNOT_OPEN_FILE;
  1162. }
  1163. }
  1164. LLFile::close(fp);
  1165. }
  1166. else
  1167. {
  1168. status = LL_ERR_CANNOT_OPEN_FILE;
  1169. }
  1170. }
  1171. LLLegacyAssetRequest* legacy = (LLLegacyAssetRequest*)user_data;
  1172. legacy->mDownCallback(filename.c_str(), uuid, legacy->mUserData, status,
  1173. ext_status);
  1174. delete legacy;
  1175. }
  1176. //static
  1177. void LLAssetStorage::legacyStoreDataCallback(const LLUUID& uuid,
  1178. void* user_data,
  1179. S32 status,
  1180. LLExtStat ext_status)
  1181. {
  1182. LLLegacyAssetRequest* legacy = (LLLegacyAssetRequest *)user_data;
  1183. if (legacy && legacy->mUpCallback)
  1184. {
  1185. legacy->mUpCallback(uuid, legacy->mUserData, status, ext_status);
  1186. }
  1187. delete legacy;
  1188. }
  1189. // Checks if an asset is in the toxic map. If it is, the entry is updated
  1190. bool LLAssetStorage::isAssetToxic(const LLUUID& uuid)
  1191. {
  1192. if (uuid.notNull())
  1193. {
  1194. toxic_asset_map_t::iterator iter = mToxicAssetMap.find(uuid);
  1195. if (iter != mToxicAssetMap.end())
  1196. {
  1197. // Found toxic asset
  1198. iter->second = LLFrameTimer::getTotalTime() + TOXIC_ASSET_LIFETIME;
  1199. return true;
  1200. }
  1201. }
  1202. return false;
  1203. }
  1204. // Cleans the toxic asset list, remove old entries
  1205. void LLAssetStorage::flushOldToxicAssets(bool force_it)
  1206. {
  1207. // Scan and look for old entries
  1208. U64 now = LLFrameTimer::getTotalTime();
  1209. toxic_asset_map_t::iterator iter = mToxicAssetMap.begin();
  1210. while (iter != mToxicAssetMap.end())
  1211. {
  1212. if (force_it || iter->second < now)
  1213. {
  1214. // Too old, remove it
  1215. mToxicAssetMap.hmap_erase(iter++);
  1216. }
  1217. else
  1218. {
  1219. ++iter;
  1220. }
  1221. }
  1222. }
  1223. // Adds an item to the toxic asset map
  1224. void LLAssetStorage::markAssetToxic(const LLUUID& id)
  1225. {
  1226. if (id.notNull())
  1227. {
  1228. // Set the value to the current time. Creates a new entry if needed.
  1229. U64 expires = LLFrameTimer::getTotalTime() + TOXIC_ASSET_LIFETIME;
  1230. mToxicAssetMap[id] = expires;
  1231. }
  1232. }