diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/test/io.cpp | |
parent | README.txt (diff) | |
download | meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2 meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz |
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/test/io.cpp')
-rw-r--r-- | linden/indra/test/io.cpp | 1387 |
1 files changed, 1387 insertions, 0 deletions
diff --git a/linden/indra/test/io.cpp b/linden/indra/test/io.cpp new file mode 100644 index 0000000..2f6ba09 --- /dev/null +++ b/linden/indra/test/io.cpp | |||
@@ -0,0 +1,1387 @@ | |||
1 | /** | ||
2 | * @file io.cpp | ||
3 | * @author Phoenix | ||
4 | * @date 2005-10-02 | ||
5 | * @brief Tests for io classes and helpers | ||
6 | * | ||
7 | * Copyright (c) 2005-2007, Linden Research, Inc. | ||
8 | * | ||
9 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
10 | * to you under the terms of the GNU General Public License, version 2.0 | ||
11 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
12 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
13 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
14 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
15 | * | ||
16 | * There are special exceptions to the terms and conditions of the GPL as | ||
17 | * it is applied to this Source Code. View the full text of the exception | ||
18 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
19 | * online at http://secondlife.com/developers/opensource/flossexception | ||
20 | * | ||
21 | * By copying, modifying or distributing this software, you acknowledge | ||
22 | * that you have read and understood your obligations described above, | ||
23 | * and agree to abide by those obligations. | ||
24 | * | ||
25 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
26 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
27 | * COMPLETENESS OR PERFORMANCE. | ||
28 | */ | ||
29 | |||
30 | #include "linden_common.h" | ||
31 | #include "lltut.h" | ||
32 | |||
33 | #include <iterator> | ||
34 | |||
35 | #include <apr-1/apr_pools.h> | ||
36 | |||
37 | #include "llbuffer.h" | ||
38 | #include "llbufferstream.h" | ||
39 | #include "lliosocket.h" | ||
40 | #include "llioutil.h" | ||
41 | #include "llmemorystream.h" | ||
42 | #include "llpipeutil.h" | ||
43 | #include "llpumpio.h" | ||
44 | #include "llsd.h" | ||
45 | #include "llsdrpcclient.h" | ||
46 | #include "llsdrpcserver.h" | ||
47 | #include "llsdserialize.h" | ||
48 | #include "lluuid.h" | ||
49 | #include "llinstantmessage.h" | ||
50 | |||
51 | namespace tut | ||
52 | { | ||
53 | struct buffer_data | ||
54 | { | ||
55 | LLBufferArray mBuffer; | ||
56 | }; | ||
57 | typedef test_group<buffer_data> buffer_test; | ||
58 | typedef buffer_test::object buffer_object; | ||
59 | tut::buffer_test tba("buffer_array"); | ||
60 | |||
61 | template<> template<> | ||
62 | void buffer_object::test<1>() | ||
63 | { | ||
64 | const char HELLO_WORLD[] = "hello world"; | ||
65 | const S32 str_len = strlen(HELLO_WORLD); | ||
66 | LLChannelDescriptors ch = mBuffer.nextChannel(); | ||
67 | mBuffer.append(ch.in(), (U8*)HELLO_WORLD, str_len); | ||
68 | S32 count = mBuffer.countAfter(ch.in(), NULL); | ||
69 | ensure_equals("total append size", count, str_len); | ||
70 | LLBufferArray::segment_iterator_t it = mBuffer.beginSegment(); | ||
71 | U8* first = (*it).data(); | ||
72 | count = mBuffer.countAfter(ch.in(), first); | ||
73 | ensure_equals("offset append size", count, str_len - 1); | ||
74 | } | ||
75 | |||
76 | template<> template<> | ||
77 | void buffer_object::test<2>() | ||
78 | { | ||
79 | const char HELLO_WORLD[] = "hello world"; | ||
80 | const S32 str_len = strlen(HELLO_WORLD); | ||
81 | LLChannelDescriptors ch = mBuffer.nextChannel(); | ||
82 | mBuffer.append(ch.in(), (U8*)HELLO_WORLD, str_len); | ||
83 | mBuffer.append(ch.in(), (U8*)HELLO_WORLD, str_len); | ||
84 | S32 count = mBuffer.countAfter(ch.in(), NULL); | ||
85 | ensure_equals("total append size", count, 2 * str_len); | ||
86 | LLBufferArray::segment_iterator_t it = mBuffer.beginSegment(); | ||
87 | U8* first = (*it).data(); | ||
88 | count = mBuffer.countAfter(ch.in(), first); | ||
89 | ensure_equals("offset append size", count, (2 * str_len) - 1); | ||
90 | } | ||
91 | |||
92 | template<> template<> | ||
93 | void buffer_object::test<3>() | ||
94 | { | ||
95 | const char ONE[] = "one"; | ||
96 | const char TWO[] = "two"; | ||
97 | std::string expected(ONE); | ||
98 | expected.append(TWO); | ||
99 | LLChannelDescriptors ch = mBuffer.nextChannel(); | ||
100 | mBuffer.append(ch.in(), (U8*)ONE, 3); | ||
101 | mBuffer.append(ch.in(), (U8*)TWO, 3); | ||
102 | char buffer[255]; | ||
103 | S32 len = 6; | ||
104 | mBuffer.readAfter(ch.in(), NULL, (U8*)buffer, len); | ||
105 | ensure_equals(len, 6); | ||
106 | buffer[len] = '\0'; | ||
107 | std::string actual(buffer); | ||
108 | ensure_equals("read", actual, expected); | ||
109 | } | ||
110 | |||
111 | template<> template<> | ||
112 | void buffer_object::test<4>() | ||
113 | { | ||
114 | const char ONE[] = "one"; | ||
115 | const char TWO[] = "two"; | ||
116 | std::string expected(ONE); | ||
117 | expected.append(TWO); | ||
118 | LLChannelDescriptors ch = mBuffer.nextChannel(); | ||
119 | mBuffer.append(ch.in(), (U8*)TWO, 3); | ||
120 | mBuffer.prepend(ch.in(), (U8*)ONE, 3); | ||
121 | char buffer[255]; | ||
122 | S32 len = 6; | ||
123 | mBuffer.readAfter(ch.in(), NULL, (U8*)buffer, len); | ||
124 | ensure_equals(len, 6); | ||
125 | buffer[len] = '\0'; | ||
126 | std::string actual(buffer); | ||
127 | ensure_equals("read", actual, expected); | ||
128 | } | ||
129 | |||
130 | template<> template<> | ||
131 | void buffer_object::test<5>() | ||
132 | { | ||
133 | const char ONE[] = "one"; | ||
134 | const char TWO[] = "two"; | ||
135 | std::string expected("netwo"); | ||
136 | LLChannelDescriptors ch = mBuffer.nextChannel(); | ||
137 | mBuffer.append(ch.in(), (U8*)TWO, 3); | ||
138 | mBuffer.prepend(ch.in(), (U8*)ONE, 3); | ||
139 | char buffer[255]; | ||
140 | S32 len = 5; | ||
141 | LLBufferArray::segment_iterator_t it = mBuffer.beginSegment(); | ||
142 | U8* addr = (*it).data(); | ||
143 | mBuffer.readAfter(ch.in(), addr, (U8*)buffer, len); | ||
144 | ensure_equals(len, 5); | ||
145 | buffer[len] = '\0'; | ||
146 | std::string actual(buffer); | ||
147 | ensure_equals("read", actual, expected); | ||
148 | } | ||
149 | |||
150 | template<> template<> | ||
151 | void buffer_object::test<6>() | ||
152 | { | ||
153 | std::string request("The early bird catches the worm."); | ||
154 | std::string response("If you're a worm, sleep late."); | ||
155 | std::ostringstream expected; | ||
156 | expected << "ContentLength: " << response.length() << "\r\n\r\n" | ||
157 | << response; | ||
158 | LLChannelDescriptors ch = mBuffer.nextChannel(); | ||
159 | mBuffer.append(ch.in(), (U8*)request.c_str(), request.length()); | ||
160 | mBuffer.append(ch.out(), (U8*)response.c_str(), response.length()); | ||
161 | S32 count = mBuffer.countAfter(ch.out(), NULL); | ||
162 | std::ostringstream header; | ||
163 | header << "ContentLength: " << count << "\r\n\r\n"; | ||
164 | std::string head(header.str()); | ||
165 | mBuffer.prepend(ch.out(), (U8*)head.c_str(), head.length()); | ||
166 | char buffer[1024]; | ||
167 | S32 len = response.size() + head.length(); | ||
168 | ensure_equals("same length", len, (S32)expected.str().length()); | ||
169 | mBuffer.readAfter(ch.out(), NULL, (U8*)buffer, len); | ||
170 | buffer[len] = '\0'; | ||
171 | std::string actual(buffer); | ||
172 | ensure_equals("threaded writes", actual, expected.str()); | ||
173 | } | ||
174 | |||
175 | template<> template<> | ||
176 | void buffer_object::test<7>() | ||
177 | { | ||
178 | const S32 LINE_COUNT = 3; | ||
179 | std::string lines[LINE_COUNT] = | ||
180 | { | ||
181 | std::string("GET /index.htm HTTP/1.0\r\n"), | ||
182 | std::string("User-Agent: Wget/1.9.1\r\n"), | ||
183 | std::string("Host: localhost:8008\r\n") | ||
184 | }; | ||
185 | std::string text; | ||
186 | S32 i; | ||
187 | for(i = 0; i < LINE_COUNT; ++i) | ||
188 | { | ||
189 | text.append(lines[i]); | ||
190 | } | ||
191 | LLChannelDescriptors ch = mBuffer.nextChannel(); | ||
192 | mBuffer.append(ch.in(), (U8*)text.c_str(), text.length()); | ||
193 | const S32 BUFFER_LEN = 1024; | ||
194 | char buf[BUFFER_LEN]; | ||
195 | S32 len; | ||
196 | U8* last = NULL; | ||
197 | std::string last_line; | ||
198 | for(i = 0; i < LINE_COUNT; ++i) | ||
199 | { | ||
200 | len = BUFFER_LEN; | ||
201 | last = mBuffer.readAfter(ch.in(), last, (U8*)buf, len); | ||
202 | char* newline = strchr((char*)buf, '\n'); | ||
203 | S32 offset = -((len - 1) - (newline - buf)); | ||
204 | ++newline; | ||
205 | *newline = '\0'; | ||
206 | last_line.assign(buf); | ||
207 | std::ostringstream message; | ||
208 | message << "line reads in line[" << i << "]"; | ||
209 | ensure_equals(message.str().c_str(), last_line, lines[i]); | ||
210 | last = mBuffer.seek(ch.in(), last, offset); | ||
211 | } | ||
212 | } | ||
213 | |||
214 | template<> template<> | ||
215 | void buffer_object::test<8>() | ||
216 | { | ||
217 | LLChannelDescriptors ch = mBuffer.nextChannel(); | ||
218 | mBuffer.append(ch.in(), (U8*)"1", 1); | ||
219 | LLBufferArray buffer; | ||
220 | buffer.append(ch.in(), (U8*)"2", 1); | ||
221 | mBuffer.takeContents(buffer); | ||
222 | mBuffer.append(ch.in(), (U8*)"3", 1); | ||
223 | S32 count = mBuffer.countAfter(ch.in(), NULL); | ||
224 | ensure_equals("buffer size", count, 3); | ||
225 | U8* temp = new U8[count]; | ||
226 | mBuffer.readAfter(ch.in(), NULL, temp, count); | ||
227 | ensure("buffer content", (0 == memcmp(temp, (void*)"123", 3))); | ||
228 | delete[] temp; | ||
229 | } | ||
230 | |||
231 | /* | ||
232 | template<> template<> | ||
233 | void buffer_object::test<9>() | ||
234 | { | ||
235 | char buffer[1024]; | ||
236 | S32 size = sprintf(buffer, | ||
237 | "%d|%d|%s|%s|%s|%s|%s|%x|%x|%x|%x|%x|%s|%s|%d|%d|%x", | ||
238 | 7, | ||
239 | 7, | ||
240 | "Hang Glider INFO", | ||
241 | "18e84d1e-04a4-4c0d-8cb6-6c73477f0a9a", | ||
242 | "0e346d8b-4433-4d66-a6b0-fd37083abc4c", | ||
243 | "0e346d8b-4433-4d66-a6b0-fd37083abc4c", | ||
244 | "00000000-0000-0000-0000-000000000000", | ||
245 | 0x7fffffff, | ||
246 | 0x7fffffff, | ||
247 | 0, | ||
248 | 0, | ||
249 | 0x7fffffff, | ||
250 | "69e0d357-2e7c-8990-a2bc-7f61c868e5a3", | ||
251 | "2004-06-04 16:09:17 note card", | ||
252 | 0, | ||
253 | 10, | ||
254 | 0) + 1; | ||
255 | |||
256 | //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"; | ||
257 | |||
258 | LLSD* bin_bucket = LLIMInfo::buildSDfrombuffer((U8*)buffer,size); | ||
259 | |||
260 | char post_buffer[1024]; | ||
261 | U32 post_size; | ||
262 | LLIMInfo::getBinaryBucket(bin_bucket,(U8*)post_buffer,post_size); | ||
263 | ensure_equals("Buffer sizes",size,(S32)post_size); | ||
264 | ensure("Buffer content",!strcmp(buffer,post_buffer)); | ||
265 | } | ||
266 | */ | ||
267 | |||
268 | /* | ||
269 | template<> template<> | ||
270 | void buffer_object::test<>() | ||
271 | { | ||
272 | } | ||
273 | */ | ||
274 | } | ||
275 | |||
276 | namespace tut | ||
277 | { | ||
278 | struct buffer_and_stream_data | ||
279 | { | ||
280 | LLBufferArray mBuffer; | ||
281 | }; | ||
282 | typedef test_group<buffer_and_stream_data> bas_test; | ||
283 | typedef bas_test::object bas_object; | ||
284 | tut::bas_test tbs("buffer_stream"); | ||
285 | |||
286 | template<> template<> | ||
287 | void bas_object::test<1>() | ||
288 | { | ||
289 | const char HELLO_WORLD[] = "hello world"; | ||
290 | const S32 str_len = strlen(HELLO_WORLD); | ||
291 | LLChannelDescriptors ch = mBuffer.nextChannel(); | ||
292 | LLBufferStream str(ch, &mBuffer); | ||
293 | mBuffer.append(ch.in(), (U8*)HELLO_WORLD, str_len); | ||
294 | std::string hello; | ||
295 | std::string world; | ||
296 | str >> hello >> world; | ||
297 | ensure_equals("first word", hello, std::string("hello")); | ||
298 | ensure_equals("second word", world, std::string("world")); | ||
299 | } | ||
300 | |||
301 | template<> template<> | ||
302 | void bas_object::test<2>() | ||
303 | { | ||
304 | std::string part1("Eat my shor"); | ||
305 | std::string part2("ts ho"); | ||
306 | std::string part3("mer"); | ||
307 | std::string ignore("ignore me"); | ||
308 | LLChannelDescriptors ch = mBuffer.nextChannel(); | ||
309 | LLBufferStream str(ch, &mBuffer); | ||
310 | mBuffer.append(ch.in(), (U8*)part1.c_str(), part1.length()); | ||
311 | mBuffer.append(ch.in(), (U8*)part2.c_str(), part2.length()); | ||
312 | mBuffer.append(ch.out(), (U8*)ignore.c_str(), ignore.length()); | ||
313 | mBuffer.append(ch.in(), (U8*)part3.c_str(), part3.length()); | ||
314 | std::string eat; | ||
315 | std::string my; | ||
316 | std::string shorts; | ||
317 | std::string homer; | ||
318 | str >> eat >> my >> shorts >> homer; | ||
319 | ensure_equals("word1", eat, std::string("Eat")); | ||
320 | ensure_equals("word2", my, std::string("my")); | ||
321 | ensure_equals("word3", shorts, std::string("shorts")); | ||
322 | ensure_equals("word4", homer, std::string("homer")); | ||
323 | } | ||
324 | |||
325 | template<> template<> | ||
326 | void bas_object::test<3>() | ||
327 | { | ||
328 | std::string part1("junk in "); | ||
329 | std::string part2("the trunk"); | ||
330 | const S32 CHANNEL = 0; | ||
331 | mBuffer.append(CHANNEL, (U8*)part1.c_str(), part1.length()); | ||
332 | mBuffer.append(CHANNEL, (U8*)part2.c_str(), part2.length()); | ||
333 | U8* last = 0; | ||
334 | const S32 BUF_LEN = 128; | ||
335 | char buf[BUF_LEN]; | ||
336 | S32 len = 11; | ||
337 | last = mBuffer.readAfter(CHANNEL, last, (U8*)buf, len); | ||
338 | buf[len] = '\0'; | ||
339 | std::string actual(buf); | ||
340 | ensure_equals("first read", actual, std::string("junk in the")); | ||
341 | last = mBuffer.seek(CHANNEL, last, -6); | ||
342 | len = 12; | ||
343 | last = mBuffer.readAfter(CHANNEL, last, (U8*)buf, len); | ||
344 | buf[len] = '\0'; | ||
345 | actual.assign(buf); | ||
346 | ensure_equals("seek and read", actual, std::string("in the trunk")); | ||
347 | } | ||
348 | |||
349 | template<> template<> | ||
350 | void bas_object::test<4>() | ||
351 | { | ||
352 | std::string phrase("zippity do da!"); | ||
353 | const S32 CHANNEL = 0; | ||
354 | mBuffer.append(CHANNEL, (U8*)phrase.c_str(), phrase.length()); | ||
355 | const S32 BUF_LEN = 128; | ||
356 | char buf[BUF_LEN]; | ||
357 | S32 len = 7; | ||
358 | U8* last = mBuffer.readAfter(CHANNEL, NULL, (U8*)buf, len); | ||
359 | mBuffer.splitAfter(last); | ||
360 | LLBufferArray::segment_iterator_t it = mBuffer.beginSegment(); | ||
361 | LLBufferArray::segment_iterator_t end = mBuffer.endSegment(); | ||
362 | std::string first((char*)((*it).data()), (*it).size()); | ||
363 | ensure_equals("first part", first, std::string("zippity")); | ||
364 | ++it; | ||
365 | std::string second((char*)((*it).data()), (*it).size()); | ||
366 | ensure_equals("second part", second, std::string(" do da!")); | ||
367 | ++it; | ||
368 | ensure("iterators equal", (it == end)); | ||
369 | } | ||
370 | |||
371 | template<> template<> | ||
372 | void bas_object::test<5>() | ||
373 | { | ||
374 | LLChannelDescriptors ch = mBuffer.nextChannel(); | ||
375 | LLBufferStream str(ch, &mBuffer); | ||
376 | std::string h1("hello"); | ||
377 | std::string h2(", how are you doing?"); | ||
378 | std::string expected(h1); | ||
379 | expected.append(h2); | ||
380 | str << h1 << h2; | ||
381 | str.flush(); | ||
382 | const S32 BUF_LEN = 128; | ||
383 | char buf[BUF_LEN]; | ||
384 | S32 actual_len = BUF_LEN; | ||
385 | S32 expected_len = h1.size() + h2.size(); | ||
386 | (void) mBuffer.readAfter(ch.out(), NULL, (U8*)buf, actual_len); | ||
387 | ensure_equals("streamed size", actual_len, expected_len); | ||
388 | buf[actual_len] = '\0'; | ||
389 | std::string actual(buf); | ||
390 | ensure_equals("streamed to buf", actual, expected); | ||
391 | } | ||
392 | |||
393 | template<> template<> | ||
394 | void bas_object::test<6>() | ||
395 | { | ||
396 | LLChannelDescriptors ch = mBuffer.nextChannel(); | ||
397 | LLBufferStream bstr(ch, &mBuffer); | ||
398 | std::ostringstream ostr; | ||
399 | std::vector<LLUUID> ids; | ||
400 | LLUUID id; | ||
401 | for(int i = 0; i < 5; ++i) | ||
402 | { | ||
403 | id.generate(); | ||
404 | ids.push_back(id); | ||
405 | } | ||
406 | bstr << "SELECT concat(u.username, ' ', l.name) " | ||
407 | << "FROM user u, user_last_name l " | ||
408 | << "WHERE u.last_name_id = l.last_name_id" | ||
409 | << " AND u.agent_id IN ('"; | ||
410 | ostr << "SELECT concat(u.username, ' ', l.name) " | ||
411 | << "FROM user u, user_last_name l " | ||
412 | << "WHERE u.last_name_id = l.last_name_id" | ||
413 | << " AND u.agent_id IN ('"; | ||
414 | std::copy( | ||
415 | ids.begin(), | ||
416 | ids.end(), | ||
417 | std::ostream_iterator<LLUUID>(bstr, "','")); | ||
418 | std::copy( | ||
419 | ids.begin(), | ||
420 | ids.end(), | ||
421 | std::ostream_iterator<LLUUID>(ostr, "','")); | ||
422 | bstr.seekp(-2, std::ios::cur); | ||
423 | ostr.seekp(-2, std::ios::cur); | ||
424 | bstr << ") "; | ||
425 | ostr << ") "; | ||
426 | bstr.flush(); | ||
427 | const S32 BUF_LEN = 512; | ||
428 | char buf[BUF_LEN]; | ||
429 | S32 actual_len = BUF_LEN; | ||
430 | (void) mBuffer.readAfter(ch.out(), NULL, (U8*)buf, actual_len); | ||
431 | buf[actual_len] = '\0'; | ||
432 | std::string actual(buf); | ||
433 | std::string expected(ostr.str()); | ||
434 | ensure_equals("size of string in seek",actual.size(),expected.size()); | ||
435 | ensure_equals("seek in ostream", actual, expected); | ||
436 | } | ||
437 | |||
438 | template<> template<> | ||
439 | void bas_object::test<7>() | ||
440 | { | ||
441 | LLChannelDescriptors ch = mBuffer.nextChannel(); | ||
442 | LLBufferStream bstr(ch, &mBuffer); | ||
443 | bstr << "1"; | ||
444 | bstr.flush(); | ||
445 | S32 count = mBuffer.countAfter(ch.out(), NULL); | ||
446 | ensure_equals("buffer size 1", count, 1); | ||
447 | LLBufferArray buffer; | ||
448 | buffer.append(ch.out(), (U8*)"2", 1); | ||
449 | mBuffer.takeContents(buffer); | ||
450 | count = mBuffer.countAfter(ch.out(), NULL); | ||
451 | ensure_equals("buffer size 2", count, 2); | ||
452 | bstr << "3"; | ||
453 | bstr.flush(); | ||
454 | count = mBuffer.countAfter(ch.out(), NULL); | ||
455 | ensure_equals("buffer size 3", count, 3); | ||
456 | U8* temp = new U8[count]; | ||
457 | mBuffer.readAfter(ch.out(), NULL, temp, count); | ||
458 | ensure("buffer content", (0 == memcmp(temp, (void*)"123", 3))); | ||
459 | delete[] temp; | ||
460 | } | ||
461 | |||
462 | template<> template<> | ||
463 | void bas_object::test<8>() | ||
464 | { | ||
465 | LLChannelDescriptors ch = mBuffer.nextChannel(); | ||
466 | LLBufferStream ostr(ch, &mBuffer); | ||
467 | typedef std::vector<U8> buf_t; | ||
468 | typedef std::vector<buf_t> actual_t; | ||
469 | actual_t actual; | ||
470 | buf_t source; | ||
471 | bool need_comma = false; | ||
472 | ostr << "["; | ||
473 | S32 total_size = 1; | ||
474 | for(S32 i = 2000; i < 2003; ++i) | ||
475 | { | ||
476 | if(need_comma) | ||
477 | { | ||
478 | ostr << ","; | ||
479 | ++total_size; | ||
480 | } | ||
481 | need_comma = true; | ||
482 | srand(69 + i); | ||
483 | S32 size = rand() % 1000 + 1000; | ||
484 | std::generate_n( | ||
485 | std::back_insert_iterator<buf_t>(source), | ||
486 | size, | ||
487 | rand); | ||
488 | actual.push_back(source); | ||
489 | ostr << "b(" << size << ")\""; | ||
490 | total_size += 8; | ||
491 | ostr.write((const char*)(&source[0]), size); | ||
492 | total_size += size; | ||
493 | source.clear(); | ||
494 | ostr << "\""; | ||
495 | ++total_size; | ||
496 | } | ||
497 | ostr << "]"; | ||
498 | ++total_size; | ||
499 | ostr.flush(); | ||
500 | |||
501 | // now that we have a bunch of data on a stream, parse it all. | ||
502 | ch = mBuffer.nextChannel(); | ||
503 | S32 count = mBuffer.countAfter(ch.in(), NULL); | ||
504 | ensure_equals("size of buffer", count, total_size); | ||
505 | LLBufferStream istr(ch, &mBuffer); | ||
506 | LLSD data; | ||
507 | count = LLSDSerialize::fromNotation(data, istr); | ||
508 | ensure("sd parsed", data.isDefined()); | ||
509 | |||
510 | for(S32 j = 0; j < 3; ++j) | ||
511 | { | ||
512 | std::ostringstream name; | ||
513 | LLSD child(data[j]); | ||
514 | name << "found buffer " << j; | ||
515 | ensure(name.str(), child.isDefined()); | ||
516 | source = child.asBinary(); | ||
517 | name.str(""); | ||
518 | name << "buffer " << j << " size"; | ||
519 | ensure_equals(name.str().c_str(), source.size(), actual[j].size()); | ||
520 | name.str(""); | ||
521 | name << "buffer " << j << " contents"; | ||
522 | ensure( | ||
523 | name.str(), | ||
524 | (0 == memcmp(&source[0], &actual[j][0], source.size()))); | ||
525 | } | ||
526 | } | ||
527 | |||
528 | template<> template<> | ||
529 | void bas_object::test<9>() | ||
530 | { | ||
531 | LLChannelDescriptors ch = mBuffer.nextChannel(); | ||
532 | LLBufferStream ostr(ch, &mBuffer); | ||
533 | typedef std::vector<U8> buf_t; | ||
534 | buf_t source; | ||
535 | bool need_comma = false; | ||
536 | ostr << "{"; | ||
537 | S32 total_size = 1; | ||
538 | for(S32 i = 1000; i < 3000; ++i) | ||
539 | { | ||
540 | if(need_comma) | ||
541 | { | ||
542 | ostr << ","; | ||
543 | ++total_size; | ||
544 | } | ||
545 | need_comma = true; | ||
546 | ostr << "'" << i << "':"; | ||
547 | total_size += 7; | ||
548 | srand(69 + i); | ||
549 | S32 size = rand() % 1000 + 1000; | ||
550 | std::generate_n( | ||
551 | std::back_insert_iterator<buf_t>(source), | ||
552 | size, | ||
553 | rand); | ||
554 | ostr << "b(" << size << ")\""; | ||
555 | total_size += 8; | ||
556 | ostr.write((const char*)(&source[0]), size); | ||
557 | total_size += size; | ||
558 | source.clear(); | ||
559 | ostr << "\""; | ||
560 | ++total_size; | ||
561 | } | ||
562 | ostr << "}"; | ||
563 | ++total_size; | ||
564 | ostr.flush(); | ||
565 | |||
566 | // now that we have a bunch of data on a stream, parse it all. | ||
567 | ch = mBuffer.nextChannel(); | ||
568 | S32 count = mBuffer.countAfter(ch.in(), NULL); | ||
569 | ensure_equals("size of buffer", count, total_size); | ||
570 | LLBufferStream istr(ch, &mBuffer); | ||
571 | LLSD data; | ||
572 | count = LLSDSerialize::fromNotation(data, istr); | ||
573 | ensure("sd parsed", data.isDefined()); | ||
574 | } | ||
575 | |||
576 | template<> template<> | ||
577 | void bas_object::test<10>() | ||
578 | { | ||
579 | const char LOGIN_STREAM[] = "{'method':'login', 'parameter': [ {" | ||
580 | "'uri': 'sl-am:kellys.region.siva.lindenlab.com/location?start=url&px=128&py=128&pz=128&lx=0&ly=0&lz=0'}, " | ||
581 | "{'version': i1}, {'texture_data': [ '61d724fb-ad79-f637-2186-5cf457560daa', '6e38b9be-b7cc-e77a-8aec-029a42b0b416', " | ||
582 | "'a9073524-e89b-2924-ca6e-a81944109a1a', '658f18b5-5f1e-e593-f5d5-36c3abc7249a', '0cc799f4-8c99-6b91-bd75-b179b12429e2', " | ||
583 | "'59fd9b64-8300-a425-aad8-2ffcbe9a49d2', '59fd9b64-8300-a425-aad8-2ffcbe9a49d2', '5748decc-f629-461c-9a36-a35a221fe21f', " | ||
584 | "'b8fc9be2-26a6-6b47-690b-0e902e983484', 'a13ca0fe-3802-dc97-e79a-70d12171c724', 'dd9643cf-fd5d-0376-ed4a-b1cc646a97d5', " | ||
585 | "'4ad13ae9-a112-af09-210a-cf9353a7a9e7', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', " | ||
586 | "'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', " | ||
587 | "'5748decc-f629-461c-9a36-a35a221fe21f', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97']," | ||
588 | "'session_id': '324cfa9f-fe5d-4d1c-a317-35f20a86a4d1','position': [ i128, i128, i128],'last_name': 'Linden','group_title': '-> !BLING! <-','group_name': 'test!','agent_access': 'M'," | ||
589 | "'attachment_data': [ {'asset_id': 'aaede2b1-9955-09d4-5c93-2b557c778cf3','attachment_point': i6,'item_id': 'f3694abc-5122-db33-73d9-e0f4288dc2bf'}]," | ||
590 | "'buddy_ids': [ '101358d5-469d-4b24-9b85-4dc3c05e635d', '1b00fec7-6265-4875-acac-80d9cfe9295c', '203ad6df-b522-491d-ba48-4e24eb57aeff', " | ||
591 | "'22d4dcdb-aebb-47fa-b925-a871cc75ee48','27da3df5-1339-4463-80aa-40504ee3b3e5', '299d1720-b61f-4268-8c29-9614aa2d44c2', " | ||
592 | "'2b048a24-2737-4994-9fa5-becc8e466253', '2cd5dc14-a853-49a4-be3c-a5a7178e37bc', '3de548e1-57be-cfea-2b78-83ae3ad95998', " | ||
593 | "'3dee98e4-a6a3-4543-91c3-bbd528447ba7', '3e2d81a3-6263-6ffe-ad5c-8ce04bee07e9', '40e70b98-fed7-47f3-9700-1bce93f9350b', " | ||
594 | "'50a9b68e-b5aa-4d35-9137-3cfebda0a15c', '54295571-9357-43ff-ae74-a83b5138160f', '6191e2d7-5f96-4856-bdab-af0f79f47ae4', " | ||
595 | "'63e577d8-cd34-4235-a0a3-de0500133364', '79cfb666-4fd0-4af7-95df-fb7d96b4e24d', '8121c2f3-4a88-4c33-9899-8fc1273f47ee', " | ||
596 | "'909da964-ef23-4f2a-ba13-f2a8cfd454b6','a2e76fcd-9360-4f6d-a924-000000000001', 'aaa6d664-527e-4d83-9cbb-7ef79ccc7cc8', " | ||
597 | "'b79bfb6c-23be-49eb-b35b-30ff2f501b37', 'ba0d9c79-148c-4a79-8e3c-0665eebe2427', 'bc9bda98-57cd-498f-b993-4ff1ac9dec93', " | ||
598 | "'c62d16f6-81cb-419d-9cac-e46dc394084d', 'd48f8fa7-2512-4fe5-80c8-c0a923412e07', 'd77e3e24-7e6c-4c3f-96d0-a1746337f8fb', " | ||
599 | "'da615c63-a84b-4592-a3d6-a90dd3e92e6e', 'df47190a-7eb7-4aff-985f-2d1d3ad6c6e9', 'e3380196-72cd-499c-a2ba-caa180bd5fe4', " | ||
600 | "'e937863f-f134-4207-803b-d6e686651d6c', 'efcdf98b-5269-45ef-ac7a-0671f09ea9d9']," | ||
601 | "'circuit_code': i124,'group_id': '8615c885-9cf0-bf0a-6e40-0c11462aa652','limited_to_estate': i1,'look_at': [ i0, i0, i0]," | ||
602 | "'agent_id': '0e346d8b-4433-4d66-a6b0-fd37083abc4c','first_name': 'Kelly','start': 'url'}]}"; | ||
603 | LLChannelDescriptors ch = mBuffer.nextChannel(); | ||
604 | mBuffer.append(ch.out(), (U8*)LOGIN_STREAM, strlen(LOGIN_STREAM)); | ||
605 | ch = mBuffer.nextChannel(); | ||
606 | LLBufferStream istr(ch, &mBuffer); | ||
607 | LLSD data; | ||
608 | S32 count = LLSDSerialize::fromNotation(data, istr); | ||
609 | ensure("parsed something", (count > 0)); | ||
610 | ensure("sd parsed", data.isDefined()); | ||
611 | ensure_equals("sd type", data.type(), LLSD::TypeMap); | ||
612 | ensure("has method", data.has("method")); | ||
613 | ensure("has parameter", data.has("parameter")); | ||
614 | LLSD parameter = data["parameter"]; | ||
615 | ensure_equals("parameter is array", parameter.type(), LLSD::TypeArray); | ||
616 | LLSD agent_params = parameter[2]; | ||
617 | std::string s_value; | ||
618 | s_value = agent_params["last_name"].asString(); | ||
619 | ensure_equals("last name", s_value, std::string("Linden")); | ||
620 | s_value = agent_params["first_name"].asString(); | ||
621 | ensure_equals("first name", s_value, std::string("Kelly")); | ||
622 | s_value = agent_params["agent_access"].asString(); | ||
623 | ensure_equals("agent access", s_value, std::string("M")); | ||
624 | s_value = agent_params["group_name"].asString(); | ||
625 | ensure_equals("group name", s_value, std::string("test!")); | ||
626 | s_value = agent_params["group_title"].asString(); | ||
627 | ensure_equals("group title", s_value, std::string("-> !BLING! <-")); | ||
628 | |||
629 | LLUUID agent_id("0e346d8b-4433-4d66-a6b0-fd37083abc4c"); | ||
630 | LLUUID id = agent_params["agent_id"]; | ||
631 | ensure_equals("agent id", id, agent_id); | ||
632 | LLUUID session_id("324cfa9f-fe5d-4d1c-a317-35f20a86a4d1"); | ||
633 | id = agent_params["session_id"]; | ||
634 | ensure_equals("session id", id, session_id); | ||
635 | LLUUID group_id ("8615c885-9cf0-bf0a-6e40-0c11462aa652"); | ||
636 | id = agent_params["group_id"]; | ||
637 | ensure_equals("group id", id, group_id); | ||
638 | |||
639 | S32 i_val = agent_params["limited_to_estate"]; | ||
640 | ensure_equals("limited to estate", i_val, 1); | ||
641 | i_val = agent_params["circuit_code"]; | ||
642 | ensure_equals("circuit code", i_val, 124); | ||
643 | } | ||
644 | |||
645 | |||
646 | template<> template<> | ||
647 | void bas_object::test<11>() | ||
648 | { | ||
649 | std::string val = "{!'foo'@:#'bar'}"; | ||
650 | std::istringstream istr; | ||
651 | istr.str(val); | ||
652 | LLSD sd; | ||
653 | S32 count = LLSDSerialize::fromNotation(sd, istr); | ||
654 | ensure_equals("parser error return value", count, -1); | ||
655 | ensure("data undefined", sd.isUndefined()); | ||
656 | } | ||
657 | |||
658 | template<> template<> | ||
659 | void bas_object::test<12>() | ||
660 | { | ||
661 | std::string val = "{!'foo':[i1,'hi',{@'bar'#:[$i2%,^'baz'&]*}+]=}"; | ||
662 | std::istringstream istr; | ||
663 | istr.str(val); | ||
664 | LLSD sd; | ||
665 | S32 count = LLSDSerialize::fromNotation(sd, istr); | ||
666 | ensure_equals("parser error return value", count, -1); | ||
667 | ensure("data undefined", sd.isUndefined()); | ||
668 | } | ||
669 | |||
670 | /* | ||
671 | template<> template<> | ||
672 | void bas_object::test<13>() | ||
673 | { | ||
674 | } | ||
675 | template<> template<> | ||
676 | void bas_object::test<14>() | ||
677 | { | ||
678 | } | ||
679 | template<> template<> | ||
680 | void bas_object::test<15>() | ||
681 | { | ||
682 | } | ||
683 | */ | ||
684 | } | ||
685 | |||
686 | |||
687 | namespace tut | ||
688 | { | ||
689 | class PumpAndChainTestData | ||
690 | { | ||
691 | protected: | ||
692 | apr_pool_t* mPool; | ||
693 | LLPumpIO* mPump; | ||
694 | LLPumpIO::chain_t mChain; | ||
695 | |||
696 | public: | ||
697 | PumpAndChainTestData() | ||
698 | { | ||
699 | apr_pool_create(&mPool, NULL); | ||
700 | mPump = new LLPumpIO(mPool); | ||
701 | } | ||
702 | |||
703 | ~PumpAndChainTestData() | ||
704 | { | ||
705 | mChain.clear(); | ||
706 | delete mPump; | ||
707 | apr_pool_destroy(mPool); | ||
708 | } | ||
709 | }; | ||
710 | typedef test_group<PumpAndChainTestData> PumpAndChainTestGroup; | ||
711 | typedef PumpAndChainTestGroup::object PumpAndChainTestObject; | ||
712 | PumpAndChainTestGroup pumpAndChainTestGroup("pump_and_chain"); | ||
713 | |||
714 | template<> template<> | ||
715 | void PumpAndChainTestObject::test<1>() | ||
716 | { | ||
717 | LLPipeStringExtractor* extractor = new LLPipeStringExtractor(); | ||
718 | |||
719 | mChain.push_back(LLIOPipe::ptr_t(new LLIOFlush)); | ||
720 | mChain.push_back(LLIOPipe::ptr_t(extractor)); | ||
721 | |||
722 | LLTimer timer; | ||
723 | timer.setTimerExpirySec(100.0f); | ||
724 | |||
725 | mPump->addChain(mChain, DEFAULT_CHAIN_EXPIRY_SECS); | ||
726 | while(!extractor->done() && !timer.hasExpired()) | ||
727 | { | ||
728 | mPump->pump(); | ||
729 | mPump->callback(); | ||
730 | } | ||
731 | |||
732 | ensure("reading string finished", extractor->done()); | ||
733 | ensure_equals("string was empty", extractor->string(), ""); | ||
734 | } | ||
735 | } | ||
736 | |||
737 | /* | ||
738 | namespace tut | ||
739 | { | ||
740 | struct double_construct | ||
741 | { | ||
742 | public: | ||
743 | double_construct() | ||
744 | { | ||
745 | llinfos << "constructed" << llendl; | ||
746 | } | ||
747 | ~double_construct() | ||
748 | { | ||
749 | llinfos << "destroyed" << llendl; | ||
750 | } | ||
751 | }; | ||
752 | typedef test_group<double_construct> double_construct_test_group; | ||
753 | typedef double_construct_test_group::object dc_test_object; | ||
754 | double_construct_test_group dctest("double construct"); | ||
755 | template<> template<> | ||
756 | void dc_test_object::test<1>() | ||
757 | { | ||
758 | ensure("test 1", true); | ||
759 | } | ||
760 | } | ||
761 | */ | ||
762 | |||
763 | namespace tut | ||
764 | { | ||
765 | /** | ||
766 | * @brief we want to test the pipes & pumps under bad conditions. | ||
767 | */ | ||
768 | struct pipe_and_pump_fitness | ||
769 | { | ||
770 | public: | ||
771 | enum | ||
772 | { | ||
773 | SERVER_LISTEN_PORT = 13050 | ||
774 | }; | ||
775 | |||
776 | pipe_and_pump_fitness() | ||
777 | { | ||
778 | LLFrameTimer::updateFrameTime(); | ||
779 | apr_pool_create(&mPool, NULL); | ||
780 | mPump = new LLPumpIO(mPool); | ||
781 | mSocket = LLSocket::create( | ||
782 | mPool, | ||
783 | LLSocket::STREAM_TCP, | ||
784 | SERVER_LISTEN_PORT); | ||
785 | } | ||
786 | |||
787 | ~pipe_and_pump_fitness() | ||
788 | { | ||
789 | mSocket.reset(); | ||
790 | delete mPump; | ||
791 | apr_pool_destroy(mPool); | ||
792 | } | ||
793 | |||
794 | protected: | ||
795 | apr_pool_t* mPool; | ||
796 | LLPumpIO* mPump; | ||
797 | LLSocket::ptr_t mSocket; | ||
798 | }; | ||
799 | typedef test_group<pipe_and_pump_fitness> fitness_test_group; | ||
800 | typedef fitness_test_group::object fitness_test_object; | ||
801 | fitness_test_group fitness("pipe and pump fitness"); | ||
802 | |||
803 | template<> template<> | ||
804 | void fitness_test_object::test<1>() | ||
805 | { | ||
806 | lldebugs << "fitness_test_object::test<1>()" << llendl; | ||
807 | |||
808 | // Set up the server | ||
809 | //lldebugs << "fitness_test_object::test<1> - setting up server." | ||
810 | // << llendl; | ||
811 | LLPumpIO::chain_t chain; | ||
812 | typedef LLCloneIOFactory<LLPipeStringInjector> emitter_t; | ||
813 | emitter_t* emitter = new emitter_t( | ||
814 | new LLPipeStringInjector("suckers never play me")); | ||
815 | boost::shared_ptr<LLChainIOFactory> factory(emitter); | ||
816 | LLIOServerSocket* server = new LLIOServerSocket( | ||
817 | mPool, | ||
818 | mSocket, | ||
819 | factory); | ||
820 | server->setResponseTimeout(SHORT_CHAIN_EXPIRY_SECS); | ||
821 | chain.push_back(LLIOPipe::ptr_t(server)); | ||
822 | mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS); | ||
823 | |||
824 | // We need to tickle the pump a little to set up the listen() | ||
825 | //lldebugs << "fitness_test_object::test<1> - initializing server." | ||
826 | // << llendl; | ||
827 | pump_loop(mPump, 0.1f); | ||
828 | |||
829 | // Set up the client | ||
830 | //lldebugs << "fitness_test_object::test<1> - connecting client." | ||
831 | // << llendl; | ||
832 | LLSocket::ptr_t client = LLSocket::create(mPool, LLSocket::STREAM_TCP); | ||
833 | LLHost server_host("127.0.0.1", SERVER_LISTEN_PORT); | ||
834 | bool connected = client->blockingConnect(server_host); | ||
835 | ensure("Connected to server", connected); | ||
836 | lldebugs << "connected" << llendl; | ||
837 | |||
838 | // We have connected, since the socket reader does not block, | ||
839 | // the first call to read data will return EAGAIN, so we need | ||
840 | // to write something. | ||
841 | chain.clear(); | ||
842 | chain.push_back(LLIOPipe::ptr_t(new LLPipeStringInjector("hi"))); | ||
843 | chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(client))); | ||
844 | chain.push_back(LLIOPipe::ptr_t(new LLIONull)); | ||
845 | mPump->addChain(chain, 1.0f); | ||
846 | |||
847 | // Now, the server should immediately send the data, but we'll | ||
848 | // never read it. pump for a bit | ||
849 | F32 elapsed = pump_loop(mPump, 2.0f); | ||
850 | ensure("Did not take too long", (elapsed < 3.0f)); | ||
851 | } | ||
852 | |||
853 | template<> template<> | ||
854 | void fitness_test_object::test<2>() | ||
855 | { | ||
856 | lldebugs << "fitness_test_object::test<2>()" << llendl; | ||
857 | |||
858 | // Set up the server | ||
859 | LLPumpIO::chain_t chain; | ||
860 | typedef LLCloneIOFactory<LLIOFuzz> emitter_t; | ||
861 | emitter_t* emitter = new emitter_t(new LLIOFuzz(1000000)); | ||
862 | boost::shared_ptr<LLChainIOFactory> factory(emitter); | ||
863 | LLIOServerSocket* server = new LLIOServerSocket( | ||
864 | mPool, | ||
865 | mSocket, | ||
866 | factory); | ||
867 | server->setResponseTimeout(SHORT_CHAIN_EXPIRY_SECS); | ||
868 | chain.push_back(LLIOPipe::ptr_t(server)); | ||
869 | mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS); | ||
870 | |||
871 | // We need to tickle the pump a little to set up the listen() | ||
872 | pump_loop(mPump, 0.1f); | ||
873 | |||
874 | // Set up the client | ||
875 | LLSocket::ptr_t client = LLSocket::create(mPool, LLSocket::STREAM_TCP); | ||
876 | LLHost server_host("127.0.0.1", SERVER_LISTEN_PORT); | ||
877 | bool connected = client->blockingConnect(server_host); | ||
878 | ensure("Connected to server", connected); | ||
879 | lldebugs << "connected" << llendl; | ||
880 | |||
881 | // We have connected, since the socket reader does not block, | ||
882 | // the first call to read data will return EAGAIN, so we need | ||
883 | // to write something. | ||
884 | chain.clear(); | ||
885 | chain.push_back(LLIOPipe::ptr_t(new LLPipeStringInjector("hi"))); | ||
886 | chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(client))); | ||
887 | chain.push_back(LLIOPipe::ptr_t(new LLIONull)); | ||
888 | mPump->addChain(chain, SHORT_CHAIN_EXPIRY_SECS / 2.0f); | ||
889 | |||
890 | // Now, the server should immediately send the data, but we'll | ||
891 | // never read it. pump for a bit | ||
892 | F32 elapsed = pump_loop(mPump, SHORT_CHAIN_EXPIRY_SECS * 2.0f); | ||
893 | ensure("Did not take too long", (elapsed < 3.0f)); | ||
894 | } | ||
895 | |||
896 | template<> template<> | ||
897 | void fitness_test_object::test<3>() | ||
898 | { | ||
899 | lldebugs << "fitness_test_object::test<3>()" << llendl; | ||
900 | |||
901 | // Set up the server | ||
902 | LLPumpIO::chain_t chain; | ||
903 | typedef LLCloneIOFactory<LLIOFuzz> emitter_t; | ||
904 | emitter_t* emitter = new emitter_t(new LLIOFuzz(1000000)); | ||
905 | boost::shared_ptr<LLChainIOFactory> factory(emitter); | ||
906 | LLIOServerSocket* server = new LLIOServerSocket( | ||
907 | mPool, | ||
908 | mSocket, | ||
909 | factory); | ||
910 | server->setResponseTimeout(SHORT_CHAIN_EXPIRY_SECS); | ||
911 | chain.push_back(LLIOPipe::ptr_t(server)); | ||
912 | mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS); | ||
913 | |||
914 | // We need to tickle the pump a little to set up the listen() | ||
915 | pump_loop(mPump, 0.1f); | ||
916 | |||
917 | // Set up the client | ||
918 | LLSocket::ptr_t client = LLSocket::create(mPool, LLSocket::STREAM_TCP); | ||
919 | LLHost server_host("127.0.0.1", SERVER_LISTEN_PORT); | ||
920 | bool connected = client->blockingConnect(server_host); | ||
921 | ensure("Connected to server", connected); | ||
922 | lldebugs << "connected" << llendl; | ||
923 | |||
924 | // We have connected, since the socket reader does not block, | ||
925 | // the first call to read data will return EAGAIN, so we need | ||
926 | // to write something. | ||
927 | chain.clear(); | ||
928 | chain.push_back(LLIOPipe::ptr_t(new LLPipeStringInjector("hi"))); | ||
929 | chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(client))); | ||
930 | chain.push_back(LLIOPipe::ptr_t(new LLIONull)); | ||
931 | mPump->addChain(chain, SHORT_CHAIN_EXPIRY_SECS * 2.0f); | ||
932 | |||
933 | // Now, the server should immediately send the data, but we'll | ||
934 | // never read it. pump for a bit | ||
935 | F32 elapsed = pump_loop(mPump, SHORT_CHAIN_EXPIRY_SECS * 2.0f + 1.0f); | ||
936 | ensure("Did not take too long", (elapsed < 4.0f)); | ||
937 | } | ||
938 | |||
939 | template<> template<> | ||
940 | void fitness_test_object::test<4>() | ||
941 | { | ||
942 | lldebugs << "fitness_test_object::test<4>()" << llendl; | ||
943 | |||
944 | // Set up the server | ||
945 | LLPumpIO::chain_t chain; | ||
946 | typedef LLCloneIOFactory<LLIOFuzz> emitter_t; | ||
947 | emitter_t* emitter = new emitter_t(new LLIOFuzz(1000000)); | ||
948 | boost::shared_ptr<LLChainIOFactory> factory(emitter); | ||
949 | LLIOServerSocket* server = new LLIOServerSocket( | ||
950 | mPool, | ||
951 | mSocket, | ||
952 | factory); | ||
953 | server->setResponseTimeout(SHORT_CHAIN_EXPIRY_SECS + 2.0f); | ||
954 | chain.push_back(LLIOPipe::ptr_t(server)); | ||
955 | mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS); | ||
956 | |||
957 | // We need to tickle the pump a little to set up the listen() | ||
958 | pump_loop(mPump, 0.1f); | ||
959 | |||
960 | // Set up the client | ||
961 | LLSocket::ptr_t client = LLSocket::create(mPool, LLSocket::STREAM_TCP); | ||
962 | LLHost server_host("127.0.0.1", SERVER_LISTEN_PORT); | ||
963 | bool connected = client->blockingConnect(server_host); | ||
964 | ensure("Connected to server", connected); | ||
965 | lldebugs << "connected" << llendl; | ||
966 | |||
967 | // We have connected, since the socket reader does not block, | ||
968 | // the first call to read data will return EAGAIN, so we need | ||
969 | // to write something. | ||
970 | chain.clear(); | ||
971 | chain.push_back(LLIOPipe::ptr_t(new LLPipeStringInjector("hi"))); | ||
972 | chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(client))); | ||
973 | chain.push_back(LLIOPipe::ptr_t(new LLIONull)); | ||
974 | mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS); | ||
975 | |||
976 | // Now, the server should immediately send the data, but we'll | ||
977 | // never read it. pump for a bit | ||
978 | F32 elapsed = pump_loop(mPump, SHORT_CHAIN_EXPIRY_SECS + 3.0f); | ||
979 | ensure("Did not take too long", (elapsed < DEFAULT_CHAIN_EXPIRY_SECS)); | ||
980 | } | ||
981 | } | ||
982 | |||
983 | namespace tut | ||
984 | { | ||
985 | struct rpc_server_data | ||
986 | { | ||
987 | class LLSimpleRPCResponse : public LLSDRPCResponse | ||
988 | { | ||
989 | public: | ||
990 | LLSimpleRPCResponse(LLSD* response) : | ||
991 | mResponsePtr(response) | ||
992 | { | ||
993 | } | ||
994 | ~LLSimpleRPCResponse() {} | ||
995 | virtual bool response(LLPumpIO* pump) | ||
996 | { | ||
997 | *mResponsePtr = mReturnValue; | ||
998 | return true; | ||
999 | } | ||
1000 | virtual bool fault(LLPumpIO* pump) | ||
1001 | { | ||
1002 | *mResponsePtr = mReturnValue; | ||
1003 | return false; | ||
1004 | } | ||
1005 | virtual bool error(LLPumpIO* pump) | ||
1006 | { | ||
1007 | ensure("LLSimpleRPCResponse::error()", false); | ||
1008 | return false; | ||
1009 | } | ||
1010 | public: | ||
1011 | LLSD* mResponsePtr; | ||
1012 | }; | ||
1013 | |||
1014 | class LLSimpleRPCClient : public LLSDRPCClient | ||
1015 | { | ||
1016 | public: | ||
1017 | LLSimpleRPCClient(LLSD* response) : | ||
1018 | mResponsePtr(response) | ||
1019 | { | ||
1020 | } | ||
1021 | ~LLSimpleRPCClient() {} | ||
1022 | void echo(const LLSD& parameter) | ||
1023 | { | ||
1024 | LLSimpleRPCResponse* resp; | ||
1025 | resp = new LLSimpleRPCResponse(mResponsePtr); | ||
1026 | static const std::string URI_NONE; | ||
1027 | static const std::string METHOD_ECHO("echo"); | ||
1028 | call(URI_NONE, METHOD_ECHO, parameter, resp, EPBQ_CALLBACK); | ||
1029 | } | ||
1030 | public: | ||
1031 | LLSD* mResponsePtr; | ||
1032 | }; | ||
1033 | |||
1034 | class LLSimpleRPCServer : public LLSDRPCServer | ||
1035 | { | ||
1036 | public: | ||
1037 | LLSimpleRPCServer() | ||
1038 | { | ||
1039 | mMethods["echo"] = new mem_fn_t( | ||
1040 | this, | ||
1041 | &LLSimpleRPCServer::rpc_Echo); | ||
1042 | } | ||
1043 | ~LLSimpleRPCServer() {} | ||
1044 | protected: | ||
1045 | typedef LLSDRPCMethodCall<LLSimpleRPCServer> mem_fn_t; | ||
1046 | ESDRPCSStatus rpc_Echo( | ||
1047 | const LLSD& parameter, | ||
1048 | const LLChannelDescriptors& channels, | ||
1049 | LLBufferArray* data) | ||
1050 | { | ||
1051 | buildResponse(channels, data, parameter); | ||
1052 | return ESDRPCS_DONE; | ||
1053 | } | ||
1054 | }; | ||
1055 | |||
1056 | apr_pool_t* mPool; | ||
1057 | LLPumpIO* mPump; | ||
1058 | LLPumpIO::chain_t mChain; | ||
1059 | LLSimpleRPCClient* mClient; | ||
1060 | LLSD mResponse; | ||
1061 | |||
1062 | rpc_server_data() : | ||
1063 | mPool(NULL), | ||
1064 | mPump(NULL), | ||
1065 | mClient(NULL) | ||
1066 | { | ||
1067 | apr_pool_create(&mPool, NULL); | ||
1068 | mPump = new LLPumpIO(mPool); | ||
1069 | mClient = new LLSimpleRPCClient(&mResponse); | ||
1070 | mChain.push_back(LLIOPipe::ptr_t(mClient)); | ||
1071 | mChain.push_back(LLIOPipe::ptr_t(new LLFilterSD2XMLRPCRequest)); | ||
1072 | mChain.push_back(LLIOPipe::ptr_t(new LLFilterXMLRPCRequest2LLSD)); | ||
1073 | mChain.push_back(LLIOPipe::ptr_t(new LLSimpleRPCServer)); | ||
1074 | mChain.push_back(LLIOPipe::ptr_t(new LLFilterSD2XMLRPCResponse)); | ||
1075 | mChain.push_back(LLIOPipe::ptr_t(new LLFilterXMLRPCResponse2LLSD)); | ||
1076 | mChain.push_back(LLIOPipe::ptr_t(mClient)); | ||
1077 | } | ||
1078 | ~rpc_server_data() | ||
1079 | { | ||
1080 | mChain.clear(); | ||
1081 | delete mPump; | ||
1082 | mPump = NULL; | ||
1083 | apr_pool_destroy(mPool); | ||
1084 | mPool = NULL; | ||
1085 | } | ||
1086 | void pump_loop(const LLSD& request) | ||
1087 | { | ||
1088 | LLTimer timer; | ||
1089 | timer.setTimerExpirySec(1.0f); | ||
1090 | mClient->echo(request); | ||
1091 | mPump->addChain(mChain, DEFAULT_CHAIN_EXPIRY_SECS); | ||
1092 | while(mResponse.isUndefined() && !timer.hasExpired()) | ||
1093 | { | ||
1094 | mPump->pump(); | ||
1095 | mPump->callback(); | ||
1096 | } | ||
1097 | } | ||
1098 | }; | ||
1099 | typedef test_group<rpc_server_data> rpc_server_test; | ||
1100 | typedef rpc_server_test::object rpc_server_object; | ||
1101 | tut::rpc_server_test rpc("rpc_server"); | ||
1102 | |||
1103 | template<> template<> | ||
1104 | void rpc_server_object::test<1>() | ||
1105 | { | ||
1106 | LLSD request; | ||
1107 | request = 1; | ||
1108 | pump_loop(request); | ||
1109 | //llinfos << "request: " << *request << llendl; | ||
1110 | //llinfos << "response: " << *mResponse << llendl; | ||
1111 | ensure_equals("integer request response", mResponse.asInteger(), 1); | ||
1112 | } | ||
1113 | |||
1114 | template<> template<> | ||
1115 | void rpc_server_object::test<2>() | ||
1116 | { | ||
1117 | 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"); | ||
1118 | std::stringstream stream; | ||
1119 | stream << "{'task_id':ucc706f2d-0b68-68f8-11a4-f1043ff35ca0}\n{\n\tname\tObject|\n\tpermissions 0\n}"; | ||
1120 | std::vector<U8> expected_binary; | ||
1121 | expected_binary.resize(stream.str().size()); | ||
1122 | memcpy(&expected_binary[0], stream.str().c_str(), stream.str().size()); | ||
1123 | stream.str(""); | ||
1124 | stream << "[{'uri':'" << uri << "'}, {'version':i1}, " | ||
1125 | << "{'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'], " | ||
1126 | << "'attachment_data':[" | ||
1127 | << "{'attachment_point':i2, 'item_id':'d6852c11-a74e-309a-0462-50533f1ef9b3', 'asset_id':'c69b29b1-8944-58ae-a7c5-2ca7b23e22fb'}," | ||
1128 | << "{'attachment_point':i10, 'item_id':'ff852c22-a74e-309a-0462-50533f1ef900', 'asset_data':b(" << expected_binary.size() << ")\""; | ||
1129 | stream.write((const char*)&expected_binary[0], expected_binary.size()); | ||
1130 | stream << "\"}" | ||
1131 | << "]" | ||
1132 | << "}]"; | ||
1133 | |||
1134 | LLSD request; | ||
1135 | S32 count = LLSDSerialize::fromNotation(request, stream); | ||
1136 | ensure("parsed something", (count > 0)); | ||
1137 | |||
1138 | pump_loop(request); | ||
1139 | ensure_equals("return type", mResponse.type(), LLSD::TypeArray); | ||
1140 | ensure_equals("return size", mResponse.size(), 3); | ||
1141 | |||
1142 | ensure_equals( | ||
1143 | "uri parameter type", | ||
1144 | mResponse[0].type(), | ||
1145 | LLSD::TypeMap); | ||
1146 | ensure_equals( | ||
1147 | "uri type", | ||
1148 | mResponse[0]["uri"].type(), | ||
1149 | LLSD::TypeString); | ||
1150 | ensure_equals("uri value", mResponse[0]["uri"].asString(), uri); | ||
1151 | |||
1152 | ensure_equals( | ||
1153 | "version parameter type", | ||
1154 | mResponse[1].type(), | ||
1155 | LLSD::TypeMap); | ||
1156 | ensure_equals( | ||
1157 | "version type", | ||
1158 | mResponse[1]["version"].type(), | ||
1159 | LLSD::TypeInteger); | ||
1160 | ensure_equals( | ||
1161 | "version value", | ||
1162 | mResponse[1]["version"].asInteger(), | ||
1163 | 1); | ||
1164 | |||
1165 | ensure_equals("agent params type", mResponse[2].type(), LLSD::TypeMap); | ||
1166 | LLSD attachment_data = mResponse[2]["attachment_data"]; | ||
1167 | ensure("attachment data exists", attachment_data.isDefined()); | ||
1168 | ensure_equals( | ||
1169 | "attachment type", | ||
1170 | attachment_data.type(), | ||
1171 | LLSD::TypeArray); | ||
1172 | ensure_equals( | ||
1173 | "attachment type 0", | ||
1174 | attachment_data[0].type(), | ||
1175 | LLSD::TypeMap); | ||
1176 | ensure_equals( | ||
1177 | "attachment type 1", | ||
1178 | attachment_data[1].type(), | ||
1179 | LLSD::TypeMap); | ||
1180 | ensure_equals("attachment size 1", attachment_data[1].size(), 3); | ||
1181 | ensure_equals( | ||
1182 | "asset data type", | ||
1183 | attachment_data[1]["asset_data"].type(), | ||
1184 | LLSD::TypeBinary); | ||
1185 | std::vector<U8> actual_binary; | ||
1186 | actual_binary = attachment_data[1]["asset_data"].asBinary(); | ||
1187 | ensure_equals( | ||
1188 | "binary data size", | ||
1189 | actual_binary.size(), | ||
1190 | expected_binary.size()); | ||
1191 | ensure( | ||
1192 | "binary data", | ||
1193 | (0 == memcmp( | ||
1194 | &actual_binary[0], | ||
1195 | &expected_binary[0], | ||
1196 | expected_binary.size()))); | ||
1197 | } | ||
1198 | |||
1199 | template<> template<> | ||
1200 | void rpc_server_object::test<3>() | ||
1201 | { | ||
1202 | 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"); | ||
1203 | |||
1204 | LLBufferArray buffer; | ||
1205 | LLChannelDescriptors buffer_channels = buffer.nextChannel(); | ||
1206 | LLBufferStream stream(buffer_channels, &buffer); | ||
1207 | stream << "[{'uri':'" << uri << "'}, {'version':i1}, " | ||
1208 | << "{'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'], " | ||
1209 | << "'attachment_data':[" | ||
1210 | << "{'attachment_point':i2, 'item_id':'d6852c11-a74e-309a-0462-50533f1ef9b3', 'asset_id':'c69b29b1-8944-58ae-a7c5-2ca7b23e22fb'},"; | ||
1211 | |||
1212 | std::stringstream tmp_str; | ||
1213 | tmp_str << "{'task_id':ucc706f2d-0b68-68f8-11a4-f1043ff35ca0}\n{\n\tname\tObject|\n\tpermissions 0\n}"; | ||
1214 | std::vector<U8> expected_binary; | ||
1215 | expected_binary.resize(tmp_str.str().size()); | ||
1216 | memcpy( | ||
1217 | &expected_binary[0], | ||
1218 | tmp_str.str().c_str(), | ||
1219 | tmp_str.str().size()); | ||
1220 | |||
1221 | LLBufferArray attachment_buffer; | ||
1222 | LLChannelDescriptors attach_channels = attachment_buffer.nextChannel(); | ||
1223 | LLBufferStream attach_stream(attach_channels, &attachment_buffer); | ||
1224 | attach_stream.write((const char*)&expected_binary[0], expected_binary.size()); | ||
1225 | attach_stream.flush(); | ||
1226 | S32 len = attachment_buffer.countAfter(attach_channels.out(), NULL); | ||
1227 | stream << "{'attachment_point':i10, 'item_id':'ff852c22-a74e-309a-0462-50533f1ef900', 'asset_data':b(" << len << ")\""; | ||
1228 | stream.flush(); | ||
1229 | buffer.takeContents(attachment_buffer); | ||
1230 | stream << "\"}]}]"; | ||
1231 | stream.flush(); | ||
1232 | |||
1233 | LLChannelDescriptors read_channel = buffer.nextChannel(); | ||
1234 | LLBufferStream read_stream(read_channel, &buffer); | ||
1235 | LLSD request; | ||
1236 | S32 count = LLSDSerialize::fromNotation(request, read_stream); | ||
1237 | ensure("parsed something", (count > 0)); | ||
1238 | ensure("deserialized", request.isDefined()); | ||
1239 | |||
1240 | // do the rpc round trip | ||
1241 | pump_loop(request); | ||
1242 | |||
1243 | ensure_equals("return type", mResponse.type(), LLSD::TypeArray); | ||
1244 | ensure_equals("return size", mResponse.size(), 3); | ||
1245 | |||
1246 | LLSD child = mResponse[0]; | ||
1247 | ensure("uri map exists", child.isDefined()); | ||
1248 | ensure_equals("uri parameter type", child.type(), LLSD::TypeMap); | ||
1249 | ensure("uri string exists", child.has("uri")); | ||
1250 | ensure_equals("uri type", child["uri"].type(), LLSD::TypeString); | ||
1251 | ensure_equals("uri value", child["uri"].asString(), uri); | ||
1252 | |||
1253 | child = mResponse[1]; | ||
1254 | ensure("version map exists", child.isDefined()); | ||
1255 | ensure_equals("version param type", child.type(), LLSD::TypeMap); | ||
1256 | ensure_equals( | ||
1257 | "version type", | ||
1258 | child["version"].type(), | ||
1259 | LLSD::TypeInteger); | ||
1260 | ensure_equals("version value", child["version"].asInteger(), 1); | ||
1261 | |||
1262 | child = mResponse[2]; | ||
1263 | ensure("agent params map exists", child.isDefined()); | ||
1264 | ensure_equals("agent params type", child.type(), LLSD::TypeMap); | ||
1265 | child = child["attachment_data"]; | ||
1266 | ensure("attachment data exists", child.isDefined()); | ||
1267 | ensure_equals("attachment type", child.type(), LLSD::TypeArray); | ||
1268 | LLSD attachment = child[0]; | ||
1269 | ensure_equals("attachment type 0", attachment.type(), LLSD::TypeMap); | ||
1270 | attachment = child[1]; | ||
1271 | ensure_equals("attachment type 1", attachment.type(), LLSD::TypeMap); | ||
1272 | ensure_equals("attachment size 1", attachment.size(), 3); | ||
1273 | ensure_equals( | ||
1274 | "asset data type", | ||
1275 | attachment["asset_data"].type(), | ||
1276 | LLSD::TypeBinary); | ||
1277 | std::vector<U8> actual_binary = attachment["asset_data"].asBinary(); | ||
1278 | ensure_equals( | ||
1279 | "binary data size", | ||
1280 | actual_binary.size(), | ||
1281 | expected_binary.size()); | ||
1282 | ensure( | ||
1283 | "binary data", | ||
1284 | (0 == memcmp( | ||
1285 | &actual_binary[0], | ||
1286 | &expected_binary[0], | ||
1287 | expected_binary.size()))); | ||
1288 | } | ||
1289 | |||
1290 | template<> template<> | ||
1291 | void rpc_server_object::test<4>() | ||
1292 | { | ||
1293 | std::string message("parcel '' is naughty."); | ||
1294 | std::stringstream str; | ||
1295 | str << "{'message':'" << LLSDNotationFormatter::escapeString(message) | ||
1296 | << "'}"; | ||
1297 | LLSD request; | ||
1298 | S32 count = LLSDSerialize::fromNotation(request, str); | ||
1299 | ensure_equals("parse count", count, 2); | ||
1300 | ensure_equals("request type", request.type(), LLSD::TypeMap); | ||
1301 | pump_loop(request); | ||
1302 | ensure("valid response", mResponse.isDefined()); | ||
1303 | ensure_equals("response type", mResponse.type(), LLSD::TypeMap); | ||
1304 | std::string actual = mResponse["message"].asString(); | ||
1305 | ensure_equals("message contents", actual, message); | ||
1306 | } | ||
1307 | |||
1308 | template<> template<> | ||
1309 | void rpc_server_object::test<5>() | ||
1310 | { | ||
1311 | // test some of the problem cases with llsdrpc over xmlrpc - | ||
1312 | // for example: | ||
1313 | // * arrays are auto-converted to parameter lists, thus, this | ||
1314 | // becomes one parameter. | ||
1315 | // * undef goes over the wire as false (this might not be a good idea) | ||
1316 | // * uuids are converted to string. | ||
1317 | std::string val = "[{'failures':!,'successfuls':[u3c115e51-04f4-523c-9fa6-98aff1034730]}]"; | ||
1318 | std::istringstream istr; | ||
1319 | istr.str(val); | ||
1320 | LLSD sd; | ||
1321 | LLSDSerialize::fromNotation(sd, istr); | ||
1322 | pump_loop(sd); | ||
1323 | ensure("valid response", mResponse.isDefined()); | ||
1324 | ensure_equals("parsed type", mResponse.type(), LLSD::TypeMap); | ||
1325 | ensure_equals("parsed size", mResponse.size(), 2); | ||
1326 | LLSD failures = mResponse["failures"]; | ||
1327 | ensure_equals("no failures.", failures.asBoolean(), false); | ||
1328 | LLSD success = mResponse["successfuls"]; | ||
1329 | ensure_equals("success type", success.type(), LLSD::TypeArray); | ||
1330 | ensure_equals("success size", success.size(), 1); | ||
1331 | ensure_equals( | ||
1332 | "success instance type", | ||
1333 | success[0].type(), | ||
1334 | LLSD::TypeString); | ||
1335 | } | ||
1336 | |||
1337 | /* | ||
1338 | template<> template<> | ||
1339 | void rpc_server_object::test<5>() | ||
1340 | { | ||
1341 | std::string expected("\xf3");//\xffsomething"); | ||
1342 | LLSD* request = LLSD::createString(expected); | ||
1343 | pump_loop(request); | ||
1344 | std::string actual; | ||
1345 | mResponse->getString(actual); | ||
1346 | if(actual != expected) | ||
1347 | { | ||
1348 | //llwarns << "iteration " << i << llendl; | ||
1349 | std::ostringstream e_str; | ||
1350 | std::string::iterator iter = expected.begin(); | ||
1351 | std::string::iterator end = expected.end(); | ||
1352 | for(; iter != end; ++iter) | ||
1353 | { | ||
1354 | e_str << (S32)((U8)(*iter)) << " "; | ||
1355 | } | ||
1356 | e_str << std::endl; | ||
1357 | llsd_serialize_string(e_str, expected); | ||
1358 | llwarns << "expected size: " << expected.size() << llendl; | ||
1359 | llwarns << "expected: " << e_str.str() << llendl; | ||
1360 | |||
1361 | std::ostringstream a_str; | ||
1362 | iter = actual.begin(); | ||
1363 | end = actual.end(); | ||
1364 | for(; iter != end; ++iter) | ||
1365 | { | ||
1366 | a_str << (S32)((U8)(*iter)) << " "; | ||
1367 | } | ||
1368 | a_str << std::endl; | ||
1369 | llsd_serialize_string(a_str, actual); | ||
1370 | llwarns << "actual size: " << actual.size() << llendl; | ||
1371 | llwarns << "actual: " << a_str.str() << llendl; | ||
1372 | } | ||
1373 | ensure_equals("binary string request response", actual, expected); | ||
1374 | delete request; | ||
1375 | } | ||
1376 | |||
1377 | template<> template<> | ||
1378 | void rpc_server_object::test<5>() | ||
1379 | { | ||
1380 | } | ||
1381 | */ | ||
1382 | } | ||
1383 | |||
1384 | |||
1385 | /* | ||
1386 | '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" | ||
1387 | */ | ||