llcachename.cpp

Go to the documentation of this file.
00001 
00032 #include "linden_common.h"
00033 
00034 #include "llcachename.h"
00035 
00036 // linden library includes
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 // Constants
00046 // probably need a setUIString() call in the interface
00047 const char* const CN_WAITING = "(Loading...)"; // *TODO: translate
00048 const char* const CN_NOBODY = "(nobody)"; // *TODO: translate
00049 const char* const CN_NONE = "(none)"; // *TODO: translate
00050 
00051 // llsd serialization constants
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 // We track name requests in flight for up to this long.
00060 // We won't re-request a name during this time
00061 const U32 PENDING_TIMEOUT_SECS = 5 * 60;
00062 
00063 // File version number
00064 const S32 CN_FILE_VERSION = 2;
00065 
00066 // Globals
00067 LLCacheName* gCacheName = NULL;
00068 
00072 
00073 class LLCacheNameEntry
00074 {
00075 public:
00076         LLCacheNameEntry();
00077 
00078 public:
00079         bool mIsGroup;
00080         U32 mCreateTime;        // unix time_t
00081         char mFirstName[DB_FIRST_NAME_BUF_SIZE]; /*Flawfinder: ignore*/
00082         char mLastName[DB_LAST_NAME_BUF_SIZE]; /*Flawfinder: ignore*/
00083         char mGroupName[DB_GROUP_NAME_BUF_SIZE]; /*Flawfinder: ignore*/
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                 // the map of UUIDs to names
00206 
00207         AskQueue                        mAskNameQueue;
00208         AskQueue                        mAskGroupQueue;
00209                 // UUIDs to ask our upstream host about
00210         
00211         PendingQueue            mPendingQueue;
00212                 // UUIDs that have been requested but are not in cache yet.
00213 
00214         ReplyQueue                      mReplyQueue;
00215                 // requests awaiting replies from us
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         // Message system callbacks.
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];       /*Flawfinder: ignore*/
00332 
00333         // *NOTE: These buffer sizes are hardcoded into sscanf() below
00334         char id_string[MAX_STRING]; /*Flawfinder: ignore*/
00335         char firstname[MAX_STRING]; /*Flawfinder: ignore*/
00336         char lastname[MAX_STRING]; /*Flawfinder: ignore*/
00337         U32 create_time;
00338 
00339         // This is OK if the first line is actually a name.  We just don't load it.
00340         char* valid = fgets(buffer, BUFFER_SIZE, fp);
00341         if (!valid) return;
00342 
00343         // *NOTE: This buffer size is hardcoded into sscanf() below
00344         char version_string[BUFFER_SIZE]; /*Flawfinder: ignore*/
00345         S32 version = 0;
00346         S32 match = sscanf(     /* Flawfinder: ignore */
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         // We'll expire entries more than a week old
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( /* Flawfinder: ignore */
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                 // undo trivial XOR
00381                 S32 i;
00382                 for (i = 0; i < UUID_BYTES; i++)
00383                 {
00384                         id.mData[i] ^= 0x33;
00385                 }
00386 
00387                 // Don't load entries that are more than a week old
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         // We'll expire entries more than a week old
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         // iterate over the agents
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                 // Only write entries for which we have valid data.
00472                 LLCacheNameEntry* entry = iter->second;
00473                 if(!entry
00474                    || (NULL != strchr(entry->mFirstName, '?'))
00475                    || (NULL != strchr(entry->mGroupName, '?')))
00476                 {
00477                         continue;
00478                 }
00479 
00480                 // store it
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 // *TODO: Deprecate
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                 // COUNTER-HACK to combat James' HACK in exportFile()...
00559                 // this group name was loaded from a name cache that did not
00560                 // bother to save the group name ==> we must ask for it
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 // *TODO: Deprecate
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 // TODO: Make the cache name callback take a SINGLE std::string,
00592 // not a separate first and last name.
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                 // id found in map therefore we can call the callback immediately.
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                 // id not found in map so we must queue the callback call until available.
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         // These are pending requests that we never heard back from.
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 //static 
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         // First call all the callbacks, because they might send messages.
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         // Forward on all replies, if needed.
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         // You should only get this message if the cache is at the simulator
00847         // level, hence having an upstream provider.
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                                 // ...it's in the cache, so send it as the reply
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 // static call back functions
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 

Generated on Fri May 16 08:32:23 2008 for SecondLife by  doxygen 1.5.5