diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llmessage/llcachename.cpp | |
parent | README.txt (diff) | |
download | meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2 meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz |
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/llmessage/llcachename.cpp')
-rw-r--r-- | linden/indra/llmessage/llcachename.cpp | 782 |
1 files changed, 782 insertions, 0 deletions
diff --git a/linden/indra/llmessage/llcachename.cpp b/linden/indra/llmessage/llcachename.cpp new file mode 100644 index 0000000..9995a6e --- /dev/null +++ b/linden/indra/llmessage/llcachename.cpp | |||
@@ -0,0 +1,782 @@ | |||
1 | /** | ||
2 | * @file llcachename.cpp | ||
3 | * @brief A hierarchical cache of first and last names queried based on UUID. | ||
4 | * | ||
5 | * Copyright (c) 2002-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #include "linden_common.h" | ||
29 | |||
30 | #include "llcachename.h" | ||
31 | |||
32 | // system includes | ||
33 | #include <string.h> // strcpy | ||
34 | #include <time.h> | ||
35 | #include <algorithm> | ||
36 | #include <functional> | ||
37 | #include <map> | ||
38 | |||
39 | // linden library includes | ||
40 | #include "message.h" | ||
41 | #include "llrand.h" | ||
42 | #include "lldbstrings.h" | ||
43 | #include "llframetimer.h" | ||
44 | #include "llhost.h" | ||
45 | #include "lluuid.h" | ||
46 | |||
47 | // Constants | ||
48 | const char* CN_WAITING = "(waiting)"; | ||
49 | const char* CN_NOBODY = "(nobody)"; | ||
50 | const char* CN_NONE = "(none)"; | ||
51 | const char* CN_HIPPOS = "(hippos)"; | ||
52 | const F32 HIPPO_PROBABILITY = 0.01f; | ||
53 | |||
54 | // File version number | ||
55 | const S32 CN_FILE_VERSION = 2; | ||
56 | |||
57 | // Globals | ||
58 | LLCacheName* gCacheName = NULL; | ||
59 | |||
60 | /// --------------------------------------------------------------------------- | ||
61 | /// class LLCacheNameEntry | ||
62 | /// --------------------------------------------------------------------------- | ||
63 | |||
64 | namespace { | ||
65 | class LLCacheNameEntry | ||
66 | { | ||
67 | public: | ||
68 | LLCacheNameEntry(); | ||
69 | |||
70 | public: | ||
71 | bool mIsGroup; | ||
72 | U32 mCreateTime; // unix time_t | ||
73 | char mFirstName[DB_FIRST_NAME_BUF_SIZE]; /*Flawfinder: ignore*/ | ||
74 | char mLastName[DB_LAST_NAME_BUF_SIZE]; /*Flawfinder: ignore*/ | ||
75 | char mGroupName[DB_GROUP_NAME_BUF_SIZE]; /*Flawfinder: ignore*/ | ||
76 | }; | ||
77 | |||
78 | LLCacheNameEntry::LLCacheNameEntry() | ||
79 | { | ||
80 | mFirstName[0] = '\0'; | ||
81 | mLastName[0] = '\0'; | ||
82 | mGroupName[0] = '\0'; | ||
83 | } | ||
84 | |||
85 | |||
86 | class PendingReply | ||
87 | { | ||
88 | public: | ||
89 | LLUUID mID; | ||
90 | LLCacheNameCallback mCallback; | ||
91 | LLHost mHost; | ||
92 | void* mData; | ||
93 | PendingReply(const LLUUID& id, LLCacheNameCallback callback, void* data = NULL) | ||
94 | : mID(id), mCallback(callback), mData(data) | ||
95 | { } | ||
96 | |||
97 | PendingReply(const LLUUID& id, const LLHost& host) | ||
98 | : mID(id), mCallback(0), mHost(host) | ||
99 | { } | ||
100 | |||
101 | void done() { mID.setNull(); } | ||
102 | bool isDone() const { return mID.isNull() != FALSE; } | ||
103 | }; | ||
104 | |||
105 | class ReplySender | ||
106 | { | ||
107 | public: | ||
108 | ReplySender(LLMessageSystem* msg); | ||
109 | ~ReplySender(); | ||
110 | |||
111 | void send(const LLUUID& id, | ||
112 | const LLCacheNameEntry& entry, const LLHost& host); | ||
113 | |||
114 | private: | ||
115 | void flush(); | ||
116 | |||
117 | LLMessageSystem* mMsg; | ||
118 | bool mPending; | ||
119 | bool mCurrIsGroup; | ||
120 | LLHost mCurrHost; | ||
121 | }; | ||
122 | |||
123 | ReplySender::ReplySender(LLMessageSystem* msg) | ||
124 | : mMsg(msg), mPending(false) | ||
125 | { } | ||
126 | |||
127 | ReplySender::~ReplySender() | ||
128 | { | ||
129 | flush(); | ||
130 | } | ||
131 | |||
132 | void ReplySender::send(const LLUUID& id, | ||
133 | const LLCacheNameEntry& entry, const LLHost& host) | ||
134 | { | ||
135 | if (mPending) | ||
136 | { | ||
137 | if (mCurrIsGroup != entry.mIsGroup | ||
138 | || mCurrHost != host) | ||
139 | { | ||
140 | flush(); | ||
141 | } | ||
142 | } | ||
143 | |||
144 | if (!mPending) | ||
145 | { | ||
146 | mPending = true; | ||
147 | mCurrIsGroup = entry.mIsGroup; | ||
148 | mCurrHost = host; | ||
149 | |||
150 | if(mCurrIsGroup) | ||
151 | mMsg->newMessageFast(_PREHASH_UUIDGroupNameReply); | ||
152 | else | ||
153 | mMsg->newMessageFast(_PREHASH_UUIDNameReply); | ||
154 | } | ||
155 | |||
156 | mMsg->nextBlockFast(_PREHASH_UUIDNameBlock); | ||
157 | mMsg->addUUIDFast(_PREHASH_ID, id); | ||
158 | if(mCurrIsGroup) | ||
159 | { | ||
160 | mMsg->addStringFast(_PREHASH_GroupName, entry.mGroupName); | ||
161 | } | ||
162 | else | ||
163 | { | ||
164 | mMsg->addStringFast(_PREHASH_FirstName, entry.mFirstName); | ||
165 | mMsg->addStringFast(_PREHASH_LastName, entry.mLastName); | ||
166 | } | ||
167 | |||
168 | if(mMsg->isSendFullFast(_PREHASH_UUIDNameBlock)) | ||
169 | { | ||
170 | flush(); | ||
171 | } | ||
172 | } | ||
173 | |||
174 | void ReplySender::flush() | ||
175 | { | ||
176 | if (mPending) | ||
177 | { | ||
178 | mMsg->sendReliable(mCurrHost); | ||
179 | mPending = false; | ||
180 | } | ||
181 | } | ||
182 | |||
183 | |||
184 | typedef std::vector<LLUUID> AskQueue; | ||
185 | typedef std::vector<PendingReply> ReplyQueue; | ||
186 | typedef std::map<LLUUID, LLCacheNameEntry*> Cache; | ||
187 | typedef std::vector<LLCacheNameCallback> Observers; | ||
188 | }; | ||
189 | |||
190 | class LLCacheName::Impl | ||
191 | { | ||
192 | public: | ||
193 | LLMessageSystem* mMsg; | ||
194 | LLHost mUpstreamHost; | ||
195 | |||
196 | Cache mCache; | ||
197 | // the map of UUIDs to names | ||
198 | |||
199 | AskQueue mAskNameQueue; | ||
200 | AskQueue mAskGroupQueue; | ||
201 | // UUIDs to ask our upstream host about | ||
202 | |||
203 | ReplyQueue mReplyQueue; | ||
204 | // requests awaiting replies from us | ||
205 | |||
206 | Observers mObservers; | ||
207 | |||
208 | LLFrameTimer mProcessTimer; | ||
209 | |||
210 | Impl(LLMessageSystem* msg); | ||
211 | ~Impl(); | ||
212 | |||
213 | void processPendingAsks(); | ||
214 | void processPendingReplies(); | ||
215 | void sendRequest(const char* msg_name, const AskQueue& queue); | ||
216 | |||
217 | // Message system callbacks. | ||
218 | void processUUIDRequest(LLMessageSystem* msg, bool isGroup); | ||
219 | void processUUIDReply(LLMessageSystem* msg, bool isGroup); | ||
220 | |||
221 | static void handleUUIDNameRequest(LLMessageSystem* msg, void** userdata); | ||
222 | static void handleUUIDNameReply(LLMessageSystem* msg, void** userdata); | ||
223 | static void handleUUIDGroupNameRequest(LLMessageSystem* msg, void** userdata); | ||
224 | static void handleUUIDGroupNameReply(LLMessageSystem* msg, void** userdata); | ||
225 | |||
226 | void notifyObservers(const LLUUID& id, const char* first, const char* last, BOOL group); | ||
227 | }; | ||
228 | |||
229 | |||
230 | /// -------------------------------------------------------------------------- | ||
231 | /// class LLCacheName | ||
232 | /// --------------------------------------------------------------------------- | ||
233 | |||
234 | LLCacheName::LLCacheName(LLMessageSystem* msg) | ||
235 | : impl(* new Impl(msg)) | ||
236 | { } | ||
237 | |||
238 | LLCacheName::LLCacheName(LLMessageSystem* msg, const LLHost& upstream_host) | ||
239 | : impl(* new Impl(msg)) | ||
240 | { | ||
241 | setUpstream(upstream_host); | ||
242 | } | ||
243 | |||
244 | LLCacheName::~LLCacheName() | ||
245 | { | ||
246 | delete &impl; | ||
247 | } | ||
248 | |||
249 | LLCacheName::Impl::Impl(LLMessageSystem* msg) | ||
250 | : mMsg(msg), mUpstreamHost(LLHost::invalid) | ||
251 | { | ||
252 | mMsg->setHandlerFuncFast( | ||
253 | _PREHASH_UUIDNameRequest, handleUUIDNameRequest, (void**)this); | ||
254 | mMsg->setHandlerFuncFast( | ||
255 | _PREHASH_UUIDNameReply, handleUUIDNameReply, (void**)this); | ||
256 | mMsg->setHandlerFuncFast( | ||
257 | _PREHASH_UUIDGroupNameRequest, handleUUIDGroupNameRequest, (void**)this); | ||
258 | mMsg->setHandlerFuncFast( | ||
259 | _PREHASH_UUIDGroupNameReply, handleUUIDGroupNameReply, (void**)this); | ||
260 | } | ||
261 | |||
262 | |||
263 | LLCacheName::Impl::~Impl() | ||
264 | { | ||
265 | for_each(mCache.begin(), mCache.end(), DeletePairedPointer()); | ||
266 | } | ||
267 | |||
268 | |||
269 | void LLCacheName::setUpstream(const LLHost& upstream_host) | ||
270 | { | ||
271 | impl.mUpstreamHost = upstream_host; | ||
272 | } | ||
273 | |||
274 | void LLCacheName::addObserver(LLCacheNameCallback callback) | ||
275 | { | ||
276 | impl.mObservers.push_back(callback); | ||
277 | } | ||
278 | |||
279 | |||
280 | void LLCacheName::importFile(FILE* fp) | ||
281 | { | ||
282 | S32 count = 0; | ||
283 | |||
284 | const S32 BUFFER_SIZE = 1024; | ||
285 | char buffer[BUFFER_SIZE]; /*Flawfinder: ignore*/ | ||
286 | |||
287 | char id_string[MAX_STRING]; /*Flawfinder: ignore*/ | ||
288 | char firstname[MAX_STRING]; /*Flawfinder: ignore*/ | ||
289 | char lastname[MAX_STRING]; /*Flawfinder: ignore*/ | ||
290 | U32 create_time; | ||
291 | |||
292 | // This is OK if the first line is actually a name. We just don't load it. | ||
293 | char* valid = fgets(buffer, BUFFER_SIZE, fp); | ||
294 | if (!valid) return; | ||
295 | |||
296 | char version_string[BUFFER_SIZE]; /*Flawfinder: ignore*/ | ||
297 | S32 version = 0; | ||
298 | S32 match = sscanf(buffer, "%s %d", version_string, &version); // XXXTBD | ||
299 | if ( match != 2 | ||
300 | || strcmp(version_string, "version") | ||
301 | || version != CN_FILE_VERSION) | ||
302 | { | ||
303 | llwarns << "Ignoring old cache name file format" << llendl; | ||
304 | return; | ||
305 | } | ||
306 | |||
307 | // We'll expire entries more than a week old | ||
308 | U32 now = (U32)time(NULL); | ||
309 | const U32 SECS_PER_DAY = 60 * 60 * 24; | ||
310 | U32 delete_before_time = now - (7 * SECS_PER_DAY); | ||
311 | |||
312 | while(!feof(fp)) | ||
313 | { | ||
314 | valid = fgets(buffer, BUFFER_SIZE, fp); | ||
315 | if (!valid) break; | ||
316 | |||
317 | match = sscanf(buffer, "%s %u %s %s", // XXXTBD | ||
318 | id_string, | ||
319 | &create_time, | ||
320 | firstname, | ||
321 | lastname); | ||
322 | if (4 != match) continue; | ||
323 | |||
324 | LLUUID id(id_string); | ||
325 | if (id.isNull()) continue; | ||
326 | |||
327 | // undo trivial XOR | ||
328 | S32 i; | ||
329 | for (i = 0; i < UUID_BYTES; i++) | ||
330 | { | ||
331 | id.mData[i] ^= 0x33; | ||
332 | } | ||
333 | |||
334 | // Don't load entries that are more than a week old | ||
335 | if (create_time < delete_before_time) continue; | ||
336 | |||
337 | LLCacheNameEntry* entry = new LLCacheNameEntry(); | ||
338 | entry->mIsGroup = false; | ||
339 | entry->mCreateTime = create_time; | ||
340 | LLString::copy(entry->mFirstName, firstname, DB_FIRST_NAME_BUF_SIZE); | ||
341 | LLString::copy(entry->mLastName, lastname, DB_LAST_NAME_BUF_SIZE); | ||
342 | impl.mCache[id] = entry; | ||
343 | |||
344 | count++; | ||
345 | } | ||
346 | |||
347 | llinfos << "LLCacheName loaded " << count << " names" << llendl; | ||
348 | } | ||
349 | |||
350 | |||
351 | void LLCacheName::exportFile(FILE* fp) | ||
352 | { | ||
353 | fprintf(fp, "version\t%d\n", CN_FILE_VERSION); | ||
354 | |||
355 | for (Cache::iterator iter = impl.mCache.begin(), | ||
356 | end = impl.mCache.end(); | ||
357 | iter != end; iter++) | ||
358 | { | ||
359 | LLCacheNameEntry* entry = iter->second; | ||
360 | // Only write entries for which we have valid data. | ||
361 | // HACK: Only write agent names. This makes the reader easier. | ||
362 | if ( entry->mFirstName[0] | ||
363 | && entry->mLastName[0]) | ||
364 | { | ||
365 | LLUUID id = iter->first; | ||
366 | |||
367 | // Trivial XOR encoding | ||
368 | S32 i; | ||
369 | for (i = 0; i < UUID_BYTES; i++) | ||
370 | { | ||
371 | id.mData[i] ^= 0x33; | ||
372 | } | ||
373 | |||
374 | char id_string[UUID_STR_SIZE]; /*Flawfinder:ignore*/ | ||
375 | id.toString(id_string); | ||
376 | |||
377 | // ...not a group name | ||
378 | fprintf(fp, "%s\t%u\t%s\t%s\n", | ||
379 | id_string, | ||
380 | entry->mCreateTime, | ||
381 | entry->mFirstName, | ||
382 | entry->mLastName); | ||
383 | } | ||
384 | } | ||
385 | } | ||
386 | |||
387 | |||
388 | BOOL LLCacheName::getName(const LLUUID& id, char* first, char* last) | ||
389 | { | ||
390 | if(id.isNull()) | ||
391 | { | ||
392 | // The function signature needs to change to pass in the | ||
393 | // length of first and last. | ||
394 | strcpy(first, CN_NOBODY); | ||
395 | last[0] = '\0'; | ||
396 | return FALSE; | ||
397 | } | ||
398 | |||
399 | LLCacheNameEntry* entry = get_ptr_in_map(impl.mCache, id ); | ||
400 | if (entry) | ||
401 | { | ||
402 | // The function signature needs to change to pass in the | ||
403 | // length of first and last. | ||
404 | strcpy(first, entry->mFirstName); | ||
405 | strcpy(last, entry->mLastName); | ||
406 | return TRUE; | ||
407 | } | ||
408 | else | ||
409 | { | ||
410 | //The function signature needs to change to pass in the | ||
411 | //length of first and last. | ||
412 | strcpy(first,(frand(1.0f) < HIPPO_PROBABILITY) | ||
413 | ? CN_HIPPOS | ||
414 | : CN_WAITING); | ||
415 | strcpy(last, ""); | ||
416 | |||
417 | impl.mAskNameQueue.push_back(id); | ||
418 | return FALSE; | ||
419 | } | ||
420 | |||
421 | } | ||
422 | |||
423 | |||
424 | |||
425 | BOOL LLCacheName::getGroupName(const LLUUID& id, char* group) | ||
426 | { | ||
427 | if(id.isNull()) | ||
428 | { | ||
429 | // The function signature needs to change to pass in the | ||
430 | // length of first and last. | ||
431 | strcpy(group, CN_NONE); | ||
432 | return FALSE; | ||
433 | } | ||
434 | |||
435 | LLCacheNameEntry* entry = get_ptr_in_map(impl.mCache,id); | ||
436 | if (entry && !entry->mGroupName[0]) | ||
437 | { | ||
438 | // COUNTER-HACK to combat James' HACK in exportFile()... | ||
439 | // this group name was loaded from a name cache that did not | ||
440 | // bother to save the group name ==> we must ask for it | ||
441 | lldebugs << "LLCacheName queuing HACK group request: " << id << llendl; | ||
442 | entry = NULL; | ||
443 | } | ||
444 | |||
445 | if (entry) | ||
446 | { | ||
447 | // The function signature needs to change to pass in the length | ||
448 | // of group. | ||
449 | strcpy(group, entry->mGroupName); | ||
450 | return TRUE; | ||
451 | } | ||
452 | else | ||
453 | { | ||
454 | // The function signature needs to change to pass in the length | ||
455 | // of first and last. | ||
456 | strcpy(group, CN_WAITING); | ||
457 | |||
458 | impl.mAskGroupQueue.push_back(id); | ||
459 | return FALSE; | ||
460 | } | ||
461 | } | ||
462 | |||
463 | // TODO: Make the cache name callback take a SINGLE std::string, | ||
464 | // not a separate first and last name. | ||
465 | void LLCacheName::get(const LLUUID& id, BOOL is_group, LLCacheNameCallback callback, void* user_data) | ||
466 | { | ||
467 | if(id.isNull()) | ||
468 | { | ||
469 | callback(id, CN_NOBODY, "", is_group, user_data); | ||
470 | } | ||
471 | |||
472 | LLCacheNameEntry* entry = get_ptr_in_map(impl.mCache, id ); | ||
473 | if (entry) | ||
474 | { | ||
475 | if (!entry->mIsGroup) | ||
476 | { | ||
477 | callback(id, entry->mFirstName, entry->mLastName, entry->mIsGroup, user_data); | ||
478 | } | ||
479 | else | ||
480 | { | ||
481 | callback(id, entry->mGroupName, "", entry->mIsGroup, user_data); | ||
482 | } | ||
483 | } | ||
484 | else | ||
485 | { | ||
486 | if (!is_group) | ||
487 | { | ||
488 | impl.mAskNameQueue.push_back(id); | ||
489 | } | ||
490 | else | ||
491 | { | ||
492 | impl.mAskGroupQueue.push_back(id); | ||
493 | } | ||
494 | impl.mReplyQueue.push_back(PendingReply(id, callback, user_data)); | ||
495 | } | ||
496 | } | ||
497 | |||
498 | void LLCacheName::processPending() | ||
499 | { | ||
500 | const F32 SECS_BETWEEN_PROCESS = 0.1f; | ||
501 | if(!impl.mProcessTimer.checkExpirationAndReset(SECS_BETWEEN_PROCESS)) | ||
502 | { | ||
503 | return; | ||
504 | } | ||
505 | |||
506 | if(!impl.mUpstreamHost.isOk()) | ||
507 | { | ||
508 | lldebugs << "LLCacheName::processPending() - bad upstream host." | ||
509 | << llendl; | ||
510 | return; | ||
511 | } | ||
512 | |||
513 | impl.processPendingAsks(); | ||
514 | impl.processPendingReplies(); | ||
515 | } | ||
516 | |||
517 | void LLCacheName::deleteEntriesOlderThan(S32 secs) | ||
518 | { | ||
519 | U32 now = (U32)time(NULL); | ||
520 | U32 expire_time = now - secs; | ||
521 | for(Cache::iterator iter = impl.mCache.begin(); iter != impl.mCache.end(); ) | ||
522 | { | ||
523 | Cache::iterator curiter = iter++; | ||
524 | LLCacheNameEntry* entry = curiter->second; | ||
525 | if (entry->mCreateTime < expire_time) | ||
526 | { | ||
527 | delete entry; | ||
528 | impl.mCache.erase(curiter); | ||
529 | } | ||
530 | } | ||
531 | } | ||
532 | |||
533 | |||
534 | void LLCacheName::dump() | ||
535 | { | ||
536 | for (Cache::iterator iter = impl.mCache.begin(), | ||
537 | end = impl.mCache.end(); | ||
538 | iter != end; iter++) | ||
539 | { | ||
540 | LLCacheNameEntry* entry = iter->second; | ||
541 | if (entry->mIsGroup) | ||
542 | { | ||
543 | llinfos | ||
544 | << iter->first << " = (group) " | ||
545 | << entry->mGroupName | ||
546 | << " @ " << entry->mCreateTime | ||
547 | << llendl; | ||
548 | } | ||
549 | else | ||
550 | { | ||
551 | llinfos | ||
552 | << iter->first << " = " | ||
553 | << entry->mFirstName << " " << entry->mLastName | ||
554 | << " @ " << entry->mCreateTime | ||
555 | << llendl; | ||
556 | } | ||
557 | } | ||
558 | } | ||
559 | |||
560 | void LLCacheName::Impl::processPendingAsks() | ||
561 | { | ||
562 | sendRequest(_PREHASH_UUIDNameRequest, mAskNameQueue); | ||
563 | sendRequest(_PREHASH_UUIDGroupNameRequest, mAskGroupQueue); | ||
564 | mAskNameQueue.clear(); | ||
565 | mAskGroupQueue.clear(); | ||
566 | } | ||
567 | |||
568 | void LLCacheName::Impl::processPendingReplies() | ||
569 | { | ||
570 | ReplyQueue::iterator it = mReplyQueue.begin(); | ||
571 | ReplyQueue::iterator end = mReplyQueue.end(); | ||
572 | |||
573 | // First call all the callbacks, because they might send messages. | ||
574 | for(; it != end; ++it) | ||
575 | { | ||
576 | LLCacheNameEntry* entry = get_ptr_in_map(mCache, it->mID); | ||
577 | if(!entry) continue; | ||
578 | |||
579 | if (it->mCallback) | ||
580 | { | ||
581 | if (!entry->mIsGroup) | ||
582 | { | ||
583 | (it->mCallback)(it->mID, | ||
584 | entry->mFirstName, entry->mLastName, | ||
585 | FALSE, it->mData); | ||
586 | } | ||
587 | else { | ||
588 | (it->mCallback)(it->mID, | ||
589 | entry->mGroupName, "", | ||
590 | TRUE, it->mData); | ||
591 | } | ||
592 | } | ||
593 | } | ||
594 | |||
595 | // Forward on all replies, if needed. | ||
596 | ReplySender sender(mMsg); | ||
597 | for (it = mReplyQueue.begin(); it != end; ++it) | ||
598 | { | ||
599 | LLCacheNameEntry* entry = get_ptr_in_map(mCache, it->mID); | ||
600 | if(!entry) continue; | ||
601 | |||
602 | if (it->mHost.isOk()) | ||
603 | { | ||
604 | sender.send(it->mID, *entry, it->mHost); | ||
605 | } | ||
606 | |||
607 | it->done(); | ||
608 | } | ||
609 | |||
610 | mReplyQueue.erase( | ||
611 | remove_if(mReplyQueue.begin(), mReplyQueue.end(), | ||
612 | std::mem_fun_ref(&PendingReply::isDone)), | ||
613 | mReplyQueue.end()); | ||
614 | } | ||
615 | |||
616 | |||
617 | void LLCacheName::Impl::sendRequest( | ||
618 | const char* msg_name, | ||
619 | const AskQueue& queue) | ||
620 | { | ||
621 | if(queue.empty()) | ||
622 | { | ||
623 | return; | ||
624 | } | ||
625 | |||
626 | bool start_new_message = true; | ||
627 | AskQueue::const_iterator it = queue.begin(); | ||
628 | AskQueue::const_iterator end = queue.end(); | ||
629 | for(; it != end; ++it) | ||
630 | { | ||
631 | if(start_new_message) | ||
632 | { | ||
633 | start_new_message = false; | ||
634 | mMsg->newMessageFast(msg_name); | ||
635 | } | ||
636 | mMsg->nextBlockFast(_PREHASH_UUIDNameBlock); | ||
637 | mMsg->addUUIDFast(_PREHASH_ID, (*it)); | ||
638 | |||
639 | if(mMsg->isSendFullFast(_PREHASH_UUIDNameBlock)) | ||
640 | { | ||
641 | start_new_message = true; | ||
642 | mMsg->sendReliable(mUpstreamHost); | ||
643 | } | ||
644 | } | ||
645 | if(!start_new_message) | ||
646 | { | ||
647 | mMsg->sendReliable(mUpstreamHost); | ||
648 | } | ||
649 | } | ||
650 | |||
651 | void LLCacheName::Impl::notifyObservers(const LLUUID& id, | ||
652 | const char* first, const char* last, BOOL is_group) | ||
653 | { | ||
654 | for (Observers::const_iterator i = mObservers.begin(), | ||
655 | end = mObservers.end(); | ||
656 | i != end; | ||
657 | ++i) | ||
658 | { | ||
659 | (**i)(id, first, last, is_group, NULL); | ||
660 | } | ||
661 | } | ||
662 | |||
663 | |||
664 | void LLCacheName::Impl::processUUIDRequest(LLMessageSystem* msg, bool isGroup) | ||
665 | { | ||
666 | // You should only get this message if the cache is at the simulator | ||
667 | // level, hence having an upstream provider. | ||
668 | if (!mUpstreamHost.isOk()) | ||
669 | { | ||
670 | llwarns << "LLCacheName - got UUID name/group request, but no upstream provider!" << llendl; | ||
671 | return; | ||
672 | } | ||
673 | |||
674 | LLHost fromHost = msg->getSender(); | ||
675 | ReplySender sender(msg); | ||
676 | |||
677 | S32 count = msg->getNumberOfBlocksFast(_PREHASH_UUIDNameBlock); | ||
678 | for(S32 i = 0; i < count; ++i) | ||
679 | { | ||
680 | LLUUID id; | ||
681 | msg->getUUIDFast(_PREHASH_UUIDNameBlock, _PREHASH_ID, id, i); | ||
682 | LLCacheNameEntry* entry = get_ptr_in_map(mCache, id); | ||
683 | if(entry) | ||
684 | { | ||
685 | if (isGroup != entry->mIsGroup) | ||
686 | { | ||
687 | llwarns << "LLCacheName - Asked for " | ||
688 | << (isGroup ? "group" : "user") << " name, " | ||
689 | << "but found " | ||
690 | << (entry->mIsGroup ? "group" : "user") | ||
691 | << ": " << id << llendl; | ||
692 | } | ||
693 | else | ||
694 | { | ||
695 | // ...it's in the cache, so send it as the reply | ||
696 | sender.send(id, *entry, fromHost); | ||
697 | } | ||
698 | } | ||
699 | else | ||
700 | { | ||
701 | if (isGroup) | ||
702 | { | ||
703 | mAskGroupQueue.push_back(id); | ||
704 | } | ||
705 | else | ||
706 | { | ||
707 | mAskNameQueue.push_back(id); | ||
708 | } | ||
709 | |||
710 | mReplyQueue.push_back(PendingReply(id, fromHost)); | ||
711 | } | ||
712 | } | ||
713 | } | ||
714 | |||
715 | |||
716 | |||
717 | void LLCacheName::Impl::processUUIDReply(LLMessageSystem* msg, bool isGroup) | ||
718 | { | ||
719 | S32 count = msg->getNumberOfBlocksFast(_PREHASH_UUIDNameBlock); | ||
720 | for(S32 i = 0; i < count; ++i) | ||
721 | { | ||
722 | LLUUID id; | ||
723 | msg->getUUIDFast(_PREHASH_UUIDNameBlock, _PREHASH_ID, id, i); | ||
724 | LLCacheNameEntry* entry = get_ptr_in_map(mCache, id); | ||
725 | if (!entry) | ||
726 | { | ||
727 | entry = new LLCacheNameEntry; | ||
728 | mCache[id] = entry; | ||
729 | } | ||
730 | |||
731 | entry->mIsGroup = isGroup; | ||
732 | entry->mCreateTime = (U32)time(NULL); | ||
733 | if (!isGroup) | ||
734 | { | ||
735 | msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_FirstName, DB_FIRST_NAME_BUF_SIZE, entry->mFirstName, i); | ||
736 | msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_LastName, DB_LAST_NAME_BUF_SIZE, entry->mLastName, i); | ||
737 | } | ||
738 | else | ||
739 | { | ||
740 | msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_GroupName, DB_GROUP_NAME_BUF_SIZE, entry->mGroupName, i); | ||
741 | } | ||
742 | |||
743 | if (!isGroup) | ||
744 | { | ||
745 | notifyObservers(id, | ||
746 | entry->mFirstName, entry->mLastName, | ||
747 | FALSE); | ||
748 | } | ||
749 | else | ||
750 | { | ||
751 | notifyObservers(id, entry->mGroupName, "", TRUE); | ||
752 | } | ||
753 | } | ||
754 | } | ||
755 | |||
756 | |||
757 | |||
758 | // static call back functions | ||
759 | |||
760 | void LLCacheName::Impl::handleUUIDNameReply(LLMessageSystem* msg, void** userData) | ||
761 | { | ||
762 | ((LLCacheName::Impl*)userData)->processUUIDReply(msg, false); | ||
763 | } | ||
764 | |||
765 | void LLCacheName::Impl::handleUUIDNameRequest(LLMessageSystem* msg, void** userData) | ||
766 | { | ||
767 | ((LLCacheName::Impl*)userData)->processUUIDRequest(msg, false); | ||
768 | } | ||
769 | |||
770 | void LLCacheName::Impl::handleUUIDGroupNameRequest(LLMessageSystem* msg, void** userData) | ||
771 | { | ||
772 | ((LLCacheName::Impl*)userData)->processUUIDRequest(msg, true); | ||
773 | } | ||
774 | |||
775 | void LLCacheName::Impl::handleUUIDGroupNameReply(LLMessageSystem* msg, void** userData) | ||
776 | { | ||
777 | ((LLCacheName::Impl*)userData)->processUUIDReply(msg, true); | ||
778 | } | ||
779 | |||
780 | |||
781 | |||
782 | |||