00001
00032 #include "linden_common.h"
00033
00034 #include "llcachename.h"
00035
00036
00037 #include "lldbstrings.h"
00038 #include "llframetimer.h"
00039 #include "llhost.h"
00040 #include "llrand.h"
00041 #include "llsdserialize.h"
00042 #include "lluuid.h"
00043 #include "message.h"
00044
00045
00046
00047 const char* const CN_WAITING = "(Loading...)";
00048 const char* const CN_NOBODY = "(nobody)";
00049 const char* const CN_NONE = "(none)";
00050
00051
00052 static const std::string AGENTS("agents");
00053 static const std::string GROUPS("groups");
00054 static const std::string CTIME("ctime");
00055 static const std::string FIRST("first");
00056 static const std::string LAST("last");
00057 static const std::string NAME("name");
00058
00059
00060
00061 const U32 PENDING_TIMEOUT_SECS = 5 * 60;
00062
00063
00064 const S32 CN_FILE_VERSION = 2;
00065
00066
00067 LLCacheName* gCacheName = NULL;
00068
00072
00073 class LLCacheNameEntry
00074 {
00075 public:
00076 LLCacheNameEntry();
00077
00078 public:
00079 bool mIsGroup;
00080 U32 mCreateTime;
00081 char mFirstName[DB_FIRST_NAME_BUF_SIZE];
00082 char mLastName[DB_LAST_NAME_BUF_SIZE];
00083 char mGroupName[DB_GROUP_NAME_BUF_SIZE];
00084 };
00085
00086 LLCacheNameEntry::LLCacheNameEntry()
00087 {
00088 mFirstName[0] = '\0';
00089 mLastName[0] = '\0';
00090 mGroupName[0] = '\0';
00091 }
00092
00093
00094 class PendingReply
00095 {
00096 public:
00097 LLUUID mID;
00098 LLCacheNameCallback mCallback;
00099 LLHost mHost;
00100 void* mData;
00101 PendingReply(const LLUUID& id, LLCacheNameCallback callback, void* data = NULL)
00102 : mID(id), mCallback(callback), mData(data)
00103 { }
00104
00105 PendingReply(const LLUUID& id, const LLHost& host)
00106 : mID(id), mCallback(0), mHost(host)
00107 { }
00108
00109 void done() { mID.setNull(); }
00110 bool isDone() const { return mID.isNull() != FALSE; }
00111 };
00112
00113 class ReplySender
00114 {
00115 public:
00116 ReplySender(LLMessageSystem* msg);
00117 ~ReplySender();
00118
00119 void send(const LLUUID& id,
00120 const LLCacheNameEntry& entry, const LLHost& host);
00121
00122 private:
00123 void flush();
00124
00125 LLMessageSystem* mMsg;
00126 bool mPending;
00127 bool mCurrIsGroup;
00128 LLHost mCurrHost;
00129 };
00130
00131 ReplySender::ReplySender(LLMessageSystem* msg)
00132 : mMsg(msg), mPending(false)
00133 { }
00134
00135 ReplySender::~ReplySender()
00136 {
00137 flush();
00138 }
00139
00140 void ReplySender::send(const LLUUID& id,
00141 const LLCacheNameEntry& entry, const LLHost& host)
00142 {
00143 if (mPending)
00144 {
00145 if (mCurrIsGroup != entry.mIsGroup
00146 || mCurrHost != host)
00147 {
00148 flush();
00149 }
00150 }
00151
00152 if (!mPending)
00153 {
00154 mPending = true;
00155 mCurrIsGroup = entry.mIsGroup;
00156 mCurrHost = host;
00157
00158 if(mCurrIsGroup)
00159 mMsg->newMessageFast(_PREHASH_UUIDGroupNameReply);
00160 else
00161 mMsg->newMessageFast(_PREHASH_UUIDNameReply);
00162 }
00163
00164 mMsg->nextBlockFast(_PREHASH_UUIDNameBlock);
00165 mMsg->addUUIDFast(_PREHASH_ID, id);
00166 if(mCurrIsGroup)
00167 {
00168 mMsg->addStringFast(_PREHASH_GroupName, entry.mGroupName);
00169 }
00170 else
00171 {
00172 mMsg->addStringFast(_PREHASH_FirstName, entry.mFirstName);
00173 mMsg->addStringFast(_PREHASH_LastName, entry.mLastName);
00174 }
00175
00176 if(mMsg->isSendFullFast(_PREHASH_UUIDNameBlock))
00177 {
00178 flush();
00179 }
00180 }
00181
00182 void ReplySender::flush()
00183 {
00184 if (mPending)
00185 {
00186 mMsg->sendReliable(mCurrHost);
00187 mPending = false;
00188 }
00189 }
00190
00191
00192 typedef std::set<LLUUID> AskQueue;
00193 typedef std::vector<PendingReply> ReplyQueue;
00194 typedef std::map<LLUUID,U32> PendingQueue;
00195 typedef std::map<LLUUID, LLCacheNameEntry*> Cache;
00196 typedef std::vector<LLCacheNameCallback> Observers;
00197
00198 class LLCacheName::Impl
00199 {
00200 public:
00201 LLMessageSystem* mMsg;
00202 LLHost mUpstreamHost;
00203
00204 Cache mCache;
00205
00206
00207 AskQueue mAskNameQueue;
00208 AskQueue mAskGroupQueue;
00209
00210
00211 PendingQueue mPendingQueue;
00212
00213
00214 ReplyQueue mReplyQueue;
00215
00216
00217 Observers mObservers;
00218
00219 LLFrameTimer mProcessTimer;
00220
00221 Impl(LLMessageSystem* msg);
00222 ~Impl();
00223
00224 void processPendingAsks();
00225 void processPendingReplies();
00226 void sendRequest(const char* msg_name, const AskQueue& queue);
00227 bool isRequestPending(const LLUUID& id);
00228
00229
00230 void processUUIDRequest(LLMessageSystem* msg, bool isGroup);
00231 void processUUIDReply(LLMessageSystem* msg, bool isGroup);
00232
00233 static void handleUUIDNameRequest(LLMessageSystem* msg, void** userdata);
00234 static void handleUUIDNameReply(LLMessageSystem* msg, void** userdata);
00235 static void handleUUIDGroupNameRequest(LLMessageSystem* msg, void** userdata);
00236 static void handleUUIDGroupNameReply(LLMessageSystem* msg, void** userdata);
00237
00238 void notifyObservers(const LLUUID& id, const char* first, const char* last, BOOL group);
00239 };
00240
00241
00245
00246 LLCacheName::LLCacheName(LLMessageSystem* msg)
00247 : impl(* new Impl(msg))
00248 { }
00249
00250 LLCacheName::LLCacheName(LLMessageSystem* msg, const LLHost& upstream_host)
00251 : impl(* new Impl(msg))
00252 {
00253 setUpstream(upstream_host);
00254 }
00255
00256 LLCacheName::~LLCacheName()
00257 {
00258 delete &impl;
00259 }
00260
00261 LLCacheName::Impl::Impl(LLMessageSystem* msg)
00262 : mMsg(msg), mUpstreamHost(LLHost::invalid)
00263 {
00264 mMsg->setHandlerFuncFast(
00265 _PREHASH_UUIDNameRequest, handleUUIDNameRequest, (void**)this);
00266 mMsg->setHandlerFuncFast(
00267 _PREHASH_UUIDNameReply, handleUUIDNameReply, (void**)this);
00268 mMsg->setHandlerFuncFast(
00269 _PREHASH_UUIDGroupNameRequest, handleUUIDGroupNameRequest, (void**)this);
00270 mMsg->setHandlerFuncFast(
00271 _PREHASH_UUIDGroupNameReply, handleUUIDGroupNameReply, (void**)this);
00272 }
00273
00274
00275 LLCacheName::Impl::~Impl()
00276 {
00277 for_each(mCache.begin(), mCache.end(), DeletePairedPointer());
00278 }
00279
00280
00281 void LLCacheName::setUpstream(const LLHost& upstream_host)
00282 {
00283 impl.mUpstreamHost = upstream_host;
00284 }
00285
00286 void LLCacheName::addObserver(LLCacheNameCallback callback)
00287 {
00288 impl.mObservers.push_back(callback);
00289 }
00290
00291 void LLCacheName::removeObserver(LLCacheNameCallback callback)
00292 {
00293 Observers::iterator it = impl.mObservers.begin();
00294 Observers::iterator end = impl.mObservers.end();
00295
00296 for ( ; it != end; ++it)
00297 {
00298 const LLCacheNameCallback& cb = (*it);
00299 if (cb == callback)
00300 {
00301 impl.mObservers.erase(it);
00302 return;
00303 }
00304 }
00305 }
00306
00307 void LLCacheName::cancelCallback(const LLUUID& id, LLCacheNameCallback callback, void* user_data)
00308 {
00309 ReplyQueue::iterator it = impl.mReplyQueue.begin();
00310 ReplyQueue::iterator end = impl.mReplyQueue.end();
00311
00312 for(; it != end; ++it)
00313 {
00314 const PendingReply& reply = (*it);
00315
00316 if ((callback == reply.mCallback)
00317 && (id == reply.mID)
00318 && (user_data == reply.mData) )
00319 {
00320 impl.mReplyQueue.erase(it);
00321 return;
00322 }
00323 }
00324 }
00325
00326 void LLCacheName::importFile(LLFILE* fp)
00327 {
00328 S32 count = 0;
00329
00330 const S32 BUFFER_SIZE = 1024;
00331 char buffer[BUFFER_SIZE];
00332
00333
00334 char id_string[MAX_STRING];
00335 char firstname[MAX_STRING];
00336 char lastname[MAX_STRING];
00337 U32 create_time;
00338
00339
00340 char* valid = fgets(buffer, BUFFER_SIZE, fp);
00341 if (!valid) return;
00342
00343
00344 char version_string[BUFFER_SIZE];
00345 S32 version = 0;
00346 S32 match = sscanf(
00347 buffer,
00348 "%1023s %d",
00349 version_string, &version);
00350 if ( match != 2
00351 || strcmp(version_string, "version")
00352 || version != CN_FILE_VERSION)
00353 {
00354 llwarns << "Ignoring old cache name file format" << llendl;
00355 return;
00356 }
00357
00358
00359 U32 now = (U32)time(NULL);
00360 const U32 SECS_PER_DAY = 60 * 60 * 24;
00361 U32 delete_before_time = now - (7 * SECS_PER_DAY);
00362
00363 while(!feof(fp))
00364 {
00365 valid = fgets(buffer, BUFFER_SIZE, fp);
00366 if (!valid) break;
00367
00368 match = sscanf(
00369 buffer,
00370 "%254s %u %254s %254s",
00371 id_string,
00372 &create_time,
00373 firstname,
00374 lastname);
00375 if (4 != match) continue;
00376
00377 LLUUID id(id_string);
00378 if (id.isNull()) continue;
00379
00380
00381 S32 i;
00382 for (i = 0; i < UUID_BYTES; i++)
00383 {
00384 id.mData[i] ^= 0x33;
00385 }
00386
00387
00388 if (create_time < delete_before_time) continue;
00389
00390 LLCacheNameEntry* entry = new LLCacheNameEntry();
00391 entry->mIsGroup = false;
00392 entry->mCreateTime = create_time;
00393 LLString::copy(entry->mFirstName, firstname, DB_FIRST_NAME_BUF_SIZE);
00394 LLString::copy(entry->mLastName, lastname, DB_LAST_NAME_BUF_SIZE);
00395 impl.mCache[id] = entry;
00396
00397 count++;
00398 }
00399
00400 llinfos << "LLCacheName loaded " << count << " names" << llendl;
00401 }
00402
00403 bool LLCacheName::importFile(std::istream& istr)
00404 {
00405 LLSD data;
00406 if(LLSDSerialize::fromXML(data, istr) < 1)
00407 return false;
00408
00409
00410 U32 now = (U32)time(NULL);
00411 const U32 SECS_PER_DAY = 60 * 60 * 24;
00412 U32 delete_before_time = now - (7 * SECS_PER_DAY);
00413
00414
00415 S32 count = 0;
00416 LLSD agents = data[AGENTS];
00417 LLSD::map_iterator iter = agents.beginMap();
00418 LLSD::map_iterator end = agents.endMap();
00419 for( ; iter != end; ++iter)
00420 {
00421 LLUUID id((*iter).first);
00422 LLSD agent = (*iter).second;
00423 U32 ctime = (U32)agent[CTIME].asInteger();
00424 if(ctime < delete_before_time) continue;
00425
00426 LLCacheNameEntry* entry = new LLCacheNameEntry();
00427 entry->mIsGroup = false;
00428 entry->mCreateTime = ctime;
00429 std::string first = agent[FIRST].asString();
00430 first.copy(entry->mFirstName, DB_FIRST_NAME_BUF_SIZE, 0);
00431 entry->mFirstName[llmin(first.size(),(std::string::size_type)DB_FIRST_NAME_BUF_SIZE-1)] = '\0';
00432 std::string last = agent[LAST].asString();
00433 last.copy(entry->mLastName, DB_LAST_NAME_BUF_SIZE, 0);
00434 entry->mLastName[llmin(last.size(),(std::string::size_type)DB_LAST_NAME_BUF_SIZE-1)] = '\0';
00435 impl.mCache[id] = entry;
00436 ++count;
00437 }
00438 llinfos << "LLCacheName loaded " << count << " agent names" << llendl;
00439
00440 count = 0;
00441 LLSD groups = data[GROUPS];
00442 iter = groups.beginMap();
00443 end = groups.endMap();
00444 for( ; iter != end; ++iter)
00445 {
00446 LLUUID id((*iter).first);
00447 LLSD group = (*iter).second;
00448 U32 ctime = (U32)group[CTIME].asInteger();
00449 if(ctime < delete_before_time) continue;
00450
00451 LLCacheNameEntry* entry = new LLCacheNameEntry();
00452 entry->mIsGroup = true;
00453 entry->mCreateTime = ctime;
00454 std::string name = group[NAME].asString();
00455 name.copy(entry->mGroupName, DB_GROUP_NAME_BUF_SIZE, 0);
00456 entry->mGroupName[llmin(name.size(), (std::string::size_type)DB_GROUP_NAME_BUF_SIZE-1)] = '\0';
00457 impl.mCache[id] = entry;
00458 ++count;
00459 }
00460 llinfos << "LLCacheName loaded " << count << " group names" << llendl;
00461 return true;
00462 }
00463
00464 void LLCacheName::exportFile(std::ostream& ostr)
00465 {
00466 LLSD data;
00467 Cache::iterator iter = impl.mCache.begin();
00468 Cache::iterator end = impl.mCache.end();
00469 for( ; iter != end; ++iter)
00470 {
00471
00472 LLCacheNameEntry* entry = iter->second;
00473 if(!entry
00474 || (NULL != strchr(entry->mFirstName, '?'))
00475 || (NULL != strchr(entry->mGroupName, '?')))
00476 {
00477 continue;
00478 }
00479
00480
00481 LLUUID id = iter->first;
00482 std::string id_str = id.asString();
00483 if(entry->mFirstName[0] && entry->mLastName[0])
00484 {
00485 data[AGENTS][id_str][FIRST] = entry->mFirstName;
00486 data[AGENTS][id_str][LAST] = entry->mLastName;
00487 data[AGENTS][id_str][CTIME] = (S32)entry->mCreateTime;
00488 }
00489 else if(entry->mIsGroup && entry->mGroupName[0])
00490 {
00491 data[GROUPS][id_str][NAME] = entry->mGroupName;
00492 data[GROUPS][id_str][CTIME] = (S32)entry->mCreateTime;
00493 }
00494 }
00495
00496 LLSDSerialize::toPrettyXML(data, ostr);
00497 }
00498
00499
00500 BOOL LLCacheName::getName(const LLUUID& id, std::string& first, std::string& last)
00501 {
00502 if(id.isNull())
00503 {
00504 first = CN_NOBODY;
00505 last.clear();
00506 return FALSE;
00507 }
00508
00509 LLCacheNameEntry* entry = get_ptr_in_map(impl.mCache, id );
00510 if (entry)
00511 {
00512 first = entry->mFirstName;
00513 last = entry->mLastName;
00514 return TRUE;
00515 }
00516 else
00517 {
00518 first = CN_WAITING;
00519 last.clear();
00520 if (!impl.isRequestPending(id))
00521 {
00522 impl.mAskNameQueue.insert(id);
00523 }
00524 return FALSE;
00525 }
00526
00527 }
00528
00529 BOOL LLCacheName::getFullName(const LLUUID& id, std::string& fullname)
00530 {
00531 std::string first_name, last_name;
00532 BOOL res = getName(id, first_name, last_name);
00533 fullname = first_name + " " + last_name;
00534 return res;
00535 }
00536
00537
00538 BOOL LLCacheName::getName(const LLUUID& id, char* first, char* last)
00539 {
00540 std::string first_name, last_name;
00541 BOOL res = getName(id, first_name, last_name);
00542 strcpy(first, first_name.c_str());
00543 strcpy(last, last_name.c_str());
00544 return res;
00545 }
00546
00547 BOOL LLCacheName::getGroupName(const LLUUID& id, std::string& group)
00548 {
00549 if(id.isNull())
00550 {
00551 group = CN_NONE;
00552 return FALSE;
00553 }
00554
00555 LLCacheNameEntry* entry = get_ptr_in_map(impl.mCache,id);
00556 if (entry && !entry->mGroupName[0])
00557 {
00558
00559
00560
00561 lldebugs << "LLCacheName queuing HACK group request: " << id << llendl;
00562 entry = NULL;
00563 }
00564
00565 if (entry)
00566 {
00567 group = entry->mGroupName;
00568 return TRUE;
00569 }
00570 else
00571 {
00572 group = CN_WAITING;
00573 if (!impl.isRequestPending(id))
00574 {
00575 impl.mAskGroupQueue.insert(id);
00576 }
00577 return FALSE;
00578 }
00579 }
00580
00581
00582 BOOL LLCacheName::getGroupName(const LLUUID& id, char* group)
00583 {
00584 std::string group_name;
00585 BOOL res = getGroupName(id, group_name);
00586 strcpy(group, group_name.c_str());
00587 return res;
00588 }
00589
00590
00591
00592
00593 void LLCacheName::get(const LLUUID& id, BOOL is_group, LLCacheNameCallback callback, void* user_data)
00594 {
00595 if(id.isNull())
00596 {
00597 callback(id, CN_NOBODY, "", is_group, user_data);
00598 }
00599
00600 LLCacheNameEntry* entry = get_ptr_in_map(impl.mCache, id );
00601 if (entry)
00602 {
00603
00604 if (entry->mIsGroup)
00605 {
00606 callback(id, entry->mGroupName, "", entry->mIsGroup, user_data);
00607 }
00608 else
00609 {
00610 callback(id, entry->mFirstName, entry->mLastName, entry->mIsGroup, user_data);
00611 }
00612 }
00613 else
00614 {
00615
00616 if (!impl.isRequestPending(id))
00617 {
00618 if (is_group)
00619 {
00620 impl.mAskGroupQueue.insert(id);
00621 }
00622 else
00623 {
00624 impl.mAskNameQueue.insert(id);
00625 }
00626 }
00627 impl.mReplyQueue.push_back(PendingReply(id, callback, user_data));
00628 }
00629 }
00630
00631 void LLCacheName::processPending()
00632 {
00633 const F32 SECS_BETWEEN_PROCESS = 0.1f;
00634 if(!impl.mProcessTimer.checkExpirationAndReset(SECS_BETWEEN_PROCESS))
00635 {
00636 return;
00637 }
00638
00639 if(!impl.mUpstreamHost.isOk())
00640 {
00641 lldebugs << "LLCacheName::processPending() - bad upstream host."
00642 << llendl;
00643 return;
00644 }
00645
00646 impl.processPendingAsks();
00647 impl.processPendingReplies();
00648 }
00649
00650 void LLCacheName::deleteEntriesOlderThan(S32 secs)
00651 {
00652 U32 now = (U32)time(NULL);
00653 U32 expire_time = now - secs;
00654 for(Cache::iterator iter = impl.mCache.begin(); iter != impl.mCache.end(); )
00655 {
00656 Cache::iterator curiter = iter++;
00657 LLCacheNameEntry* entry = curiter->second;
00658 if (entry->mCreateTime < expire_time)
00659 {
00660 delete entry;
00661 impl.mCache.erase(curiter);
00662 }
00663 }
00664
00665
00666 U32 pending_expire_time = now - PENDING_TIMEOUT_SECS;
00667 for(PendingQueue::iterator p_iter = impl.mPendingQueue.begin();
00668 p_iter != impl.mPendingQueue.end(); )
00669 {
00670 PendingQueue::iterator p_curitor = p_iter++;
00671
00672 if (p_curitor->second < pending_expire_time)
00673 {
00674 impl.mPendingQueue.erase(p_curitor);
00675 }
00676 }
00677 }
00678
00679
00680 void LLCacheName::dump()
00681 {
00682 for (Cache::iterator iter = impl.mCache.begin(),
00683 end = impl.mCache.end();
00684 iter != end; iter++)
00685 {
00686 LLCacheNameEntry* entry = iter->second;
00687 if (entry->mIsGroup)
00688 {
00689 llinfos
00690 << iter->first << " = (group) "
00691 << entry->mGroupName
00692 << " @ " << entry->mCreateTime
00693 << llendl;
00694 }
00695 else
00696 {
00697 llinfos
00698 << iter->first << " = "
00699 << entry->mFirstName << " " << entry->mLastName
00700 << " @ " << entry->mCreateTime
00701 << llendl;
00702 }
00703 }
00704 }
00705
00706 void LLCacheName::dumpStats()
00707 {
00708 llinfos << "Queue sizes: "
00709 << " Cache=" << impl.mCache.size()
00710 << " AskName=" << impl.mAskNameQueue.size()
00711 << " AskGroup=" << impl.mAskGroupQueue.size()
00712 << " Pending=" << impl.mPendingQueue.size()
00713 << " Reply=" << impl.mReplyQueue.size()
00714 << " Observers=" << impl.mObservers.size()
00715 << llendl;
00716 }
00717
00718
00719 LLString LLCacheName::getDefaultName()
00720 {
00721 return LLString(CN_WAITING);
00722 }
00723
00724 void LLCacheName::Impl::processPendingAsks()
00725 {
00726 sendRequest(_PREHASH_UUIDNameRequest, mAskNameQueue);
00727 sendRequest(_PREHASH_UUIDGroupNameRequest, mAskGroupQueue);
00728 mAskNameQueue.clear();
00729 mAskGroupQueue.clear();
00730 }
00731
00732 void LLCacheName::Impl::processPendingReplies()
00733 {
00734 ReplyQueue::iterator it = mReplyQueue.begin();
00735 ReplyQueue::iterator end = mReplyQueue.end();
00736
00737
00738 for(; it != end; ++it)
00739 {
00740 LLCacheNameEntry* entry = get_ptr_in_map(mCache, it->mID);
00741 if(!entry) continue;
00742
00743 if (it->mCallback)
00744 {
00745 if (!entry->mIsGroup)
00746 {
00747 (it->mCallback)(it->mID,
00748 entry->mFirstName, entry->mLastName,
00749 FALSE, it->mData);
00750 }
00751 else {
00752 (it->mCallback)(it->mID,
00753 entry->mGroupName, "",
00754 TRUE, it->mData);
00755 }
00756 }
00757 }
00758
00759
00760 ReplySender sender(mMsg);
00761 for (it = mReplyQueue.begin(); it != end; ++it)
00762 {
00763 LLCacheNameEntry* entry = get_ptr_in_map(mCache, it->mID);
00764 if(!entry) continue;
00765
00766 if (it->mHost.isOk())
00767 {
00768 sender.send(it->mID, *entry, it->mHost);
00769 }
00770
00771 it->done();
00772 }
00773
00774 mReplyQueue.erase(
00775 remove_if(mReplyQueue.begin(), mReplyQueue.end(),
00776 std::mem_fun_ref(&PendingReply::isDone)),
00777 mReplyQueue.end());
00778 }
00779
00780
00781 void LLCacheName::Impl::sendRequest(
00782 const char* msg_name,
00783 const AskQueue& queue)
00784 {
00785 if(queue.empty())
00786 {
00787 return;
00788 }
00789
00790 bool start_new_message = true;
00791 AskQueue::const_iterator it = queue.begin();
00792 AskQueue::const_iterator end = queue.end();
00793 for(; it != end; ++it)
00794 {
00795 if(start_new_message)
00796 {
00797 start_new_message = false;
00798 mMsg->newMessageFast(msg_name);
00799 }
00800 mMsg->nextBlockFast(_PREHASH_UUIDNameBlock);
00801 mMsg->addUUIDFast(_PREHASH_ID, (*it));
00802
00803 if(mMsg->isSendFullFast(_PREHASH_UUIDNameBlock))
00804 {
00805 start_new_message = true;
00806 mMsg->sendReliable(mUpstreamHost);
00807 }
00808 }
00809 if(!start_new_message)
00810 {
00811 mMsg->sendReliable(mUpstreamHost);
00812 }
00813 }
00814
00815 void LLCacheName::Impl::notifyObservers(const LLUUID& id,
00816 const char* first, const char* last, BOOL is_group)
00817 {
00818 for (Observers::const_iterator i = mObservers.begin(),
00819 end = mObservers.end();
00820 i != end;
00821 ++i)
00822 {
00823 (**i)(id, first, last, is_group, NULL);
00824 }
00825 }
00826
00827 bool LLCacheName::Impl::isRequestPending(const LLUUID& id)
00828 {
00829 U32 now = (U32)time(NULL);
00830 U32 expire_time = now - PENDING_TIMEOUT_SECS;
00831
00832 PendingQueue::iterator iter = mPendingQueue.find(id);
00833
00834 if (iter == mPendingQueue.end()
00835 || (iter->second < expire_time) )
00836 {
00837 mPendingQueue[id] = now;
00838 return false;
00839 }
00840
00841 return true;
00842 }
00843
00844 void LLCacheName::Impl::processUUIDRequest(LLMessageSystem* msg, bool isGroup)
00845 {
00846
00847
00848 if (!mUpstreamHost.isOk())
00849 {
00850 llwarns << "LLCacheName - got UUID name/group request, but no upstream provider!" << llendl;
00851 return;
00852 }
00853
00854 LLHost fromHost = msg->getSender();
00855 ReplySender sender(msg);
00856
00857 S32 count = msg->getNumberOfBlocksFast(_PREHASH_UUIDNameBlock);
00858 for(S32 i = 0; i < count; ++i)
00859 {
00860 LLUUID id;
00861 msg->getUUIDFast(_PREHASH_UUIDNameBlock, _PREHASH_ID, id, i);
00862 LLCacheNameEntry* entry = get_ptr_in_map(mCache, id);
00863 if(entry)
00864 {
00865 if (isGroup != entry->mIsGroup)
00866 {
00867 llwarns << "LLCacheName - Asked for "
00868 << (isGroup ? "group" : "user") << " name, "
00869 << "but found "
00870 << (entry->mIsGroup ? "group" : "user")
00871 << ": " << id << llendl;
00872 }
00873 else
00874 {
00875
00876 sender.send(id, *entry, fromHost);
00877 }
00878 }
00879 else
00880 {
00881 if (!isRequestPending(id))
00882 {
00883 if (isGroup)
00884 {
00885 mAskGroupQueue.insert(id);
00886 }
00887 else
00888 {
00889 mAskNameQueue.insert(id);
00890 }
00891 }
00892
00893 mReplyQueue.push_back(PendingReply(id, fromHost));
00894 }
00895 }
00896 }
00897
00898
00899
00900 void LLCacheName::Impl::processUUIDReply(LLMessageSystem* msg, bool isGroup)
00901 {
00902 S32 count = msg->getNumberOfBlocksFast(_PREHASH_UUIDNameBlock);
00903 for(S32 i = 0; i < count; ++i)
00904 {
00905 LLUUID id;
00906 msg->getUUIDFast(_PREHASH_UUIDNameBlock, _PREHASH_ID, id, i);
00907 LLCacheNameEntry* entry = get_ptr_in_map(mCache, id);
00908 if (!entry)
00909 {
00910 entry = new LLCacheNameEntry;
00911 mCache[id] = entry;
00912 }
00913
00914 mPendingQueue.erase(id);
00915
00916 entry->mIsGroup = isGroup;
00917 entry->mCreateTime = (U32)time(NULL);
00918 if (!isGroup)
00919 {
00920 msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_FirstName, DB_FIRST_NAME_BUF_SIZE, entry->mFirstName, i);
00921 msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_LastName, DB_LAST_NAME_BUF_SIZE, entry->mLastName, i);
00922 }
00923 else
00924 {
00925 msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_GroupName, DB_GROUP_NAME_BUF_SIZE, entry->mGroupName, i);
00926 }
00927
00928 if (!isGroup)
00929 {
00930 notifyObservers(id,
00931 entry->mFirstName, entry->mLastName,
00932 FALSE);
00933 }
00934 else
00935 {
00936 notifyObservers(id, entry->mGroupName, "", TRUE);
00937 }
00938 }
00939 }
00940
00941
00942
00943
00944
00945 void LLCacheName::Impl::handleUUIDNameReply(LLMessageSystem* msg, void** userData)
00946 {
00947 ((LLCacheName::Impl*)userData)->processUUIDReply(msg, false);
00948 }
00949
00950 void LLCacheName::Impl::handleUUIDNameRequest(LLMessageSystem* msg, void** userData)
00951 {
00952 ((LLCacheName::Impl*)userData)->processUUIDRequest(msg, false);
00953 }
00954
00955 void LLCacheName::Impl::handleUUIDGroupNameRequest(LLMessageSystem* msg, void** userData)
00956 {
00957 ((LLCacheName::Impl*)userData)->processUUIDRequest(msg, true);
00958 }
00959
00960 void LLCacheName::Impl::handleUUIDGroupNameReply(LLMessageSystem* msg, void** userData)
00961 {
00962 ((LLCacheName::Impl*)userData)->processUUIDReply(msg, true);
00963 }
00964