llcachename.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032
  1. /**
  2. * @file llcachename.cpp
  3. * @brief A hierarchical cache of first and last names queried based on UUID.
  4. *
  5. * $LicenseInfo:firstyear=2002&license=viewergpl$
  6. *
  7. * Copyright (c) 2002-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 <algorithm>
  34. #include "llcachename.h"
  35. #include "lldbstrings.h"
  36. #include "hbfastmap.h"
  37. #include "llframetimer.h"
  38. #include "llmessage.h"
  39. #include "llhost.h"
  40. #include "llrand.h"
  41. #include "llsdserialize.h"
  42. // LLSD serialization constants
  43. static const std::string AGENTS("agents");
  44. static const std::string GROUPS("groups");
  45. static const std::string CTIME("ctime");
  46. static const std::string FIRST("first");
  47. static const std::string LAST("last");
  48. static const std::string NAME("name");
  49. // We track name requests in flight for up to this long and hold on requesting
  50. // them again during this time.
  51. constexpr U32 PENDING_TIMEOUT_SECS = 300;
  52. // Globals
  53. LLCacheName* gCacheNamep = NULL;
  54. // ----------------------------------------------------------------------------
  55. // LLCacheNameEntry class
  56. // ----------------------------------------------------------------------------
  57. class LLCacheNameEntry
  58. {
  59. public:
  60. LLCacheNameEntry();
  61. public:
  62. bool mIsGroup;
  63. U32 mCreateTime; // unix time_t
  64. // *TODO: collapse names to one field, which will eliminate many string
  65. // compares on "Resident"
  66. std::string mFirstName;
  67. std::string mLastName;
  68. std::string mGroupName;
  69. };
  70. LLCacheNameEntry::LLCacheNameEntry()
  71. : mIsGroup(false),
  72. mCreateTime(0)
  73. {
  74. }
  75. class PendingReply
  76. {
  77. public:
  78. PendingReply(const LLUUID& id, const LLHost& host)
  79. : mID(id),
  80. mHost(host)
  81. {
  82. }
  83. boost::signals2::connection setCallback(const LLCacheNameCallback& cb)
  84. {
  85. return mSignal.connect(cb);
  86. }
  87. void done() { mID.setNull(); }
  88. bool isDone() const { return mID.isNull(); }
  89. public:
  90. LLUUID mID;
  91. LLCacheNameSignal mSignal;
  92. LLHost mHost;
  93. };
  94. class ReplySender
  95. {
  96. public:
  97. ReplySender(LLMessageSystem* msg);
  98. ~ReplySender();
  99. void send(const LLUUID& id, const LLCacheNameEntry& entry,
  100. const LLHost& host);
  101. private:
  102. void flush();
  103. private:
  104. LLMessageSystem* mMsg;
  105. bool mPending;
  106. bool mCurrIsGroup;
  107. LLHost mCurrHost;
  108. };
  109. ReplySender::ReplySender(LLMessageSystem* msg)
  110. : mMsg(msg),
  111. mPending(false),
  112. mCurrIsGroup(false)
  113. {
  114. }
  115. ReplySender::~ReplySender()
  116. {
  117. flush();
  118. }
  119. void ReplySender::send(const LLUUID& id, const LLCacheNameEntry& entry,
  120. const LLHost& host)
  121. {
  122. if (mPending && (mCurrIsGroup != entry.mIsGroup || mCurrHost != host))
  123. {
  124. flush();
  125. }
  126. if (!mPending)
  127. {
  128. mPending = true;
  129. mCurrIsGroup = entry.mIsGroup;
  130. mCurrHost = host;
  131. if (mCurrIsGroup)
  132. {
  133. mMsg->newMessageFast(_PREHASH_UUIDGroupNameReply);
  134. }
  135. else
  136. {
  137. mMsg->newMessageFast(_PREHASH_UUIDNameReply);
  138. }
  139. }
  140. mMsg->nextBlockFast(_PREHASH_UUIDNameBlock);
  141. mMsg->addUUIDFast(_PREHASH_ID, id);
  142. if (mCurrIsGroup)
  143. {
  144. mMsg->addStringFast(_PREHASH_GroupName, entry.mGroupName);
  145. }
  146. else
  147. {
  148. mMsg->addStringFast(_PREHASH_FirstName, entry.mFirstName);
  149. mMsg->addStringFast(_PREHASH_LastName, entry.mLastName);
  150. }
  151. if (mMsg->isSendFullFast(_PREHASH_UUIDNameBlock))
  152. {
  153. flush();
  154. }
  155. }
  156. void ReplySender::flush()
  157. {
  158. if (mPending)
  159. {
  160. mMsg->sendReliable(mCurrHost);
  161. mPending = false;
  162. }
  163. }
  164. // ----------------------------------------------------------------------------
  165. // LLCacheName::Impl class: hides gory details from main API
  166. // ----------------------------------------------------------------------------
  167. typedef std::list<PendingReply*> reply_map_t;
  168. typedef fast_hmap<LLUUID, U32> pending_map_t;
  169. typedef fast_hmap<LLUUID, LLCacheNameEntry*> cache_map_t;
  170. typedef std::map<std::string, LLUUID> revcache_map_t;
  171. class LLCacheName::Impl
  172. {
  173. protected:
  174. LOG_CLASS(LLCacheName::Impl);
  175. public:
  176. Impl(LLMessageSystem* msg);
  177. ~Impl();
  178. bool getName(const LLUUID& id, std::string& first, std::string& last);
  179. boost::signals2::connection addPending(const LLUUID& id,
  180. const LLCacheNameCallback& callback);
  181. void addPending(const LLUUID& id, const LLHost& host);
  182. void processPendingAsks();
  183. void processPendingReplies();
  184. void sendRequest(const char* msg_name, const uuid_list_t& queue);
  185. bool isRequestPending(const LLUUID& id);
  186. // Message system callbacks.
  187. void processUUIDRequest(LLMessageSystem* msg, bool is_group);
  188. void processUUIDReply(LLMessageSystem* msg, bool is_group);
  189. static void handleUUIDNameRequest(LLMessageSystem* msg, void** userdata);
  190. static void handleUUIDNameReply(LLMessageSystem* msg, void** userdata);
  191. static void handleUUIDGroupNameRequest(LLMessageSystem* msg,
  192. void** userdata);
  193. static void handleUUIDGroupNameReply(LLMessageSystem* msg,
  194. void** userdata);
  195. public:
  196. LLMessageSystem* mMsg;
  197. LLHost mUpstreamHost;
  198. cache_map_t mCache; // The map of UUIDs to names
  199. revcache_map_t mReverseCache; // Map of names to UUIDs
  200. uuid_list_t mAskNameQueue;
  201. uuid_list_t mAskGroupQueue; // UUIDs to ask our upstream host about
  202. // UUIDs that have been requested but are not in cache yet.
  203. pending_map_t mPendingQueue;
  204. reply_map_t mReplyQueue; // Requests awaiting replies from us
  205. LLCacheNameSignal mSignal;
  206. LLFrameTimer mProcessTimer;
  207. std::string mLoadingString;
  208. std::string mNobodyString;
  209. std::string mNoneString;
  210. };
  211. LLCacheName::Impl::Impl(LLMessageSystem* msg)
  212. : mMsg(msg),
  213. mLoadingString("(loading...)"),
  214. mNobodyString("(nobody)"),
  215. mNoneString("(none)")
  216. {
  217. mMsg->setHandlerFuncFast(_PREHASH_UUIDNameRequest,
  218. handleUUIDNameRequest, (void**)this);
  219. mMsg->setHandlerFuncFast(_PREHASH_UUIDNameReply,
  220. handleUUIDNameReply, (void**)this);
  221. mMsg->setHandlerFuncFast(_PREHASH_UUIDGroupNameRequest,
  222. handleUUIDGroupNameRequest, (void**)this);
  223. mMsg->setHandlerFuncFast(_PREHASH_UUIDGroupNameReply,
  224. handleUUIDGroupNameReply, (void**)this);
  225. }
  226. LLCacheName::Impl::~Impl()
  227. {
  228. for (auto it = mCache.begin(), end = mCache.end(); it != end; ++it)
  229. {
  230. delete it->second;
  231. }
  232. mCache.clear();
  233. std::for_each(mReplyQueue.begin(), mReplyQueue.end(), DeletePointer());
  234. mReplyQueue.clear();
  235. }
  236. boost::signals2::connection LLCacheName::Impl::addPending(const LLUUID& id,
  237. const LLCacheNameCallback& callback)
  238. {
  239. PendingReply* reply = new PendingReply(id, LLHost());
  240. boost::signals2::connection res = reply->setCallback(callback);
  241. mReplyQueue.push_back(reply);
  242. return res;
  243. }
  244. void LLCacheName::Impl::addPending(const LLUUID& id, const LLHost& host)
  245. {
  246. PendingReply* reply = new PendingReply(id, host);
  247. mReplyQueue.push_back(reply);
  248. }
  249. bool LLCacheName::Impl::getName(const LLUUID& id, std::string& first,
  250. std::string& last)
  251. {
  252. if (id.isNull())
  253. {
  254. first = mNobodyString;
  255. last.clear();
  256. return true;
  257. }
  258. LLCacheNameEntry* entryp = get_ptr_in_map(mCache, id);
  259. if (entryp)
  260. {
  261. first = entryp->mFirstName;
  262. last = entryp->mLastName;
  263. return true;
  264. }
  265. first = mLoadingString;
  266. last.clear();
  267. if (!isRequestPending(id))
  268. {
  269. mAskNameQueue.emplace(id);
  270. }
  271. return false;
  272. }
  273. void LLCacheName::Impl::processPendingAsks()
  274. {
  275. sendRequest(_PREHASH_UUIDNameRequest, mAskNameQueue);
  276. sendRequest(_PREHASH_UUIDGroupNameRequest, mAskGroupQueue);
  277. mAskNameQueue.clear();
  278. mAskGroupQueue.clear();
  279. }
  280. void LLCacheName::Impl::processPendingReplies()
  281. {
  282. reply_map_t::iterator reply_queue_begin = mReplyQueue.begin();
  283. reply_map_t::iterator reply_queue_end = mReplyQueue.end();
  284. reply_map_t::iterator it;
  285. // First call all the callbacks, because they might send messages.
  286. std::string fullname;
  287. for (it = reply_queue_begin; it != reply_queue_end; ++it)
  288. {
  289. PendingReply* replyp = *it;
  290. LLCacheNameEntry* entryp = get_ptr_in_map(mCache, replyp->mID);
  291. if (!entryp) continue;
  292. if (entryp->mIsGroup)
  293. {
  294. (replyp->mSignal)(replyp->mID, entryp->mGroupName, true);
  295. }
  296. else
  297. {
  298. fullname = LLCacheName::buildFullName(entryp->mFirstName,
  299. entryp->mLastName);
  300. (replyp->mSignal)(replyp->mID, fullname, false);
  301. }
  302. }
  303. // Forward on all replies, if needed.
  304. ReplySender sender(mMsg);
  305. for (it = reply_queue_begin; it != reply_queue_end; ++it)
  306. {
  307. PendingReply* replyp = *it;
  308. LLCacheNameEntry* entryp = get_ptr_in_map(mCache, replyp->mID);
  309. if (!entryp) continue;
  310. if (replyp->mHost.isOk())
  311. {
  312. sender.send(replyp->mID, *entryp, replyp->mHost);
  313. }
  314. replyp->done();
  315. }
  316. for (it = reply_queue_begin; it != reply_queue_end; )
  317. {
  318. reply_map_t::iterator curit = it++;
  319. PendingReply* replyp = *curit;
  320. if (replyp->isDone())
  321. {
  322. delete replyp;
  323. mReplyQueue.erase(curit);
  324. }
  325. }
  326. }
  327. void LLCacheName::Impl::sendRequest(const char* msg_name,
  328. const uuid_list_t& queue)
  329. {
  330. if (queue.empty())
  331. {
  332. return;
  333. }
  334. bool start_new_message = true;
  335. for (uuid_list_t::const_iterator it = queue.begin(), end = queue.end();
  336. it != end; ++it)
  337. {
  338. if (start_new_message)
  339. {
  340. start_new_message = false;
  341. mMsg->newMessageFast(msg_name);
  342. }
  343. mMsg->nextBlockFast(_PREHASH_UUIDNameBlock);
  344. mMsg->addUUIDFast(_PREHASH_ID, *it);
  345. if (mMsg->isSendFullFast(_PREHASH_UUIDNameBlock))
  346. {
  347. start_new_message = true;
  348. mMsg->sendReliable(mUpstreamHost);
  349. }
  350. }
  351. if (!start_new_message)
  352. {
  353. mMsg->sendReliable(mUpstreamHost);
  354. }
  355. }
  356. bool LLCacheName::Impl::isRequestPending(const LLUUID& id)
  357. {
  358. U32 now = (U32)time(NULL);
  359. U32 expire_time = now - PENDING_TIMEOUT_SECS;
  360. pending_map_t::iterator iter = mPendingQueue.find(id);
  361. if (iter == mPendingQueue.end() || iter->second < expire_time)
  362. {
  363. mPendingQueue[id] = now;
  364. return false;
  365. }
  366. return true;
  367. }
  368. void LLCacheName::Impl::processUUIDRequest(LLMessageSystem* msg, bool is_group)
  369. {
  370. // You should only get this message if the cache is at the simulator level,
  371. // hence having an upstream provider.
  372. if (!mUpstreamHost.isOk())
  373. {
  374. llwarns << "Got UUID name/group request, but no upstream provider !"
  375. << llendl;
  376. return;
  377. }
  378. LLHost from_host = msg->getSender();
  379. ReplySender sender(msg);
  380. S32 count = msg->getNumberOfBlocksFast(_PREHASH_UUIDNameBlock);
  381. for (S32 i = 0; i < count; ++i)
  382. {
  383. LLUUID id;
  384. msg->getUUIDFast(_PREHASH_UUIDNameBlock, _PREHASH_ID, id, i);
  385. LLCacheNameEntry* entryp = get_ptr_in_map(mCache, id);
  386. if (entryp)
  387. {
  388. if (is_group != entryp->mIsGroup)
  389. {
  390. llwarns << "Asked for " << (is_group ? "group" : "user")
  391. << " name, but found "
  392. << (entryp->mIsGroup ? "group" : "user") << ": " << id
  393. << llendl;
  394. }
  395. else // It is in the cache, so send it as the reply
  396. {
  397. sender.send(id, *entryp, from_host);
  398. }
  399. }
  400. else
  401. {
  402. if (!isRequestPending(id))
  403. {
  404. if (is_group)
  405. {
  406. mAskGroupQueue.emplace(id);
  407. }
  408. else
  409. {
  410. mAskNameQueue.emplace(id);
  411. }
  412. }
  413. addPending(id, from_host);
  414. }
  415. }
  416. }
  417. void LLCacheName::Impl::processUUIDReply(LLMessageSystem* msg, bool is_group)
  418. {
  419. S32 count = msg->getNumberOfBlocksFast(_PREHASH_UUIDNameBlock);
  420. for (S32 i = 0; i < count; ++i)
  421. {
  422. LLUUID id;
  423. msg->getUUIDFast(_PREHASH_UUIDNameBlock, _PREHASH_ID, id, i);
  424. LLCacheNameEntry* entryp = get_ptr_in_map(mCache, id);
  425. if (!entryp)
  426. {
  427. entryp = new LLCacheNameEntry;
  428. mCache[id] = entryp;
  429. }
  430. mPendingQueue.erase(id);
  431. entryp->mIsGroup = is_group;
  432. entryp->mCreateTime = (U32)time(NULL);
  433. if (is_group)
  434. {
  435. msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_GroupName,
  436. entryp->mGroupName, i);
  437. LLStringFn::replace_ascii_controlchars(entryp->mGroupName,
  438. LL_UNKNOWN_CHAR);
  439. }
  440. else
  441. {
  442. msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_FirstName,
  443. entryp->mFirstName, i);
  444. msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_LastName,
  445. entryp->mLastName, i);
  446. }
  447. if (!is_group)
  448. {
  449. // NOTE: Very occasionally the server sends down a full name in the
  450. // first name field with an empty last name, for example,
  451. // first = "Ladanie1 Resident", last = "". I cannot reproduce this,
  452. // nor can I find a bug in the server code. Ensure "Resident" does
  453. // not appear via cleanFullName, because buildFullName() only
  454. // checks last name. JC
  455. std::string full_name;
  456. if (entryp->mLastName.empty())
  457. {
  458. full_name = cleanFullName(entryp->mFirstName);
  459. // Fix what we are putting in the cache
  460. entryp->mFirstName = full_name;
  461. entryp->mLastName = "Resident";
  462. }
  463. else
  464. {
  465. full_name = LLCacheName::buildFullName(entryp->mFirstName,
  466. entryp->mLastName);
  467. }
  468. mSignal(id, full_name, false);
  469. // Do not keep "Resident" for reverse lookups
  470. full_name = cleanFullName(full_name);
  471. mReverseCache[full_name] = id;
  472. }
  473. else
  474. {
  475. mSignal(id, entryp->mGroupName, true);
  476. mReverseCache[entryp->mGroupName] = id;
  477. }
  478. }
  479. }
  480. //static
  481. void LLCacheName::Impl::handleUUIDNameReply(LLMessageSystem* msg,
  482. void** datap)
  483. {
  484. ((LLCacheName::Impl*)datap)->processUUIDReply(msg, false);
  485. }
  486. //static
  487. void LLCacheName::Impl::handleUUIDNameRequest(LLMessageSystem* msg,
  488. void** datap)
  489. {
  490. ((LLCacheName::Impl*)datap)->processUUIDRequest(msg, false);
  491. }
  492. //static
  493. void LLCacheName::Impl::handleUUIDGroupNameRequest(LLMessageSystem* msg,
  494. void** datap)
  495. {
  496. ((LLCacheName::Impl*)datap)->processUUIDRequest(msg, true);
  497. }
  498. //static
  499. void LLCacheName::Impl::handleUUIDGroupNameReply(LLMessageSystem* msg,
  500. void** datap)
  501. {
  502. ((LLCacheName::Impl*)datap)->processUUIDReply(msg, true);
  503. }
  504. // ----------------------------------------------------------------------------
  505. // LLCacheName class proper
  506. // ----------------------------------------------------------------------------
  507. LLCacheName::LLCacheName(LLMessageSystem* msgp, const std::string& loading,
  508. const std::string& nobody, const std::string& none)
  509. : impl(*new Impl(msgp))
  510. {
  511. if (!loading.empty())
  512. {
  513. impl.mLoadingString = loading;
  514. }
  515. if (!nobody.empty())
  516. {
  517. impl.mNobodyString = nobody;
  518. }
  519. if (!none.empty())
  520. {
  521. impl.mNoneString = none;
  522. }
  523. }
  524. LLCacheName::~LLCacheName()
  525. {
  526. delete &impl;
  527. }
  528. void LLCacheName::setUpstream(const LLHost& upstream_host)
  529. {
  530. impl.mUpstreamHost = upstream_host;
  531. }
  532. boost::signals2::connection LLCacheName::addObserver(const LLCacheNameCallback& cb)
  533. {
  534. return impl.mSignal.connect(cb);
  535. }
  536. bool LLCacheName::importFile(std::istream& istr)
  537. {
  538. LLSD data;
  539. if (LLSDSerialize::fromXMLDocument(data, istr) ==
  540. LLSDParser::PARSE_FAILURE)
  541. {
  542. return false;
  543. }
  544. // We will expire entries more than a week old
  545. U32 now = (U32)time(NULL);
  546. constexpr U32 SECS_PER_DAY = 60 * 60 * 24;
  547. U32 delete_before_time = now - (7 * SECS_PER_DAY);
  548. // Iterate over the agents
  549. S32 count = 0;
  550. LLSD agents = data[AGENTS];
  551. LLSD::map_iterator iter = agents.beginMap();
  552. LLSD::map_iterator end = agents.endMap();
  553. for ( ; iter != end; ++iter)
  554. {
  555. LLUUID id(iter->first);
  556. LLSD agent = iter->second;
  557. U32 ctime = (U32)agent[CTIME].asInteger();
  558. if (ctime < delete_before_time) continue;
  559. LLCacheNameEntry* entry = new LLCacheNameEntry();
  560. entry->mIsGroup = false;
  561. entry->mCreateTime = ctime;
  562. entry->mFirstName = agent[FIRST].asString();
  563. entry->mLastName = agent[LAST].asString();
  564. impl.mCache[id] = entry;
  565. std::string fullname = buildFullName(entry->mFirstName,
  566. entry->mLastName);
  567. // Do not keep "Resident" for reverse lookups:
  568. fullname = cleanFullName(fullname);
  569. impl.mReverseCache[fullname] = id;
  570. ++count;
  571. }
  572. llinfos << "Loaded " << count << " avatar names" << llendl;
  573. count = 0;
  574. LLSD groups = data[GROUPS];
  575. iter = groups.beginMap();
  576. end = groups.endMap();
  577. for ( ; iter != end; ++iter)
  578. {
  579. LLUUID id(iter->first);
  580. LLSD group = iter->second;
  581. U32 ctime = (U32)group[CTIME].asInteger();
  582. if (ctime < delete_before_time) continue;
  583. LLCacheNameEntry* entry = new LLCacheNameEntry();
  584. entry->mIsGroup = true;
  585. entry->mCreateTime = ctime;
  586. entry->mGroupName = group[NAME].asString();
  587. impl.mCache[id] = entry;
  588. impl.mReverseCache[entry->mGroupName] = id;
  589. ++count;
  590. }
  591. llinfos << "Loaded " << count << " group names." << llendl;
  592. return true;
  593. }
  594. void LLCacheName::exportFile(std::ostream& ostr)
  595. {
  596. LLSD data;
  597. for (cache_map_t::iterator iter = impl.mCache.begin(),
  598. end = impl.mCache.end();
  599. iter != end; ++iter)
  600. {
  601. // Only write entries for which we have valid data.
  602. LLCacheNameEntry* entry = iter->second;
  603. if (!entry || entry->mFirstName.find('?') != std::string::npos ||
  604. entry->mGroupName.find('?') != std::string::npos)
  605. {
  606. continue;
  607. }
  608. // Store it
  609. LLUUID id = iter->first;
  610. std::string id_str = id.asString();
  611. // IDEVO TODO: Should we store SLIDs with last name "Resident" or not?
  612. if (!entry->mFirstName.empty() && !entry->mLastName.empty())
  613. {
  614. data[AGENTS][id_str][FIRST] = entry->mFirstName;
  615. data[AGENTS][id_str][LAST] = entry->mLastName;
  616. data[AGENTS][id_str][CTIME] = (S32)entry->mCreateTime;
  617. }
  618. else if (entry->mIsGroup && !entry->mGroupName.empty())
  619. {
  620. data[GROUPS][id_str][NAME] = entry->mGroupName;
  621. data[GROUPS][id_str][CTIME] = (S32)entry->mCreateTime;
  622. }
  623. }
  624. LLSDSerialize::toPrettyXML(data, ostr);
  625. }
  626. bool LLCacheName::getName(const LLUUID& id, std::string& first,
  627. std::string& last)
  628. {
  629. return impl.getName(id, first, last);
  630. }
  631. bool LLCacheName::getFullName(const LLUUID& id, std::string& fullname)
  632. {
  633. std::string first_name, last_name;
  634. bool res = impl.getName(id, first_name, last_name);
  635. fullname = buildFullName(first_name, last_name);
  636. return res;
  637. }
  638. bool LLCacheName::getGroupName(const LLUUID& id, std::string& group)
  639. {
  640. if (id.isNull())
  641. {
  642. group = impl.mNoneString;
  643. return true;
  644. }
  645. LLCacheNameEntry* entryp = get_ptr_in_map(impl.mCache,id);
  646. if (entryp && entryp->mGroupName.empty())
  647. {
  648. // COUNTER-HACK to combat James' HACK in exportFile()... This group
  649. // name was loaded from a name cache that did not bother to save the
  650. // group name ==> we must ask for it.
  651. LL_DEBUGS("NameCache") << "Queuing HACK group request: " << id
  652. << LL_ENDL;
  653. entryp = NULL;
  654. }
  655. if (entryp)
  656. {
  657. group = entryp->mGroupName;
  658. return true;
  659. }
  660. group = impl.mLoadingString;
  661. if (!impl.isRequestPending(id))
  662. {
  663. impl.mAskGroupQueue.emplace(id);
  664. }
  665. return false;
  666. }
  667. bool LLCacheName::getUUID(const std::string& first, const std::string& last,
  668. LLUUID& id)
  669. {
  670. std::string full_name = buildFullName(first, last);
  671. return getUUID(full_name, id);
  672. }
  673. bool LLCacheName::getUUID(const std::string& full_name, LLUUID& id)
  674. {
  675. revcache_map_t::iterator iter =
  676. impl.mReverseCache.find(cleanFullName(full_name));
  677. if (iter == impl.mReverseCache.end())
  678. {
  679. return false;
  680. }
  681. id = iter->second;
  682. return true;
  683. }
  684. // This is a little bit kludgy. LLCacheNameCallback is a slot instead of a
  685. // function pointer. The reason it is a slot is so that the legacy get()
  686. // function below can bind an old callback and pass it as a slot. The reason it
  687. // is not a boost::function is so that trackable behavior does not get lost. As
  688. // a result, we have to bind the slot to a signal to call it, even when we call
  689. // it immediately. -Steve
  690. // NOTE: Even though passing first and last name is a bit of extra overhead, it
  691. // eliminates the potential need for any parsing should any code need to handle
  692. // first and last name independently.
  693. boost::signals2::connection LLCacheName::get(const LLUUID& id, bool is_group,
  694. const LLCacheNameCallback& callback)
  695. {
  696. boost::signals2::connection res;
  697. if (id.isNull())
  698. {
  699. LLCacheNameSignal signal;
  700. signal.connect(callback);
  701. signal(id, is_group ? impl.mNoneString : impl.mNobodyString, is_group);
  702. return res;
  703. }
  704. LLCacheNameEntry* entryp = get_ptr_in_map(impl.mCache, id);
  705. if (entryp)
  706. {
  707. LLCacheNameSignal signal;
  708. signal.connect(callback);
  709. // Id found in map therefore we can call the callback immediately.
  710. if (entryp->mIsGroup)
  711. {
  712. signal(id, entryp->mGroupName, entryp->mIsGroup);
  713. }
  714. else
  715. {
  716. std::string fullname = buildFullName(entryp->mFirstName,
  717. entryp->mLastName);
  718. signal(id, fullname, entryp->mIsGroup);
  719. }
  720. }
  721. else
  722. {
  723. // Id not found in map so we must queue the callback call until
  724. // available.
  725. if (!impl.isRequestPending(id))
  726. {
  727. if (is_group)
  728. {
  729. impl.mAskGroupQueue.emplace(id);
  730. }
  731. else
  732. {
  733. impl.mAskNameQueue.emplace(id);
  734. }
  735. }
  736. res = impl.addPending(id, callback);
  737. }
  738. return res;
  739. }
  740. void LLCacheName::processPending()
  741. {
  742. constexpr F32 SECS_BETWEEN_PROCESS = 0.1f;
  743. if (!impl.mProcessTimer.checkExpirationAndReset(SECS_BETWEEN_PROCESS))
  744. {
  745. return;
  746. }
  747. if (!impl.mUpstreamHost.isOk())
  748. {
  749. LL_DEBUGS("NameCache") << "Bad upstream host." << LL_ENDL;
  750. return;
  751. }
  752. impl.processPendingAsks();
  753. impl.processPendingReplies();
  754. }
  755. void LLCacheName::deleteEntriesOlderThan(S32 secs)
  756. {
  757. U32 now = (U32)time(NULL);
  758. U32 expire_time = now - secs;
  759. for (cache_map_t::iterator iter = impl.mCache.begin(),
  760. end = impl.mCache.end();
  761. iter != end; )
  762. {
  763. cache_map_t::iterator curiter = iter++;
  764. LLCacheNameEntry* entryp = curiter->second;
  765. if (entryp->mCreateTime < expire_time)
  766. {
  767. delete entryp;
  768. impl.mCache.erase(curiter);
  769. }
  770. }
  771. // These are pending requests that we never heard back from.
  772. U32 pending_expire_time = now - PENDING_TIMEOUT_SECS;
  773. for (pending_map_t::iterator it = impl.mPendingQueue.begin(),
  774. end = impl.mPendingQueue.end();
  775. it != end; )
  776. {
  777. pending_map_t::iterator curit = it++;
  778. if (curit->second < pending_expire_time)
  779. {
  780. impl.mPendingQueue.erase(curit);
  781. }
  782. }
  783. }
  784. void LLCacheName::dump()
  785. {
  786. for (cache_map_t::iterator iter = impl.mCache.begin(),
  787. end = impl.mCache.end();
  788. iter != end; iter++)
  789. {
  790. LLCacheNameEntry* entryp = iter->second;
  791. if (entryp->mIsGroup)
  792. {
  793. llinfos << iter->first << " = (group) " << entryp->mGroupName
  794. << " @ " << entryp->mCreateTime << llendl;
  795. }
  796. else
  797. {
  798. llinfos << iter->first << " = "
  799. << buildFullName(entryp->mFirstName, entryp->mLastName)
  800. << " @ " << entryp->mCreateTime << llendl;
  801. }
  802. }
  803. }
  804. void LLCacheName::dumpStats()
  805. {
  806. llinfos << "Queue sizes: "
  807. << " Cache=" << impl.mCache.size()
  808. << " AskName=" << impl.mAskNameQueue.size()
  809. << " AskGroup=" << impl.mAskGroupQueue.size()
  810. << " Pending=" << impl.mPendingQueue.size()
  811. << " Reply=" << impl.mReplyQueue.size()
  812. << llendl;
  813. }
  814. void LLCacheName::clear()
  815. {
  816. for (auto it = impl.mCache.begin(), end = impl.mCache.end();
  817. it != end; ++it)
  818. {
  819. delete it->second;
  820. }
  821. impl.mCache.clear();
  822. }
  823. const std::string& LLCacheName::getDefaultName() const
  824. {
  825. return impl.mLoadingString;
  826. }
  827. //static
  828. std::string LLCacheName::buildFullName(const std::string& first,
  829. const std::string& last)
  830. {
  831. std::string fullname = first;
  832. if (!last.empty() &&
  833. !(LLAvatarName::sOmitResidentAsLastName && last == "Resident"))
  834. {
  835. fullname += ' ';
  836. fullname += last;
  837. }
  838. return fullname;
  839. }
  840. //static
  841. std::string LLCacheName::cleanFullName(const std::string& full_name)
  842. {
  843. return full_name.substr(0, full_name.find(" Resident"));
  844. }
  845. //static
  846. std::string LLCacheName::buildUsername(const std::string& full_name)
  847. {
  848. // Rare, but handle hard-coded error names returned from server
  849. if (full_name == "(\?\?\?) (\?\?\?)")
  850. {
  851. return "(\?\?\?)";
  852. }
  853. std::string::size_type index = full_name.find(' ');
  854. if (index != std::string::npos)
  855. {
  856. std::string username;
  857. username = full_name.substr(0, index);
  858. std::string lastname = full_name.substr(index+1);
  859. if (lastname != "Resident")
  860. {
  861. username = username + "." + lastname;
  862. }
  863. LLStringUtil::toLower(username);
  864. return username;
  865. }
  866. // If the input was not a correctly formatted legacy name just return it
  867. // unchanged
  868. return full_name;
  869. }
  870. //static
  871. std::string LLCacheName::buildLegacyName(const std::string& complete_name)
  872. {
  873. // boost::regex was showing up in the crashreporter, so doing painfully
  874. // manual parsing using substr. LF
  875. // *TODO: convert to std::regex ?
  876. size_t open_paren = complete_name.rfind(" (");
  877. size_t close_paren = complete_name.rfind(')');
  878. if (open_paren != std::string::npos &&
  879. close_paren == complete_name.length() - 1)
  880. {
  881. size_t length = close_paren - open_paren - 2;
  882. std::string legacy_name = complete_name.substr(open_paren + 2, length);
  883. if (legacy_name.length() > 0)
  884. {
  885. std::string cap_letter = legacy_name.substr(0, 1);
  886. LLStringUtil::toUpper(cap_letter);
  887. legacy_name = cap_letter + legacy_name.substr(1);
  888. size_t separator = legacy_name.find('.');
  889. if (separator != std::string::npos)
  890. {
  891. std::string last_name = legacy_name.substr(separator + 1);
  892. legacy_name = legacy_name.substr(0, separator);
  893. if (last_name.length() > 0)
  894. {
  895. cap_letter = last_name.substr(0, 1);
  896. LLStringUtil::toUpper(cap_letter);
  897. legacy_name = legacy_name + " " + cap_letter +
  898. last_name.substr(1);
  899. }
  900. }
  901. return legacy_name;
  902. }
  903. }
  904. return complete_name;
  905. }