PageRenderTime 132ms CodeModel.GetById 12ms app.highlight 108ms RepoModel.GetById 1ms app.codeStats 1ms

/indra/test/io.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1597 lines | 1285 code | 118 blank | 194 comment | 18 complexity | 9f244e082b7266502a853b67c4f227e5 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

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

Large files files are truncated, but you can click here to view the full file