io.cpp

Go to the documentation of this file.
00001 
00034 #include "linden_common.h"
00035 #include "lltut.h"
00036 
00037 #include <iterator>
00038 
00039 #include <apr-1/apr_pools.h>
00040 
00041 #include "llbuffer.h"
00042 #include "llbufferstream.h"
00043 #include "lliosocket.h"
00044 #include "llioutil.h"
00045 #include "llmemorystream.h"
00046 #include "llpipeutil.h"
00047 #include "llpumpio.h"
00048 #include "llsd.h"
00049 #include "llsdrpcclient.h"
00050 #include "llsdrpcserver.h"
00051 #include "llsdserialize.h"
00052 #include "lluuid.h"
00053 #include "llinstantmessage.h"
00054 
00055 namespace tut
00056 {
00057         struct heap_buffer_data
00058         {
00059                 heap_buffer_data() : mBuffer(NULL) {}
00060                 ~heap_buffer_data() { if(mBuffer) delete mBuffer; }
00061                 LLHeapBuffer* mBuffer;
00062         };
00063         typedef test_group<heap_buffer_data> heap_buffer_test;
00064         typedef heap_buffer_test::object heap_buffer_object;
00065         tut::heap_buffer_test thb("heap_buffer");
00066 
00067         template<> template<>
00068         void heap_buffer_object::test<1>()
00069         {
00070                 const S32 BUF_SIZE = 100;
00071                 mBuffer = new LLHeapBuffer(BUF_SIZE);
00072                 ensure_equals("empty buffer capacity", mBuffer->capacity(), BUF_SIZE);
00073                 const S32 SEGMENT_SIZE = 50;
00074                 LLSegment segment;
00075                 mBuffer->createSegment(0, SEGMENT_SIZE, segment);
00076                 ensure_equals("used buffer capacity", mBuffer->capacity(), BUF_SIZE);
00077         }
00078 
00079         template<> template<>
00080         void heap_buffer_object::test<2>()
00081         {
00082                 const S32 BUF_SIZE = 10;
00083                 mBuffer = new LLHeapBuffer(BUF_SIZE);
00084                 LLSegment segment;
00085                 mBuffer->createSegment(0, BUF_SIZE, segment);
00086                 ensure("segment is in buffer", mBuffer->containsSegment(segment));
00087                 ensure_equals("buffer consumed", mBuffer->bytesLeft(), 0);
00088                 bool  created;
00089                 created = mBuffer->createSegment(0, 0, segment);
00090                 ensure("Create zero size segment fails", !created);
00091                 created = mBuffer->createSegment(0, BUF_SIZE, segment);
00092                 ensure("Create segment fails", !created);
00093         }
00094 
00095         template<> template<>
00096         void heap_buffer_object::test<3>()
00097         {
00098                 const S32 BUF_SIZE = 10;
00099                 mBuffer = new LLHeapBuffer(BUF_SIZE);
00100                 LLSegment segment;
00101                 mBuffer->createSegment(0, BUF_SIZE, segment);
00102                 ensure("segment is in buffer", mBuffer->containsSegment(segment));
00103                 ensure_equals("buffer consumed", mBuffer->bytesLeft(), 0);
00104                 bool reclaimed = mBuffer->reclaimSegment(segment);
00105                 ensure("buffer reclaimed.", reclaimed);
00106                 ensure_equals("buffer available", mBuffer->bytesLeft(), BUF_SIZE);
00107                 bool  created;
00108                 created = mBuffer->createSegment(0, 0, segment);
00109                 ensure("Create zero size segment fails", !created);
00110                 created = mBuffer->createSegment(0, BUF_SIZE, segment);
00111                 ensure("Create another segment succeeds", created);
00112         }
00113 
00114         template<> template<>
00115         void heap_buffer_object::test<4>()
00116         {
00117                 const S32 BUF_SIZE = 10;
00118                 const S32 SEGMENT_SIZE = 4;
00119                 mBuffer = new LLHeapBuffer(BUF_SIZE);
00120                 LLSegment seg1;
00121                 mBuffer->createSegment(0, SEGMENT_SIZE, seg1);
00122                 ensure("segment is in buffer", mBuffer->containsSegment(seg1));
00123                 LLSegment seg2;
00124                 mBuffer->createSegment(0, SEGMENT_SIZE, seg2);
00125                 ensure("segment is in buffer", mBuffer->containsSegment(seg2));
00126                 LLSegment seg3;
00127                 mBuffer->createSegment(0, SEGMENT_SIZE, seg3);
00128                 ensure("segment is in buffer", mBuffer->containsSegment(seg3));
00129                 ensure_equals("segment is truncated", seg3.size(), 2);
00130                 LLSegment seg4;
00131                 bool created;
00132                 created = mBuffer->createSegment(0, SEGMENT_SIZE, seg4);
00133                 ensure("Create segment fails", !created);
00134                 bool reclaimed;
00135                 reclaimed = mBuffer->reclaimSegment(seg1);
00136                 ensure("buffer reclaim succeed.", reclaimed);
00137                 ensure_equals("no buffer available", mBuffer->bytesLeft(), 0);
00138                 reclaimed = mBuffer->reclaimSegment(seg2);
00139                 ensure("buffer reclaim succeed.", reclaimed);
00140                 ensure_equals("buffer reclaimed", mBuffer->bytesLeft(), 0);
00141                 reclaimed = mBuffer->reclaimSegment(seg3);
00142                 ensure("buffer reclaim succeed.", reclaimed);
00143                 ensure_equals("buffer reclaimed", mBuffer->bytesLeft(), BUF_SIZE);
00144                 created = mBuffer->createSegment(0, SEGMENT_SIZE, seg1);
00145                 ensure("segment is in buffer", mBuffer->containsSegment(seg1));
00146                 ensure("Create segment succeds", created);
00147         }
00148 }
00149 
00150 namespace tut
00151 {
00152         struct buffer_data
00153         {
00154                 LLBufferArray mBuffer;
00155         };
00156         typedef test_group<buffer_data> buffer_test;
00157         typedef buffer_test::object buffer_object;
00158         tut::buffer_test tba("buffer_array");
00159 
00160         template<> template<>
00161         void buffer_object::test<1>()
00162         {
00163                 const char HELLO_WORLD[] = "hello world";
00164                 const S32 str_len = strlen(HELLO_WORLD);
00165                 LLChannelDescriptors ch = mBuffer.nextChannel();
00166                 mBuffer.append(ch.in(), (U8*)HELLO_WORLD, str_len);
00167                 S32 count = mBuffer.countAfter(ch.in(), NULL);
00168                 ensure_equals("total append size", count, str_len);
00169                 LLBufferArray::segment_iterator_t it = mBuffer.beginSegment();
00170                 U8* first = (*it).data();
00171                 count = mBuffer.countAfter(ch.in(), first);
00172                 ensure_equals("offset append size", count, str_len - 1);
00173         }
00174 
00175         template<> template<>
00176         void buffer_object::test<2>()
00177         {
00178                 const char HELLO_WORLD[] = "hello world";
00179                 const S32 str_len = strlen(HELLO_WORLD);                /* Flawfinder: ignore */
00180                 LLChannelDescriptors ch = mBuffer.nextChannel();
00181                 mBuffer.append(ch.in(), (U8*)HELLO_WORLD, str_len);
00182                 mBuffer.append(ch.in(), (U8*)HELLO_WORLD, str_len);
00183                 S32 count = mBuffer.countAfter(ch.in(), NULL);
00184                 ensure_equals("total append size", count, 2 * str_len);
00185                 LLBufferArray::segment_iterator_t it = mBuffer.beginSegment();
00186                 U8* first = (*it).data();
00187                 count = mBuffer.countAfter(ch.in(), first);
00188                 ensure_equals("offset append size", count, (2 * str_len) - 1);
00189         }
00190 
00191         template<> template<>
00192         void buffer_object::test<3>()
00193         {
00194                 const char ONE[] = "one";
00195                 const char TWO[] = "two";
00196                 std::string expected(ONE);
00197                 expected.append(TWO);
00198                 LLChannelDescriptors ch = mBuffer.nextChannel();
00199                 mBuffer.append(ch.in(), (U8*)ONE, 3);
00200                 mBuffer.append(ch.in(), (U8*)TWO, 3);
00201                 char buffer[255];       /* Flawfinder: ignore */
00202                 S32 len = 6;
00203                 mBuffer.readAfter(ch.in(), NULL, (U8*)buffer, len);
00204                 ensure_equals(len, 6);
00205                 buffer[len] = '\0';
00206                 std::string actual(buffer);
00207                 ensure_equals("read", actual, expected);
00208         }
00209 
00210         template<> template<>
00211         void buffer_object::test<4>()
00212         {
00213                 const char ONE[] = "one";
00214                 const char TWO[] = "two";
00215                 std::string expected(ONE);
00216                 expected.append(TWO);
00217                 LLChannelDescriptors ch = mBuffer.nextChannel();
00218                 mBuffer.append(ch.in(), (U8*)TWO, 3);
00219                 mBuffer.prepend(ch.in(), (U8*)ONE, 3);
00220                 char buffer[255];       /* Flawfinder: ignore */
00221                 S32 len = 6;
00222                 mBuffer.readAfter(ch.in(), NULL, (U8*)buffer, len);
00223                 ensure_equals(len, 6);
00224                 buffer[len] = '\0';
00225                 std::string actual(buffer);
00226                 ensure_equals("read", actual, expected);
00227         }
00228 
00229         template<> template<>
00230         void buffer_object::test<5>()
00231         {
00232                 const char ONE[] = "one";
00233                 const char TWO[] = "two";
00234                 std::string expected("netwo");
00235                 LLChannelDescriptors ch = mBuffer.nextChannel();
00236                 mBuffer.append(ch.in(), (U8*)TWO, 3);
00237                 mBuffer.prepend(ch.in(), (U8*)ONE, 3);
00238                 char buffer[255];       /* Flawfinder: ignore */
00239                 S32 len = 5;
00240                 LLBufferArray::segment_iterator_t it = mBuffer.beginSegment();
00241                 U8* addr = (*it).data();
00242                 mBuffer.readAfter(ch.in(), addr, (U8*)buffer, len);
00243                 ensure_equals(len, 5);
00244                 buffer[len] = '\0';
00245                 std::string actual(buffer);
00246                 ensure_equals("read", actual, expected);
00247         }
00248 
00249         template<> template<>
00250         void buffer_object::test<6>()
00251         {
00252                 std::string request("The early bird catches the worm.");
00253                 std::string response("If you're a worm, sleep late.");
00254                 std::ostringstream expected;
00255                 expected << "ContentLength: " << response.length() << "\r\n\r\n"
00256                                  << response;
00257                 LLChannelDescriptors ch = mBuffer.nextChannel();
00258                 mBuffer.append(ch.in(), (U8*)request.c_str(), request.length());
00259                 mBuffer.append(ch.out(), (U8*)response.c_str(), response.length());
00260                 S32 count = mBuffer.countAfter(ch.out(), NULL);
00261                 std::ostringstream header;
00262                 header << "ContentLength: " << count << "\r\n\r\n";
00263                 std::string head(header.str());
00264                 mBuffer.prepend(ch.out(), (U8*)head.c_str(), head.length());
00265                 char buffer[1024];      /* Flawfinder: ignore */
00266                 S32 len = response.size() + head.length();
00267                 ensure_equals("same length", len, (S32)expected.str().length());
00268                 mBuffer.readAfter(ch.out(), NULL, (U8*)buffer, len);
00269                 buffer[len] = '\0';
00270                 std::string actual(buffer);
00271                 ensure_equals("threaded writes", actual, expected.str());
00272         }
00273 
00274         template<> template<>
00275         void buffer_object::test<7>()
00276         {
00277                 const S32 LINE_COUNT = 3;
00278                 std::string lines[LINE_COUNT] =
00279                         {
00280                                 std::string("GET /index.htm HTTP/1.0\r\n"),
00281                                 std::string("User-Agent: Wget/1.9.1\r\n"),
00282                                 std::string("Host: localhost:8008\r\n")
00283                         };
00284                 std::string text;
00285                 S32 i;
00286                 for(i = 0; i < LINE_COUNT; ++i)
00287                 {
00288                         text.append(lines[i]);
00289                 }
00290                 LLChannelDescriptors ch = mBuffer.nextChannel();
00291                 mBuffer.append(ch.in(), (U8*)text.c_str(), text.length());
00292                 const S32 BUFFER_LEN = 1024;
00293                 char buf[BUFFER_LEN];
00294                 S32 len;
00295                 U8* last = NULL;
00296                 std::string last_line;
00297                 for(i = 0; i < LINE_COUNT; ++i)
00298                 {
00299                         len = BUFFER_LEN;
00300                         last = mBuffer.readAfter(ch.in(), last, (U8*)buf, len);
00301                         char* newline = strchr((char*)buf, '\n');
00302                         S32 offset = -((len - 1) - (newline - buf));
00303                         ++newline;
00304                         *newline = '\0';
00305                         last_line.assign(buf);
00306                         std::ostringstream message;
00307                         message << "line reads in line["         << i << "]";
00308                         ensure_equals(message.str().c_str(), last_line, lines[i]);
00309                         last = mBuffer.seek(ch.in(), last, offset);
00310                 }
00311         }
00312 
00313         template<> template<>
00314         void buffer_object::test<8>()
00315         {
00316                 LLChannelDescriptors ch = mBuffer.nextChannel();
00317                 mBuffer.append(ch.in(), (U8*)"1", 1);
00318                 LLBufferArray buffer;
00319                 buffer.append(ch.in(), (U8*)"2", 1);
00320                 mBuffer.takeContents(buffer);
00321                 mBuffer.append(ch.in(), (U8*)"3", 1);
00322                 S32 count = mBuffer.countAfter(ch.in(), NULL);
00323                 ensure_equals("buffer size", count, 3);
00324                 U8* temp = new U8[count];
00325                 mBuffer.readAfter(ch.in(), NULL, temp, count);
00326                 ensure("buffer content", (0 == memcmp(temp, (void*)"123", 3)));
00327                 delete[] temp;
00328         }
00329 
00330         template<> template<>
00331         void buffer_object::test<9>()
00332         {
00333                 LLChannelDescriptors ch = mBuffer.nextChannel();
00334                 mBuffer.append(ch.in(), (U8*)"1", 1);
00335                 S32 capacity = mBuffer.capacity();
00336                 ensure("has capacity", capacity > 0);
00337                 U8* temp = new U8[capacity - 1];
00338                 mBuffer.append(ch.in(), temp, capacity - 1);
00339                 capacity = mBuffer.capacity();
00340                 ensure("has capacity when full", capacity > 0);
00341                 S32 used = mBuffer.countAfter(ch.in(), NULL);
00342                 ensure_equals("used equals capacity", used, capacity);
00343 
00344                 LLBufferArray::segment_iterator_t iter = mBuffer.beginSegment();
00345                 while(iter != mBuffer.endSegment())
00346                 {
00347                         mBuffer.eraseSegment(iter++);
00348                 }
00349 
00350                 used = mBuffer.countAfter(ch.in(), NULL);
00351                 ensure_equals("used is zero", used, 0);
00352                 S32 capacity2 = mBuffer.capacity();
00353                 ensure_equals("capacity the same after erase", capacity2, capacity);
00354                 mBuffer.append(ch.in(), temp, capacity - 1);
00355                 capacity2 = mBuffer.capacity();
00356                 ensure_equals("capacity the same after append", capacity2, capacity);
00357 
00358                 delete[] temp;
00359         }
00360 
00361 #if 0
00362         template<> template<>
00363         void buffer_object::test<9>()
00364         {
00365                 char buffer[1024];      /* Flawfinder: ignore */
00366                 S32 size = sprintf(buffer,
00367                                                 "%d|%d|%s|%s|%s|%s|%s|%x|%x|%x|%x|%x|%s|%s|%d|%d|%x",
00368                                                 7,
00369                                                 7,
00370                                                 "Hang Glider INFO",
00371                                                 "18e84d1e-04a4-4c0d-8cb6-6c73477f0a9a",
00372                                                 "0e346d8b-4433-4d66-a6b0-fd37083abc4c",
00373                                                 "0e346d8b-4433-4d66-a6b0-fd37083abc4c",
00374                                                 "00000000-0000-0000-0000-000000000000",
00375                                                 0x7fffffff,
00376                                                 0x7fffffff,
00377                                                 0,
00378                                                 0,
00379                                                 0x7fffffff,
00380                                                 "69e0d357-2e7c-8990-a2bc-7f61c868e5a3",
00381                                                 "2004-06-04 16:09:17 note card",
00382                                                 0,
00383                                                 10,
00384                                                 0) + 1;
00385 
00386                 //const char* expected = "7|7|Hang Glider INFO|18e84d1e-04a4-4c0d-8cb6-6c73477f0a9a|0e346d8b-4433-4d66-a6b0-fd37083abc4c|0e346d8b-4433-4d66-a6b0-fd37083abc4c|00000000-0000-0000-0000-000000000000|7fffffff|7fffffff|0|0|7fffffff|69e0d357-2e7c-8990-a2bc-7f61c868e5a3|2004-06-04 16:09:17 note card|0|10|0\0";
00387                 
00388                 LLSD* bin_bucket = LLIMInfo::buildSDfrombuffer((U8*)buffer,size);
00389 
00390                 char post_buffer[1024];
00391                 U32 post_size;
00392                 LLIMInfo::getBinaryBucket(bin_bucket,(U8*)post_buffer,post_size);
00393                 ensure_equals("Buffer sizes",size,(S32)post_size);
00394                 ensure("Buffer content",!strcmp(buffer,post_buffer));
00395         }
00396 #endif
00397 
00398         /*
00399         template<> template<>
00400         void buffer_object::test<>()
00401         {
00402         }
00403         */
00404 }
00405 
00406 namespace tut
00407 {
00408         struct buffer_and_stream_data
00409         {
00410                 LLBufferArray mBuffer;
00411         };
00412         typedef test_group<buffer_and_stream_data> bas_test;
00413         typedef bas_test::object bas_object;
00414         tut::bas_test tbs("buffer_stream");
00415 
00416         template<> template<>
00417         void bas_object::test<1>()
00418         {
00419                 const char HELLO_WORLD[] = "hello world";
00420                 const S32 str_len = strlen(HELLO_WORLD);        /* Flawfinder: ignore */
00421                 LLChannelDescriptors ch = mBuffer.nextChannel();
00422                 LLBufferStream str(ch, &mBuffer);
00423                 mBuffer.append(ch.in(), (U8*)HELLO_WORLD, str_len);
00424                 std::string hello;
00425                 std::string world;
00426                 str >> hello >> world;
00427                 ensure_equals("first word", hello, std::string("hello"));
00428                 ensure_equals("second word", world, std::string("world"));
00429         }
00430 
00431         template<> template<>
00432         void bas_object::test<2>()
00433         {
00434                 std::string part1("Eat my shor");
00435                 std::string part2("ts ho");
00436                 std::string part3("mer");
00437                 std::string ignore("ignore me");
00438                 LLChannelDescriptors ch = mBuffer.nextChannel();
00439                 LLBufferStream str(ch, &mBuffer);
00440                 mBuffer.append(ch.in(), (U8*)part1.c_str(), part1.length());
00441                 mBuffer.append(ch.in(), (U8*)part2.c_str(), part2.length());
00442                 mBuffer.append(ch.out(), (U8*)ignore.c_str(), ignore.length());
00443                 mBuffer.append(ch.in(), (U8*)part3.c_str(), part3.length());
00444                 std::string eat;
00445                 std::string my;
00446                 std::string shorts;
00447                 std::string homer;
00448                 str >> eat >> my >> shorts >> homer;
00449                 ensure_equals("word1", eat, std::string("Eat"));
00450                 ensure_equals("word2", my, std::string("my"));
00451                 ensure_equals("word3", shorts, std::string("shorts"));
00452                 ensure_equals("word4", homer, std::string("homer"));
00453         }
00454 
00455         template<> template<>
00456         void bas_object::test<3>()
00457         {
00458                 std::string part1("junk in ");
00459                 std::string part2("the trunk");
00460                 const S32 CHANNEL = 0;
00461                 mBuffer.append(CHANNEL, (U8*)part1.c_str(), part1.length());
00462                 mBuffer.append(CHANNEL, (U8*)part2.c_str(), part2.length());
00463                 U8* last = 0;
00464                 const S32 BUF_LEN = 128;
00465                 char buf[BUF_LEN];
00466                 S32 len = 11;
00467                 last = mBuffer.readAfter(CHANNEL, last, (U8*)buf, len);
00468                 buf[len] = '\0';
00469                 std::string actual(buf);
00470                 ensure_equals("first read", actual, std::string("junk in the"));
00471                 last = mBuffer.seek(CHANNEL, last, -6);
00472                 len = 12;
00473                 last = mBuffer.readAfter(CHANNEL, last, (U8*)buf, len);
00474                 buf[len] = '\0';
00475                 actual.assign(buf);
00476                 ensure_equals("seek and read", actual, std::string("in the trunk"));
00477         }
00478 
00479         template<> template<>
00480         void bas_object::test<4>()
00481         {
00482                 std::string phrase("zippity do da!");
00483                 const S32 CHANNEL = 0;
00484                 mBuffer.append(CHANNEL, (U8*)phrase.c_str(), phrase.length());
00485                 const S32 BUF_LEN = 128;
00486                 char buf[BUF_LEN];
00487                 S32 len = 7;
00488                 U8* last = mBuffer.readAfter(CHANNEL, NULL, (U8*)buf, len);
00489                 mBuffer.splitAfter(last);
00490                 LLBufferArray::segment_iterator_t it = mBuffer.beginSegment();
00491                 LLBufferArray::segment_iterator_t end = mBuffer.endSegment();
00492                 std::string first((char*)((*it).data()), (*it).size());
00493                 ensure_equals("first part", first, std::string("zippity"));
00494                 ++it;
00495                 std::string second((char*)((*it).data()), (*it).size());
00496                 ensure_equals("second part",    second, std::string(" do da!"));
00497                 ++it;
00498                 ensure("iterators equal",        (it == end));
00499         }
00500 
00501         template<> template<>
00502         void bas_object::test<5>()
00503         {
00504                 LLChannelDescriptors ch = mBuffer.nextChannel();
00505                 LLBufferStream str(ch, &mBuffer);
00506                 std::string h1("hello");
00507                 std::string h2(", how are you doing?");
00508                 std::string expected(h1);
00509                 expected.append(h2);
00510                 str << h1 << h2;
00511                 str.flush();
00512                 const S32 BUF_LEN = 128;
00513                 char buf[BUF_LEN];
00514                 S32 actual_len = BUF_LEN;
00515                 S32 expected_len = h1.size() + h2.size();
00516                 (void) mBuffer.readAfter(ch.out(), NULL, (U8*)buf, actual_len);
00517                 ensure_equals("streamed size", actual_len, expected_len);
00518                 buf[actual_len] = '\0';
00519                 std::string actual(buf);
00520                 ensure_equals("streamed to buf", actual, expected);
00521         }
00522 
00523         template<> template<>
00524         void bas_object::test<6>()
00525         {
00526                 LLChannelDescriptors ch = mBuffer.nextChannel();
00527                 LLBufferStream bstr(ch, &mBuffer);
00528                 std::ostringstream ostr;
00529                 std::vector<LLUUID> ids;
00530                 LLUUID id;
00531                 for(int i = 0; i < 5; ++i)
00532                 {
00533                         id.generate();
00534                         ids.push_back(id);
00535                 }
00536                 bstr << "SELECT concat(u.username, ' ', l.name) "
00537                          << "FROM user u, user_last_name l "
00538                          << "WHERE u.last_name_id = l.last_name_id"
00539                          << " AND u.agent_id IN ('";
00540                 ostr << "SELECT concat(u.username, ' ', l.name) "
00541                          << "FROM user u, user_last_name l "
00542                          << "WHERE u.last_name_id = l.last_name_id"
00543                          << " AND u.agent_id IN ('";
00544                 std::copy(
00545                         ids.begin(),
00546                         ids.end(),
00547                         std::ostream_iterator<LLUUID>(bstr, "','"));
00548                 std::copy(
00549                         ids.begin(),
00550                         ids.end(),
00551                         std::ostream_iterator<LLUUID>(ostr, "','"));
00552                 bstr.seekp(-2, std::ios::cur);
00553                 ostr.seekp(-2, std::ios::cur);
00554                 bstr << ") ";
00555                 ostr << ") ";
00556                 bstr.flush();
00557                 const S32 BUF_LEN = 512;
00558                 char buf[BUF_LEN];              /* Flawfinder: ignore */
00559                 S32 actual_len = BUF_LEN;
00560                 (void) mBuffer.readAfter(ch.out(), NULL, (U8*)buf, actual_len);
00561                 buf[actual_len] = '\0';
00562                 std::string actual(buf);
00563                 std::string expected(ostr.str());
00564                 ensure_equals("size of string in seek",actual.size(),expected.size());
00565                 ensure_equals("seek in ostream", actual, expected);
00566         }
00567 
00568         template<> template<>
00569         void bas_object::test<7>()
00570         {
00571                 LLChannelDescriptors ch = mBuffer.nextChannel();
00572                 LLBufferStream bstr(ch, &mBuffer);
00573                 bstr << "1";
00574                 bstr.flush();
00575                 S32 count = mBuffer.countAfter(ch.out(), NULL);
00576                 ensure_equals("buffer size 1", count, 1);
00577                 LLBufferArray buffer;
00578                 buffer.append(ch.out(), (U8*)"2", 1);
00579                 mBuffer.takeContents(buffer);
00580                 count = mBuffer.countAfter(ch.out(), NULL);
00581                 ensure_equals("buffer size 2", count, 2);
00582                 bstr << "3";
00583                 bstr.flush();
00584                 count = mBuffer.countAfter(ch.out(), NULL);
00585                 ensure_equals("buffer size 3", count, 3);
00586                 U8* temp = new U8[count];
00587                 mBuffer.readAfter(ch.out(), NULL, temp, count);
00588                 ensure("buffer content", (0 == memcmp(temp, (void*)"123", 3)));
00589                 delete[] temp;
00590         }
00591 
00592         template<> template<>
00593         void bas_object::test<8>()
00594         {
00595                 LLChannelDescriptors ch = mBuffer.nextChannel();
00596                 LLBufferStream ostr(ch, &mBuffer);
00597                 typedef std::vector<U8> buf_t;
00598                 typedef std::vector<buf_t> actual_t;
00599                 actual_t actual;
00600                 buf_t source;
00601                 bool need_comma = false;
00602                 ostr << "[";
00603                 S32 total_size = 1;
00604                 for(S32 i = 2000; i < 2003; ++i)
00605                 {
00606                         if(need_comma)
00607                         {
00608                                 ostr << ",";
00609                                 ++total_size;
00610                         }
00611                         need_comma = true;
00612                         srand(69 + i);  /* Flawfinder: ignore */
00613                         S32 size = rand() % 1000 + 1000;
00614                         std::generate_n(
00615                                 std::back_insert_iterator<buf_t>(source),
00616                                 size,
00617                                 rand);
00618                         actual.push_back(source);
00619                         ostr << "b(" << size << ")\"";
00620                         total_size += 8;
00621                         ostr.write((const char*)(&source[0]), size);
00622                         total_size += size;
00623                         source.clear();
00624                         ostr << "\"";
00625                         ++total_size;
00626                 }
00627                 ostr << "]";
00628                 ++total_size;
00629                 ostr.flush();
00630 
00631                 // now that we have a bunch of data on a stream, parse it all.
00632                 ch = mBuffer.nextChannel();
00633                 S32 count = mBuffer.countAfter(ch.in(), NULL);
00634                 ensure_equals("size of buffer", count, total_size);
00635                 LLBufferStream istr(ch, &mBuffer);
00636                 LLSD data;
00637                 count = LLSDSerialize::fromNotation(data, istr, total_size);
00638                 ensure("sd parsed", data.isDefined());
00639 
00640                 for(S32 j = 0; j < 3; ++j)
00641                 {
00642                         std::ostringstream name;
00643                         LLSD child(data[j]);
00644                         name << "found buffer " << j;
00645                         ensure(name.str(), child.isDefined());
00646                         source = child.asBinary();
00647                         name.str("");
00648                         name << "buffer " << j << " size";
00649                         ensure_equals(name.str().c_str(), source.size(), actual[j].size());
00650                         name.str("");
00651                         name << "buffer " << j << " contents";
00652                         ensure(
00653                                 name.str(),
00654                                 (0 == memcmp(&source[0], &actual[j][0], source.size())));
00655                 }
00656         }
00657 
00658         template<> template<>
00659         void bas_object::test<9>()
00660         {
00661                 LLChannelDescriptors ch = mBuffer.nextChannel();
00662                 LLBufferStream ostr(ch, &mBuffer);
00663                 typedef std::vector<U8> buf_t;
00664                 buf_t source;
00665                 bool need_comma = false;
00666                 ostr << "{";
00667                 S32 total_size = 1;
00668                 for(S32 i = 1000; i < 3000; ++i)
00669                 {
00670                         if(need_comma)
00671                         {
00672                                 ostr << ",";
00673                                 ++total_size;
00674                         }
00675                         need_comma = true;
00676                         ostr << "'" << i << "':";
00677                         total_size += 7;
00678                         srand(69 + i);          /* Flawfinder: ignore */
00679                         S32 size = rand() % 1000 + 1000;
00680                         std::generate_n(
00681                                 std::back_insert_iterator<buf_t>(source),
00682                                 size,
00683                                 rand);
00684                         ostr << "b(" << size << ")\"";
00685                         total_size += 8;
00686                         ostr.write((const char*)(&source[0]), size);
00687                         total_size += size;
00688                         source.clear();
00689                         ostr << "\"";
00690                         ++total_size;
00691                 }
00692                 ostr << "}";
00693                 ++total_size;
00694                 ostr.flush();
00695 
00696                 // now that we have a bunch of data on a stream, parse it all.
00697                 ch = mBuffer.nextChannel();
00698                 S32 count = mBuffer.countAfter(ch.in(), NULL);
00699                 ensure_equals("size of buffer", count, total_size);
00700                 LLBufferStream istr(ch, &mBuffer);
00701                 LLSD data;
00702                 count = LLSDSerialize::fromNotation(data, istr, total_size);
00703                 ensure("sd parsed", data.isDefined());
00704         }
00705 
00706         template<> template<>
00707         void bas_object::test<10>()
00708         {
00709                 const char LOGIN_STREAM[] = "{'method':'login', 'parameter': [ {"
00710                                                                                 "'uri': 'sl-am:kellys.region.siva.lindenlab.com/location?start=url&px=128&py=128&pz=128&lx=0&ly=0&lz=0'}, "
00711                                                                                 "{'version': i1}, {'texture_data': [ '61d724fb-ad79-f637-2186-5cf457560daa', '6e38b9be-b7cc-e77a-8aec-029a42b0b416', "
00712                                                                                 "'a9073524-e89b-2924-ca6e-a81944109a1a', '658f18b5-5f1e-e593-f5d5-36c3abc7249a', '0cc799f4-8c99-6b91-bd75-b179b12429e2', "
00713                                                                                 "'59fd9b64-8300-a425-aad8-2ffcbe9a49d2', '59fd9b64-8300-a425-aad8-2ffcbe9a49d2', '5748decc-f629-461c-9a36-a35a221fe21f', "
00714                                                                                 "'b8fc9be2-26a6-6b47-690b-0e902e983484', 'a13ca0fe-3802-dc97-e79a-70d12171c724', 'dd9643cf-fd5d-0376-ed4a-b1cc646a97d5', "
00715                                                                                 "'4ad13ae9-a112-af09-210a-cf9353a7a9e7', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', "
00716                                                                                 "'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', "
00717                                                                                 "'5748decc-f629-461c-9a36-a35a221fe21f', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97'],"
00718                                                                                 "'session_id': '324cfa9f-fe5d-4d1c-a317-35f20a86a4d1','position': [ i128, i128, i128],'last_name': 'Linden','group_title': '-> !BLING! <-','group_name': 'test!','agent_access': 'M',"
00719                                                                                 "'attachment_data': [ {'asset_id': 'aaede2b1-9955-09d4-5c93-2b557c778cf3','attachment_point': i6,'item_id': 'f3694abc-5122-db33-73d9-e0f4288dc2bf'}],"
00720                                                                                 "'buddy_ids': [ '101358d5-469d-4b24-9b85-4dc3c05e635d', '1b00fec7-6265-4875-acac-80d9cfe9295c', '203ad6df-b522-491d-ba48-4e24eb57aeff', "
00721                                                                                 "'22d4dcdb-aebb-47fa-b925-a871cc75ee48','27da3df5-1339-4463-80aa-40504ee3b3e5', '299d1720-b61f-4268-8c29-9614aa2d44c2', "
00722                                                                                 "'2b048a24-2737-4994-9fa5-becc8e466253', '2cd5dc14-a853-49a4-be3c-a5a7178e37bc', '3de548e1-57be-cfea-2b78-83ae3ad95998', "
00723                                                                                 "'3dee98e4-a6a3-4543-91c3-bbd528447ba7', '3e2d81a3-6263-6ffe-ad5c-8ce04bee07e9', '40e70b98-fed7-47f3-9700-1bce93f9350b', "
00724                                                                                 "'50a9b68e-b5aa-4d35-9137-3cfebda0a15c', '54295571-9357-43ff-ae74-a83b5138160f', '6191e2d7-5f96-4856-bdab-af0f79f47ae4', "
00725                                                                                 "'63e577d8-cd34-4235-a0a3-de0500133364', '79cfb666-4fd0-4af7-95df-fb7d96b4e24d', '8121c2f3-4a88-4c33-9899-8fc1273f47ee', "
00726                                                                                 "'909da964-ef23-4f2a-ba13-f2a8cfd454b6','a2e76fcd-9360-4f6d-a924-000000000001', 'aaa6d664-527e-4d83-9cbb-7ef79ccc7cc8', "
00727                                                                                 "'b79bfb6c-23be-49eb-b35b-30ff2f501b37', 'ba0d9c79-148c-4a79-8e3c-0665eebe2427', 'bc9bda98-57cd-498f-b993-4ff1ac9dec93', "
00728                                                                                 "'c62d16f6-81cb-419d-9cac-e46dc394084d', 'd48f8fa7-2512-4fe5-80c8-c0a923412e07', 'd77e3e24-7e6c-4c3f-96d0-a1746337f8fb', "
00729                                                                                 "'da615c63-a84b-4592-a3d6-a90dd3e92e6e', 'df47190a-7eb7-4aff-985f-2d1d3ad6c6e9', 'e3380196-72cd-499c-a2ba-caa180bd5fe4', "
00730                                                                                 "'e937863f-f134-4207-803b-d6e686651d6c', 'efcdf98b-5269-45ef-ac7a-0671f09ea9d9'],"
00731                                                                                 "'circuit_code': i124,'group_id': '8615c885-9cf0-bf0a-6e40-0c11462aa652','limited_to_estate': i1,'look_at': [ i0, i0, i0],"
00732                                                                                 "'agent_id': '0e346d8b-4433-4d66-a6b0-fd37083abc4c','first_name': 'Kelly','start': 'url'}]}";
00733                 LLChannelDescriptors ch = mBuffer.nextChannel();
00734                 mBuffer.append(ch.out(), (U8*)LOGIN_STREAM, strlen(LOGIN_STREAM));              /* Flawfinder: ignore */
00735                 ch = mBuffer.nextChannel();
00736                 LLBufferStream istr(ch, &mBuffer);
00737                 LLSD data;
00738                 S32 count = LLSDSerialize::fromNotation(
00739                         data,
00740                         istr,
00741                         mBuffer.count(ch.in()));
00742                 ensure("parsed something", (count > 0));
00743                 ensure("sd parsed", data.isDefined());
00744                 ensure_equals("sd type", data.type(), LLSD::TypeMap);
00745                 ensure("has method", data.has("method"));
00746                 ensure("has parameter", data.has("parameter"));
00747                 LLSD parameter = data["parameter"];
00748                 ensure_equals("parameter is array", parameter.type(), LLSD::TypeArray);
00749                 LLSD agent_params = parameter[2];
00750                 std::string s_value;
00751                 s_value = agent_params["last_name"].asString();
00752                 ensure_equals("last name", s_value, std::string("Linden"));
00753                 s_value = agent_params["first_name"].asString();
00754                 ensure_equals("first name", s_value, std::string("Kelly"));
00755                 s_value = agent_params["agent_access"].asString();
00756                 ensure_equals("agent access", s_value, std::string("M"));
00757                 s_value = agent_params["group_name"].asString();
00758                 ensure_equals("group name", s_value, std::string("test!"));
00759                 s_value = agent_params["group_title"].asString();
00760                 ensure_equals("group title", s_value, std::string("-> !BLING! <-"));
00761 
00762                 LLUUID agent_id("0e346d8b-4433-4d66-a6b0-fd37083abc4c");
00763                 LLUUID id = agent_params["agent_id"];
00764                 ensure_equals("agent id", id, agent_id);
00765                 LLUUID session_id("324cfa9f-fe5d-4d1c-a317-35f20a86a4d1");
00766                 id = agent_params["session_id"];
00767                 ensure_equals("session id", id, session_id);
00768                 LLUUID group_id ("8615c885-9cf0-bf0a-6e40-0c11462aa652");
00769                 id = agent_params["group_id"];
00770                 ensure_equals("group id", id, group_id);
00771 
00772                 S32 i_val = agent_params["limited_to_estate"];
00773                 ensure_equals("limited to estate", i_val, 1);
00774                 i_val = agent_params["circuit_code"];
00775                 ensure_equals("circuit code", i_val, 124);
00776         }
00777 
00778 
00779         template<> template<>
00780         void bas_object::test<11>()
00781         {
00782                 std::string val = "{!'foo'@:#'bar'}";
00783                 std::istringstream istr;
00784                 istr.str(val);
00785                 LLSD sd;
00786                 S32 count = LLSDSerialize::fromNotation(sd, istr, val.size());
00787                 ensure_equals("parser error return value", count, -1);
00788                 ensure("data undefined", sd.isUndefined());
00789         }
00790 
00791         template<> template<>
00792         void bas_object::test<12>()
00793         {
00794                 std::string val = "{!'foo':[i1,'hi',{@'bar'#:[$i2%,^'baz'&]*}+]=}";
00795                 std::istringstream istr;
00796                 istr.str(val);
00797                 LLSD sd;
00798                 S32 count = LLSDSerialize::fromNotation(sd, istr, val.size());
00799                 ensure_equals("parser error return value", count, -1);
00800                 ensure("data undefined", sd.isUndefined());
00801         }
00802 
00803 /*
00804         template<> template<>
00805         void bas_object::test<13>()
00806         {
00807         }
00808         template<> template<>
00809         void bas_object::test<14>()
00810         {
00811         }
00812         template<> template<>
00813         void bas_object::test<15>()
00814         {
00815         }
00816 */
00817 }
00818 
00819 
00820 namespace tut
00821 {
00822         class PumpAndChainTestData
00823         {
00824         protected:
00825                 apr_pool_t* mPool;
00826                 LLPumpIO* mPump;
00827                 LLPumpIO::chain_t mChain;
00828                 
00829         public:
00830                 PumpAndChainTestData()
00831                 {
00832                         apr_pool_create(&mPool, NULL);
00833                         mPump = new LLPumpIO(mPool);
00834                 }
00835                 
00836                 ~PumpAndChainTestData()
00837                 {
00838                         mChain.clear();
00839                         delete mPump;
00840                         apr_pool_destroy(mPool);
00841                 }
00842         };
00843         typedef test_group<PumpAndChainTestData>        PumpAndChainTestGroup;
00844         typedef PumpAndChainTestGroup::object           PumpAndChainTestObject;
00845         PumpAndChainTestGroup pumpAndChainTestGroup("pump_and_chain");
00846 
00847         template<> template<>
00848         void PumpAndChainTestObject::test<1>()
00849         {
00850                 LLPipeStringExtractor* extractor = new LLPipeStringExtractor();
00851 
00852                 mChain.push_back(LLIOPipe::ptr_t(new LLIOFlush));
00853                 mChain.push_back(LLIOPipe::ptr_t(extractor));
00854 
00855                 LLTimer timer;
00856                 timer.setTimerExpirySec(100.0f);
00857 
00858                 mPump->addChain(mChain, DEFAULT_CHAIN_EXPIRY_SECS);
00859                 while(!extractor->done() && !timer.hasExpired())
00860                 {
00861                         mPump->pump();
00862                         mPump->callback();
00863                 }
00864                 
00865                 ensure("reading string finished", extractor->done());
00866                 ensure_equals("string was empty", extractor->string(), "");
00867         }
00868 }
00869 
00870 /*
00871 namespace tut
00872 {
00873         struct double_construct
00874         {
00875         public:
00876                 double_construct()
00877                 {
00878                         llinfos << "constructed" << llendl;
00879                 }
00880                 ~double_construct()
00881                 {
00882                         llinfos << "destroyed" << llendl;
00883                 }
00884         };
00885         typedef test_group<double_construct> double_construct_test_group;
00886         typedef double_construct_test_group::object dc_test_object;
00887         double_construct_test_group dctest("double construct");
00888         template<> template<>
00889         void dc_test_object::test<1>()
00890         {
00891                 ensure("test 1", true);
00892         }
00893 }
00894 */
00895 
00896 namespace tut
00897 {
00901         struct pipe_and_pump_fitness
00902         {
00903         public:
00904                 enum
00905                 {
00906                         SERVER_LISTEN_PORT = 13050
00907                 };
00908                 
00909                 pipe_and_pump_fitness()
00910                 {
00911                         LLFrameTimer::updateFrameTime();                        
00912                         apr_pool_create(&mPool, NULL);
00913                         mPump = new LLPumpIO(mPool);
00914                         mSocket = LLSocket::create(
00915                                 mPool,
00916                                 LLSocket::STREAM_TCP,
00917                                 SERVER_LISTEN_PORT);
00918                 }
00919 
00920                 ~pipe_and_pump_fitness()
00921                 {
00922                         mSocket.reset();
00923                         delete mPump;
00924                         apr_pool_destroy(mPool);
00925                 }
00926 
00927         protected:
00928                 apr_pool_t* mPool;
00929                 LLPumpIO* mPump;
00930                 LLSocket::ptr_t mSocket;
00931         };
00932         typedef test_group<pipe_and_pump_fitness> fitness_test_group;
00933         typedef fitness_test_group::object fitness_test_object;
00934         fitness_test_group fitness("pipe and pump fitness");
00935 
00936         template<> template<>
00937         void fitness_test_object::test<1>()
00938         {
00939                 lldebugs << "fitness_test_object::test<1>()" << llendl;
00940 
00941                 // Set up the server
00942                 //lldebugs << "fitness_test_object::test<1> - setting up server."
00943                 //       << llendl;
00944                 LLPumpIO::chain_t chain;
00945                 typedef LLCloneIOFactory<LLPipeStringInjector> emitter_t;
00946                 emitter_t* emitter = new emitter_t(
00947                         new LLPipeStringInjector("suckers never play me"));
00948                 boost::shared_ptr<LLChainIOFactory> factory(emitter);
00949                 LLIOServerSocket* server = new LLIOServerSocket(
00950                         mPool,
00951                         mSocket,
00952                         factory);
00953                 server->setResponseTimeout(SHORT_CHAIN_EXPIRY_SECS);
00954                 chain.push_back(LLIOPipe::ptr_t(server));
00955                 mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS);
00956 
00957                 // We need to tickle the pump a little to set up the listen()
00958                 //lldebugs << "fitness_test_object::test<1> - initializing server."
00959                 //       << llendl;
00960                 pump_loop(mPump, 0.1f);
00961 
00962                 // Set up the client
00963                 //lldebugs << "fitness_test_object::test<1> - connecting client."
00964                 //       << llendl;
00965                 LLSocket::ptr_t client = LLSocket::create(mPool, LLSocket::STREAM_TCP);
00966                 LLHost server_host("127.0.0.1", SERVER_LISTEN_PORT);
00967                 bool connected = client->blockingConnect(server_host);
00968                 ensure("Connected to server", connected);
00969                 lldebugs << "connected" << llendl;
00970 
00971                 // We have connected, since the socket reader does not block,
00972                 // the first call to read data will return EAGAIN, so we need
00973                 // to write something.
00974                 chain.clear();
00975                 chain.push_back(LLIOPipe::ptr_t(new LLPipeStringInjector("hi")));
00976                 chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(client)));
00977                 chain.push_back(LLIOPipe::ptr_t(new LLIONull));
00978                 mPump->addChain(chain, 1.0f);
00979 
00980                 // Now, the server should immediately send the data, but we'll
00981                 // never read it. pump for a bit
00982                 F32 elapsed = pump_loop(mPump, 2.0f);
00983                 ensure("Did not take too long", (elapsed < 3.0f));
00984         }
00985 
00986         template<> template<>
00987         void fitness_test_object::test<2>()
00988         {
00989                 lldebugs << "fitness_test_object::test<2>()" << llendl;
00990 
00991                 // Set up the server
00992                 LLPumpIO::chain_t chain;
00993                 typedef LLCloneIOFactory<LLIOFuzz> emitter_t;
00994                 emitter_t* emitter = new emitter_t(new LLIOFuzz(1000000));
00995                 boost::shared_ptr<LLChainIOFactory> factory(emitter);
00996                 LLIOServerSocket* server = new LLIOServerSocket(
00997                         mPool,
00998                         mSocket,
00999                         factory);
01000                 server->setResponseTimeout(SHORT_CHAIN_EXPIRY_SECS);
01001                 chain.push_back(LLIOPipe::ptr_t(server));
01002                 mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS);
01003 
01004                 // We need to tickle the pump a little to set up the listen()
01005                 pump_loop(mPump, 0.1f);
01006 
01007                 // Set up the client
01008                 LLSocket::ptr_t client = LLSocket::create(mPool, LLSocket::STREAM_TCP);
01009                 LLHost server_host("127.0.0.1", SERVER_LISTEN_PORT);
01010                 bool connected = client->blockingConnect(server_host);
01011                 ensure("Connected to server", connected);
01012                 lldebugs << "connected" << llendl;
01013 
01014                 // We have connected, since the socket reader does not block,
01015                 // the first call to read data will return EAGAIN, so we need
01016                 // to write something.
01017                 chain.clear();
01018                 chain.push_back(LLIOPipe::ptr_t(new LLPipeStringInjector("hi")));
01019                 chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(client)));
01020                 chain.push_back(LLIOPipe::ptr_t(new LLIONull));
01021                 mPump->addChain(chain, SHORT_CHAIN_EXPIRY_SECS / 2.0f);
01022 
01023                 // Now, the server should immediately send the data, but we'll
01024                 // never read it. pump for a bit
01025                 F32 elapsed = pump_loop(mPump, SHORT_CHAIN_EXPIRY_SECS * 2.0f);
01026                 ensure("Did not take too long", (elapsed < 3.0f));
01027         }
01028 
01029         template<> template<>
01030         void fitness_test_object::test<3>()
01031         {
01032                 lldebugs << "fitness_test_object::test<3>()" << llendl;
01033 
01034                 // Set up the server
01035                 LLPumpIO::chain_t chain;
01036                 typedef LLCloneIOFactory<LLIOFuzz> emitter_t;
01037                 emitter_t* emitter = new emitter_t(new LLIOFuzz(1000000));
01038                 boost::shared_ptr<LLChainIOFactory> factory(emitter);
01039                 LLIOServerSocket* server = new LLIOServerSocket(
01040                         mPool,
01041                         mSocket,
01042                         factory);
01043                 server->setResponseTimeout(SHORT_CHAIN_EXPIRY_SECS);
01044                 chain.push_back(LLIOPipe::ptr_t(server));
01045                 mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS);
01046 
01047                 // We need to tickle the pump a little to set up the listen()
01048                 pump_loop(mPump, 0.1f);
01049 
01050                 // Set up the client
01051                 LLSocket::ptr_t client = LLSocket::create(mPool, LLSocket::STREAM_TCP);
01052                 LLHost server_host("127.0.0.1", SERVER_LISTEN_PORT);
01053                 bool connected = client->blockingConnect(server_host);
01054                 ensure("Connected to server", connected);
01055                 lldebugs << "connected" << llendl;
01056 
01057                 // We have connected, since the socket reader does not block,
01058                 // the first call to read data will return EAGAIN, so we need
01059                 // to write something.
01060                 chain.clear();
01061                 chain.push_back(LLIOPipe::ptr_t(new LLPipeStringInjector("hi")));
01062                 chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(client)));
01063                 chain.push_back(LLIOPipe::ptr_t(new LLIONull));
01064                 mPump->addChain(chain, SHORT_CHAIN_EXPIRY_SECS * 2.0f);
01065 
01066                 // Now, the server should immediately send the data, but we'll
01067                 // never read it. pump for a bit
01068                 F32 elapsed = pump_loop(mPump, SHORT_CHAIN_EXPIRY_SECS * 2.0f + 1.0f);
01069                 ensure("Did not take too long", (elapsed < 4.0f));
01070         }
01071 
01072         template<> template<>
01073         void fitness_test_object::test<4>()
01074         {
01075                 lldebugs << "fitness_test_object::test<4>()" << llendl;
01076 
01077                 // Set up the server
01078                 LLPumpIO::chain_t chain;
01079                 typedef LLCloneIOFactory<LLIOFuzz> emitter_t;
01080                 emitter_t* emitter = new emitter_t(new LLIOFuzz(1000000));
01081                 boost::shared_ptr<LLChainIOFactory> factory(emitter);
01082                 LLIOServerSocket* server = new LLIOServerSocket(
01083                         mPool,
01084                         mSocket,
01085                         factory);
01086                 server->setResponseTimeout(SHORT_CHAIN_EXPIRY_SECS + 1.80f);
01087                 chain.push_back(LLIOPipe::ptr_t(server));
01088                 mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS);
01089 
01090                 // We need to tickle the pump a little to set up the listen()
01091                 pump_loop(mPump, 0.1f);
01092 
01093                 // Set up the client
01094                 LLSocket::ptr_t client = LLSocket::create(mPool, LLSocket::STREAM_TCP);
01095                 LLHost server_host("127.0.0.1", SERVER_LISTEN_PORT);
01096                 bool connected = client->blockingConnect(server_host);
01097                 ensure("Connected to server", connected);
01098                 lldebugs << "connected" << llendl;
01099 
01100                 // We have connected, since the socket reader does not block,
01101                 // the first call to read data will return EAGAIN, so we need
01102                 // to write something.
01103                 chain.clear();
01104                 chain.push_back(LLIOPipe::ptr_t(new LLPipeStringInjector("hi")));
01105                 chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(client)));
01106                 chain.push_back(LLIOPipe::ptr_t(new LLIONull));
01107                 mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS);
01108 
01109                 // Now, the server should immediately send the data, but we'll
01110                 // never read it. pump for a bit
01111                 F32 elapsed = pump_loop(mPump, SHORT_CHAIN_EXPIRY_SECS + 3.0f);
01112                 ensure("Did not take too long", (elapsed < DEFAULT_CHAIN_EXPIRY_SECS));
01113         }
01114 
01115         template<> template<>
01116         void fitness_test_object::test<5>()
01117         {
01118                 // Set up the server
01119                 LLPumpIO::chain_t chain;
01120                 typedef LLCloneIOFactory<LLIOSleeper> sleeper_t;
01121                 sleeper_t* sleeper = new sleeper_t(new LLIOSleeper);
01122                 boost::shared_ptr<LLChainIOFactory> factory(sleeper);
01123                 LLIOServerSocket* server = new LLIOServerSocket(
01124                         mPool,
01125                         mSocket,
01126                         factory);
01127                 server->setResponseTimeout(1.0);
01128                 chain.push_back(LLIOPipe::ptr_t(server));
01129                 mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS);
01130                 // We need to tickle the pump a little to set up the listen()
01131                 pump_loop(mPump, 0.1f);
01132                 U32 count = mPump->runningChains();
01133                 ensure_equals("server chain onboard", count, 1);
01134                 lldebugs << "** Server is up." << llendl;
01135 
01136                 // Set up the client
01137                 LLSocket::ptr_t client = LLSocket::create(mPool, LLSocket::STREAM_TCP);
01138                 LLHost server_host("127.0.0.1", SERVER_LISTEN_PORT);
01139                 bool connected = client->blockingConnect(server_host);
01140                 ensure("Connected to server", connected);
01141                 lldebugs << "connected" << llendl;
01142                 F32 elapsed = pump_loop(mPump,0.1f);
01143                 count = mPump->runningChains();
01144                 ensure_equals("server chain onboard", count, 2);
01145                 lldebugs << "** Client is connected." << llendl;
01146 
01147                 // We have connected, since the socket reader does not block,
01148                 // the first call to read data will return EAGAIN, so we need
01149                 // to write something.
01150                 chain.clear();
01151                 chain.push_back(LLIOPipe::ptr_t(new LLPipeStringInjector("hi")));
01152                 chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(client)));
01153                 chain.push_back(LLIOPipe::ptr_t(new LLIONull));
01154                 mPump->addChain(chain, 0.2f);
01155                 chain.clear();
01156 
01157                 // pump for a bit and make sure all 3 chains are running
01158                 elapsed = pump_loop(mPump,0.1f);
01159                 count = mPump->runningChains();
01160                 ensure_equals("client chain onboard", count, 3);
01161                 lldebugs << "** request should have been sent." << llendl;
01162 
01163                 // pump for long enough the the client socket closes, and the
01164                 // server socket should not be closed yet.
01165                 elapsed = pump_loop(mPump,0.2f);
01166                 count = mPump->runningChains();
01167                 ensure_equals("client chain timed out ", count, 2);
01168                 lldebugs << "** client chain should be closed." << llendl;
01169 
01170                 // At this point, the socket should be closed by the timeout
01171                 elapsed = pump_loop(mPump,1.0f);
01172                 count = mPump->runningChains();
01173                 ensure_equals("accepted socked close", count, 1);
01174                 lldebugs << "** Sleeper should have timed out.." << llendl;
01175         }
01176 }
01177 
01178 namespace tut
01179 {
01180         struct rpc_server_data
01181         {
01182                 class LLSimpleRPCResponse : public LLSDRPCResponse
01183                 {
01184                 public:
01185                         LLSimpleRPCResponse(LLSD* response) :
01186                                 mResponsePtr(response)
01187                         {
01188                         }
01189                         ~LLSimpleRPCResponse() {}
01190                         virtual bool response(LLPumpIO* pump)
01191                         {
01192                                 *mResponsePtr = mReturnValue;
01193                                 return true;
01194                         }
01195                         virtual bool fault(LLPumpIO* pump)
01196                         {
01197                                 *mResponsePtr = mReturnValue;
01198                                 return false;
01199                         }
01200                         virtual bool error(LLPumpIO* pump)
01201                         {
01202                                 ensure("LLSimpleRPCResponse::error()", false);
01203                                 return false;
01204                         }
01205                 public:
01206                         LLSD* mResponsePtr;
01207                 };
01208 
01209                 class LLSimpleRPCClient : public LLSDRPCClient
01210                 {
01211                 public:
01212                         LLSimpleRPCClient(LLSD* response) :
01213                                 mResponsePtr(response)
01214                         {
01215                         }
01216                         ~LLSimpleRPCClient() {}
01217                         void echo(const LLSD& parameter)
01218                         {
01219                                 LLSimpleRPCResponse* resp;
01220                                 resp = new LLSimpleRPCResponse(mResponsePtr);
01221                                 static const std::string URI_NONE;
01222                                 static const std::string METHOD_ECHO("echo");
01223                                 call(URI_NONE, METHOD_ECHO, parameter, resp, EPBQ_CALLBACK);
01224                         }
01225                 public:
01226                         LLSD* mResponsePtr;
01227                 };
01228 
01229                 class LLSimpleRPCServer : public LLSDRPCServer
01230                 {
01231                 public:
01232                         LLSimpleRPCServer()
01233                         {
01234                                 mMethods["echo"] = new mem_fn_t(
01235                                         this,
01236                                         &LLSimpleRPCServer::rpc_Echo);
01237                         }
01238                         ~LLSimpleRPCServer() {}
01239                 protected:
01240                         typedef LLSDRPCMethodCall<LLSimpleRPCServer> mem_fn_t;
01241                         ESDRPCSStatus rpc_Echo(
01242                                 const LLSD& parameter,
01243                                 const LLChannelDescriptors& channels,
01244                                 LLBufferArray* data)
01245                         {
01246                                 buildResponse(channels, data, parameter);
01247                                 return ESDRPCS_DONE;
01248                         }
01249                 };
01250 
01251                 apr_pool_t* mPool;
01252                 LLPumpIO* mPump;
01253                 LLPumpIO::chain_t mChain;
01254                 LLSimpleRPCClient* mClient;
01255                 LLSD mResponse;
01256 
01257                 rpc_server_data() :
01258                         mPool(NULL),
01259                         mPump(NULL),
01260                         mClient(NULL)
01261                 {
01262                         apr_pool_create(&mPool, NULL);
01263                         mPump = new LLPumpIO(mPool);
01264                         mClient = new LLSimpleRPCClient(&mResponse);
01265                         mChain.push_back(LLIOPipe::ptr_t(mClient));
01266                         mChain.push_back(LLIOPipe::ptr_t(new LLFilterSD2XMLRPCRequest));
01267                         mChain.push_back(LLIOPipe::ptr_t(new LLFilterXMLRPCRequest2LLSD));
01268                         mChain.push_back(LLIOPipe::ptr_t(new LLSimpleRPCServer));
01269                         mChain.push_back(LLIOPipe::ptr_t(new LLFilterSD2XMLRPCResponse));
01270                         mChain.push_back(LLIOPipe::ptr_t(new LLFilterXMLRPCResponse2LLSD));
01271                         mChain.push_back(LLIOPipe::ptr_t(mClient));
01272                 }
01273                 ~rpc_server_data()
01274                 {
01275                         mChain.clear();
01276                         delete mPump;
01277                         mPump = NULL;
01278                         apr_pool_destroy(mPool);
01279                         mPool = NULL;
01280                 }
01281                 void pump_loop(const LLSD& request)
01282                 {
01283                         LLTimer timer;
01284                         timer.setTimerExpirySec(1.0f);
01285                         mClient->echo(request);
01286                         mPump->addChain(mChain, DEFAULT_CHAIN_EXPIRY_SECS);
01287                         while(mResponse.isUndefined() && !timer.hasExpired())
01288                         {
01289                                 mPump->pump();
01290                                 mPump->callback();
01291                         }
01292                 }
01293         };
01294         typedef test_group<rpc_server_data> rpc_server_test;
01295         typedef rpc_server_test::object rpc_server_object;
01296         tut::rpc_server_test rpc("rpc_server");
01297 
01298         template<> template<>
01299         void rpc_server_object::test<1>()
01300         {
01301                 LLSD request;
01302                 request = 1;
01303                 pump_loop(request);
01304                 //llinfos << "request: " << *request << llendl;
01305                 //llinfos << "response: " << *mResponse << llendl;
01306                 ensure_equals("integer request response", mResponse.asInteger(), 1);
01307         }
01308 
01309         template<> template<>
01310         void rpc_server_object::test<2>()
01311         {
01312                 std::string uri("sl-am:66.150.244.180:12035/location?start=region&px=70.9247&py=254.378&pz=38.7304&lx=-0.043753&ly=-0.999042&lz=0");
01313                 std::stringstream stream;
01314                 stream << "{'task_id':ucc706f2d-0b68-68f8-11a4-f1043ff35ca0}\n{\n\tname\tObject|\n\tpermissions 0\n}";
01315                 std::vector<U8> expected_binary;
01316                 expected_binary.resize(stream.str().size());
01317                 memcpy(&expected_binary[0], stream.str().c_str(), stream.str().size());         /* Flawfinder: ignore */
01318                 stream.str("");
01319                 stream << "[{'uri':'" << uri << "'}, {'version':i1}, "
01320                                   << "{'agent_id':'3c115e51-04f4-523c-9fa6-98aff1034730', 'session_id':'2c585cec-038c-40b0-b42e-a25ebab4d132', 'circuit_code':i1075, 'start':'region', 'limited_to_estate':i1 'first_name':'Phoenix', 'last_name':'Linden', 'group_title':'', 'group_id':u00000000-0000-0000-0000-000000000000, 'position':[r70.9247,r254.378,r38.7304], 'look_at':[r-0.043753,r-0.999042,r0], 'granters':[ua2e76fcd-9360-4f6d-a924-000000000003], 'texture_data':['5e481e8a-58a6-fc34-6e61-c7a36095c07f', 'c39675f5-ca90-a304-bb31-42cdb803a132', '5c989edf-88d1-b2ac-b00b-5ed4bab8e368', '6522e74d-1660-4e7f-b601-6f48c1659a77', '7ca39b4c-bd19-4699-aff7-f93fd03d3e7b', '41c58177-5eb6-5aeb-029d-bc4093f3c130', '97b75473-8b93-9b25-2a11-035b9ae93195', '1c2d8d9b-90eb-89d4-dea8-c1ed83990614', '69ec543f-e27b-c07c-9094-a8be6300f274', 'c9f8b80f-c629-4633-04ee-c566ce9fea4b', '989cddba-7ab6-01ed-67aa-74accd2a2a65', '45e319b2-6a8c-fa5c-895b-1a7149b88aef', '5748decc-f629-461c-9a36-a35a221fe21f', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', '685fbe10-ab40-f065-0aec-726cc6dfd7a1', '406f98fd-9c89-1d52-5f39-e67d508c5ee5', '685fbe10-ab40-f065-0aec-726cc6dfd7a1', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97'], "
01321                                   << "'attachment_data':["
01322                                   << "{'attachment_point':i2, 'item_id':'d6852c11-a74e-309a-0462-50533f1ef9b3', 'asset_id':'c69b29b1-8944-58ae-a7c5-2ca7b23e22fb'},"
01323                                   << "{'attachment_point':i10, 'item_id':'ff852c22-a74e-309a-0462-50533f1ef900', 'asset_data':b(" << expected_binary.size() << ")\"";
01324                 stream.write((const char*)&expected_binary[0], expected_binary.size());
01325                 stream << "\"}"
01326                                   << "]"
01327                                   << "}]";
01328 
01329                 LLSD request;
01330                 S32 count = LLSDSerialize::fromNotation(
01331                         request,
01332                         stream,
01333                         stream.str().size());
01334                 ensure("parsed something", (count > 0));
01335 
01336                 pump_loop(request);
01337                 ensure_equals("return type", mResponse.type(), LLSD::TypeArray);
01338                 ensure_equals("return size", mResponse.size(), 3);
01339 
01340                 ensure_equals(
01341                         "uri parameter type",
01342                         mResponse[0].type(),
01343                         LLSD::TypeMap);
01344                 ensure_equals(
01345                         "uri type",
01346                         mResponse[0]["uri"].type(),
01347                         LLSD::TypeString);
01348                 ensure_equals("uri value", mResponse[0]["uri"].asString(), uri);
01349 
01350                 ensure_equals(
01351                         "version parameter type",
01352                         mResponse[1].type(),
01353                         LLSD::TypeMap);
01354                 ensure_equals(
01355                         "version type",
01356                         mResponse[1]["version"].type(),
01357                         LLSD::TypeInteger);
01358                 ensure_equals(
01359                         "version value",
01360                         mResponse[1]["version"].asInteger(),
01361                         1);
01362 
01363                 ensure_equals("agent params type", mResponse[2].type(), LLSD::TypeMap);
01364                 LLSD attachment_data = mResponse[2]["attachment_data"];
01365                 ensure("attachment data exists", attachment_data.isDefined());
01366                 ensure_equals(
01367                         "attachment type",
01368                         attachment_data.type(),
01369                         LLSD::TypeArray);
01370                 ensure_equals(
01371                         "attachment type 0",
01372                         attachment_data[0].type(),
01373                         LLSD::TypeMap);
01374                 ensure_equals(
01375                         "attachment type 1",
01376                         attachment_data[1].type(),
01377                         LLSD::TypeMap);
01378                 ensure_equals("attachment size 1", attachment_data[1].size(), 3);
01379                 ensure_equals(
01380                         "asset data type",
01381                         attachment_data[1]["asset_data"].type(),
01382                         LLSD::TypeBinary);
01383                 std::vector<U8> actual_binary;
01384                 actual_binary = attachment_data[1]["asset_data"].asBinary();
01385                 ensure_equals(
01386                         "binary data size",
01387                         actual_binary.size(),
01388                         expected_binary.size());
01389                 ensure(
01390                         "binary data",
01391                         (0 == memcmp(
01392                                 &actual_binary[0],
01393                                 &expected_binary[0],
01394                                 expected_binary.size())));
01395         }
01396 
01397         template<> template<>
01398         void rpc_server_object::test<3>()
01399         {
01400                 std::string uri("sl-am:66.150.244.180:12035/location?start=region&px=70.9247&py=254.378&pz=38.7304&lx=-0.043753&ly=-0.999042&lz=0");
01401 
01402                 LLBufferArray buffer;
01403                 LLChannelDescriptors buffer_channels = buffer.nextChannel();
01404                 LLBufferStream stream(buffer_channels, &buffer);
01405                 stream << "[{'uri':'" << uri << "'}, {'version':i1}, "
01406                                   << "{'agent_id':'3c115e51-04f4-523c-9fa6-98aff1034730', 'session_id':'2c585cec-038c-40b0-b42e-a25ebab4d132', 'circuit_code':i1075, 'start':'region', 'limited_to_estate':i1 'first_name':'Phoenix', 'last_name':'Linden', 'group_title':'', 'group_id':u00000000-0000-0000-0000-000000000000, 'position':[r70.9247,r254.378,r38.7304], 'look_at':[r-0.043753,r-0.999042,r0], 'granters':[ua2e76fcd-9360-4f6d-a924-000000000003], 'texture_data':['5e481e8a-58a6-fc34-6e61-c7a36095c07f', 'c39675f5-ca90-a304-bb31-42cdb803a132', '5c989edf-88d1-b2ac-b00b-5ed4bab8e368', '6522e74d-1660-4e7f-b601-6f48c1659a77', '7ca39b4c-bd19-4699-aff7-f93fd03d3e7b', '41c58177-5eb6-5aeb-029d-bc4093f3c130', '97b75473-8b93-9b25-2a11-035b9ae93195', '1c2d8d9b-90eb-89d4-dea8-c1ed83990614', '69ec543f-e27b-c07c-9094-a8be6300f274', 'c9f8b80f-c629-4633-04ee-c566ce9fea4b', '989cddba-7ab6-01ed-67aa-74accd2a2a65', '45e319b2-6a8c-fa5c-895b-1a7149b88aef', '5748decc-f629-461c-9a36-a35a221fe21f', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', '685fbe10-ab40-f065-0aec-726cc6dfd7a1', '406f98fd-9c89-1d52-5f39-e67d508c5ee5', '685fbe10-ab40-f065-0aec-726cc6dfd7a1', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97'], "
01407                                   << "'attachment_data':["
01408                                   << "{'attachment_point':i2, 'item_id':'d6852c11-a74e-309a-0462-50533f1ef9b3', 'asset_id':'c69b29b1-8944-58ae-a7c5-2ca7b23e22fb'},";
01409 
01410                 std::stringstream tmp_str;
01411                 tmp_str << "{'task_id':ucc706f2d-0b68-68f8-11a4-f1043ff35ca0}\n{\n\tname\tObject|\n\tpermissions 0\n}";
01412                 std::vector<U8> expected_binary;
01413                 expected_binary.resize(tmp_str.str().size());
01414                 memcpy(         /* Flawfinder: ignore */
01415                         &expected_binary[0],
01416                         tmp_str.str().c_str(),
01417                         tmp_str.str().size());
01418 
01419                 LLBufferArray attachment_buffer;
01420                 LLChannelDescriptors attach_channels = attachment_buffer.nextChannel();
01421                 LLBufferStream attach_stream(attach_channels, &attachment_buffer);
01422                 attach_stream.write((const char*)&expected_binary[0], expected_binary.size());
01423                 attach_stream.flush();
01424                 S32 len = attachment_buffer.countAfter(attach_channels.out(), NULL);
01425                 stream << "{'attachment_point':i10, 'item_id':'ff852c22-a74e-309a-0462-50533f1ef900', 'asset_data':b(" << len << ")\"";
01426                 stream.flush();
01427                 buffer.takeContents(attachment_buffer);
01428                 stream << "\"}]}]";
01429                 stream.flush();
01430 
01431                 LLChannelDescriptors read_channel = buffer.nextChannel();
01432                 LLBufferStream read_stream(read_channel, &buffer);
01433                 LLSD request;
01434                 S32 count = LLSDSerialize::fromNotation(
01435                         request,
01436                         read_stream,
01437                         buffer.count(read_channel.in()));
01438                 ensure("parsed something", (count > 0));
01439                 ensure("deserialized", request.isDefined());
01440 
01441                 // do the rpc round trip
01442                 pump_loop(request);
01443 
01444                 ensure_equals("return type", mResponse.type(), LLSD::TypeArray);
01445                 ensure_equals("return size", mResponse.size(), 3);
01446 
01447                 LLSD child = mResponse[0];
01448                 ensure("uri map exists", child.isDefined());
01449                 ensure_equals("uri parameter type", child.type(), LLSD::TypeMap);
01450                 ensure("uri string exists", child.has("uri"));
01451                 ensure_equals("uri type", child["uri"].type(), LLSD::TypeString);
01452                 ensure_equals("uri value", child["uri"].asString(), uri);
01453 
01454                 child = mResponse[1];
01455                 ensure("version map exists",    child.isDefined());
01456                 ensure_equals("version param type", child.type(), LLSD::TypeMap);
01457                 ensure_equals(
01458                         "version type",
01459                         child["version"].type(),
01460                         LLSD::TypeInteger);
01461                 ensure_equals("version value", child["version"].asInteger(), 1);
01462 
01463                 child = mResponse[2];
01464                 ensure("agent params map exists", child.isDefined());
01465                 ensure_equals("agent params type", child.type(), LLSD::TypeMap);
01466                 child = child["attachment_data"];
01467                 ensure("attachment data exists", child.isDefined());
01468                 ensure_equals("attachment type", child.type(), LLSD::TypeArray);
01469                 LLSD attachment = child[0];
01470                 ensure_equals("attachment type 0", attachment.type(), LLSD::TypeMap);
01471                 attachment = child[1];
01472                 ensure_equals("attachment type 1", attachment.type(), LLSD::TypeMap);
01473                 ensure_equals("attachment size 1", attachment.size(), 3);
01474                 ensure_equals(
01475                         "asset data type",
01476                         attachment["asset_data"].type(),
01477                         LLSD::TypeBinary);
01478                 std::vector<U8> actual_binary = attachment["asset_data"].asBinary();
01479                 ensure_equals(
01480                         "binary data size",
01481                         actual_binary.size(),
01482                         expected_binary.size());
01483                 ensure(
01484                         "binary data",
01485                         (0 == memcmp(
01486                                 &actual_binary[0],
01487                                 &expected_binary[0],
01488                                 expected_binary.size())));
01489         }
01490 
01491         template<> template<>
01492         void rpc_server_object::test<4>()
01493         {
01494                 std::string message("parcel '' is naughty.");
01495                 std::stringstream str;
01496                 str << "{'message':'" << LLSDNotationFormatter::escapeString(message)
01497                         << "'}";
01498                 LLSD request;
01499                 S32 count = LLSDSerialize::fromNotation(
01500                         request,
01501                         str,
01502                         str.str().size());
01503                 ensure_equals("parse count", count, 2);
01504                 ensure_equals("request type", request.type(), LLSD::TypeMap);
01505                 pump_loop(request);
01506                 ensure("valid response", mResponse.isDefined());
01507                 ensure_equals("response type", mResponse.type(), LLSD::TypeMap);
01508                 std::string actual = mResponse["message"].asString();
01509                 ensure_equals("message contents", actual, message);
01510         }
01511 
01512         template<> template<>
01513         void rpc_server_object::test<5>()
01514         {
01515                 // test some of the problem cases with llsdrpc over xmlrpc -
01516                 // for example:
01517                 // * arrays are auto-converted to parameter lists, thus, this
01518                 // becomes one parameter.
01519                 // * undef goes over the wire as false (this might not be a good idea)
01520                 // * uuids are converted to string.
01521                 std::string val = "[{'failures':!,'successfuls':[u3c115e51-04f4-523c-9fa6-98aff1034730]}]";
01522                 std::istringstream istr;
01523                 istr.str(val);
01524                 LLSD sd;
01525                 LLSDSerialize::fromNotation(sd, istr, val.size());
01526                 pump_loop(sd);
01527                 ensure("valid response", mResponse.isDefined());
01528                 ensure_equals("parsed type", mResponse.type(), LLSD::TypeMap);
01529                 ensure_equals("parsed size", mResponse.size(), 2);
01530                 LLSD failures = mResponse["failures"];
01531                 ensure_equals("no failures.", failures.asBoolean(), false);
01532                 LLSD success = mResponse["successfuls"];
01533                 ensure_equals("success type", success.type(), LLSD::TypeArray);
01534                 ensure_equals("success size", success.size(), 1);
01535                 ensure_equals(
01536                         "success instance type",
01537                         success[0].type(),
01538                         LLSD::TypeString);
01539         }
01540 
01541 /*
01542         template<> template<>
01543         void rpc_server_object::test<5>()
01544         {
01545                 std::string expected("\xf3");//\xffsomething");
01546                 LLSD* request = LLSD::createString(expected);
01547                 pump_loop(request);
01548                 std::string actual;
01549                 mResponse->getString(actual);
01550                 if(actual != expected)
01551                 {
01552                         //llwarns << "iteration " << i << llendl;
01553                         std::ostringstream e_str;
01554                         std::string::iterator iter = expected.begin();
01555                         std::string::iterator end = expected.end();
01556                         for(; iter != end; ++iter)
01557                         {
01558                                 e_str << (S32)((U8)(*iter)) << " ";
01559                         }
01560                         e_str << std::endl;
01561                         llsd_serialize_string(e_str, expected);
01562                         llwarns << "expected size: " << expected.size() << llendl;
01563                         llwarns << "expected:     " << e_str.str() << llendl;
01564 
01565                         std::ostringstream a_str;
01566                         iter = actual.begin();
01567                         end = actual.end();
01568                         for(; iter != end; ++iter)
01569                         {
01570                                 a_str << (S32)((U8)(*iter)) << " ";
01571                         }
01572                         a_str << std::endl;
01573                         llsd_serialize_string(a_str, actual);
01574                         llwarns << "actual size:          " << actual.size() << llendl;
01575                         llwarns << "actual:             " << a_str.str() << llendl;
01576                 }
01577                 ensure_equals("binary string request response", actual, expected);
01578                 delete request;
01579         }
01580 
01581         template<> template<>
01582         void rpc_server_object::test<5>()
01583         {
01584         }
01585 */
01586 }
01587 
01588 
01589 /*
01590 'asset_data':b(12100)"{'task_id':ucc706f2d-0b68-68f8-11a4-f1043ff35ca0}\n{\n\tname\tObject|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffffff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreator_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444921\n\ttotal_crc\t323\n\ttype\t2\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.368634403\t0.00781063363\t-0.569040775\n\toldpos\t150.117996\t25.8658009\t8.19664001\n\trotation\t-0.06293071806430816650390625\t-0.6995697021484375\t-0.7002241611480712890625\t0.1277817934751510620117188\n\tchildpos\t-0.00499999989\t-0.0359999985\t0.307999998\n\tchildrot\t-0.515492737293243408203125\t-0.46601200103759765625\t0.529055416584014892578125\t0.4870323240756988525390625\n\tscale\t0.074629\t0.289956\t0.01\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t0\t0\t1\n\tsit_hint\t0\n\tstate\t160\n\tmaterial\t3\n\tsoundid\t00000000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundradius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t16\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\tscale_x\t1\n\t\t\tscale_y\t1\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t1\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tfaces\t6\n\t{\n\t\timageid\tddde1ffc-678b-3cda-1748-513086bdf01b\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tddde1ffc-678b-3cda-1748-513086bdf01b\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t-1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t0\n\tbirthtime\t1061088050622956\n\treztime\t1094866329019785\n\tparceltime\t1133568981980596\n\ttax_rate\t1.00084\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tchild\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n{'task_id':u61fa7364-e151-0597-774c-523312dae31b}\n{\n\tname\tObject|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffffff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreator_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444922\n\ttotal_crc\t324\n\ttype\t2\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.367110789\t0.00780026987\t-0.566269755\n\toldpos\t150.115005\t25.8479004\t8.18669987\n\trotation\t0.47332942485809326171875\t-0.380102097988128662109375\t-0.5734078884124755859375\t0.550168216228485107421875\n\tchildpos\t-0.00499999989\t-0.0370000005\t0.305000007\n\tchildrot\t-0.736649334430694580078125\t-0.03042060509324073791503906\t-0.02784589119255542755126953\t0.67501628398895263671875\n\tscale\t0.074629\t0.289956\t0.01\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t0\t0\t1\n\tsit_hint\t0\n\tstate\t160\n\tmaterial\t3\n\tsoundid\t00000000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundradius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t16\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\tscale_x\t1\n\t\t\tscale_y\t1\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t1\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tfaces\t6\n\t{\n\t\timageid\tddde1ffc-678b-3cda-1748-513086bdf01b\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tddde1ffc-678b-3cda-1748-513086bdf01b\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t-1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t0\n\tbirthtime\t1061087839248891\n\treztime\t1094866329020800\n\tparceltime\t1133568981981983\n\ttax_rate\t1.00084\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tchild\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n{'task_id':ub8d68643-7dd8-57af-0d24-8790032aed0c}\n{\n\tname\tObject|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffffff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreator_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444923\n\ttotal_crc\t235\n\ttype\t2\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.120029509\t-0.00284469454\t-0.0302077383\n\toldpos\t150.710999\t25.8584995\t8.19172001\n\trotation\t0.145459949970245361328125\t-0.1646589934825897216796875\t0.659558117389678955078125\t-0.718826770782470703125\n\tchildpos\t0\t-0.182999998\t-0.26699999\n\tchildrot\t0.991444766521453857421875\t3.271923924330621957778931e-05\t-0.0002416197530692443251609802\t0.1305266767740249633789062\n\tscale\t0.0382982\t0.205957\t0.368276\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t0\t0\t1\n\tsit_hint\t0\n\tstate\t160\n\tmaterial\t3\n\tsoundid\t00000000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundradius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t32\n\t\t\tbegin\t0.3\n\t\t\tend\t0.65\n\t\t\tscale_x\t1\n\t\t\tscale_y\t0.05\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t0\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tfaces\t3\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t0\n\tbirthtime\t1061087534454174\n\treztime\t1094866329021741\n\tparceltime\t1133568981982889\n\ttax_rate\t1.00326\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tchild\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n{'task_id':ue4b19200-9d33-962f-c8c5-6f25be3a3fd0}\n{\n\tname\tApotheosis_Immolaine_tail|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffffff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreator_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444924\n\ttotal_crc\t675\n\ttype\t1\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.34780401\t-0.00968400016\t-0.260098994\n\toldpos\t0\t0\t0\n\trotation\t0.73164522647857666015625\t-0.67541944980621337890625\t-0.07733880728483200073242188\t0.05022468417882919311523438\n\tvelocity\t0\t0\t0\n\tangvel\t0\t0\t0\n\tscale\t0.0382982\t0.32228\t0.383834\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t0\t0\t1\n\tsit_hint\t0\n\tstate\t160\n\tmaterial\t3\n\tsoundid\t00000000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundradius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t32\n\t\t\tbegin\t0.3\n\t\t\tend\t0.65\n\t\t\tscale_x\t1\n\t\t\tscale_y\t0.05\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t0\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tfaces\t3\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t0\n\tbirthtime\t1061087463950186\n\treztime\t1094866329022555\n\tparceltime\t1133568981984359\n\tdescription\t(No Description)|\n\ttax_rate\t1.01736\n\tnamevalue\tAttachPt U32 RW S 10\n\tnamevalue\tAttachmentOrientation VEC3 RW DS -3.110088, -0.182018, 1.493795\n\tnamevalue\tAttachmentOffset VEC3 RW DS -0.347804, -0.009684, -0.260099\n\tnamevalue\tAttachItemID STRING RW SV 20f36c3a-b44b-9bc7-87f3-018bfdfc8cda\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\torig_asset_id\t8747acbc-d391-1e59-69f1-41d06830e6c0\n\torig_item_id\t20f36c3a-b44b-9bc7-87f3-018bfdfc8cda\n\tfrom_task_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tlinked\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n"
01591 */

Generated on Fri May 16 08:34:29 2008 for SecondLife by  doxygen 1.5.5