PageRenderTime 121ms CodeModel.GetById 15ms app.highlight 96ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llmessage/llcircuit.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1412 lines | 1009 code | 214 blank | 189 comment | 141 complexity | a21a61a51bb26413ae388c4bf5bad65c MD5 | raw file
   1/** 
   2 * @file llcircuit.cpp
   3 * @brief Class to track UDP endpoints for the message system.
   4 *
   5 * $LicenseInfo:firstyear=2002&license=viewerlgpl$
   6 * Second Life Viewer Source Code
   7 * Copyright (C) 2010, Linden Research, Inc.
   8 * 
   9 * This library is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU Lesser General Public
  11 * License as published by the Free Software Foundation;
  12 * version 2.1 of the License only.
  13 * 
  14 * This library is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * Lesser General Public License for more details.
  18 * 
  19 * You should have received a copy of the GNU Lesser General Public
  20 * License along with this library; if not, write to the Free Software
  21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  22 * 
  23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  24 * $/LicenseInfo$
  25 */
  26
  27#include "linden_common.h"
  28 
  29#if LL_WINDOWS
  30
  31#include <process.h>
  32
  33#else
  34
  35#if LL_LINUX
  36#include <dlfcn.h>		// RTLD_LAZY
  37#endif
  38#include <sys/types.h>
  39#include <sys/socket.h>
  40#include <netinet/in.h>
  41
  42#endif
  43
  44
  45#if !defined(USE_CIRCUIT_LIST)
  46#include <algorithm>
  47#endif
  48#include <sstream>
  49#include <iterator>
  50#include <stack>
  51
  52#include "llcircuit.h"
  53
  54#include "message.h"
  55#include "llrand.h"
  56#include "llstl.h"
  57#include "lltransfermanager.h"
  58#include "llmodularmath.h"
  59
  60const S32 PING_START_BLOCK = 3;		// How many pings behind we have to be to consider ourself blocked.
  61const S32 PING_RELEASE_BLOCK = 2;	// How many pings behind we have to be to consider ourself unblocked.
  62
  63const F32 TARGET_PERIOD_LENGTH = 5.f;	// seconds
  64const F32 LL_DUPLICATE_SUPPRESSION_TIMEOUT = 60.f; //seconds - this can be long, as time-based cleanup is
  65													// only done when wrapping packetids, now...
  66
  67LLCircuitData::LLCircuitData(const LLHost &host, TPACKETID in_id, 
  68							 const F32 circuit_heartbeat_interval, const F32 circuit_timeout)
  69:	mHost (host),
  70	mWrapID(0),
  71	mPacketsOutID(0), 
  72	mPacketsInID(in_id),
  73	mHighestPacketID(in_id),
  74	mTimeoutCallback(NULL),
  75	mTimeoutUserData(NULL),
  76	mTrusted(FALSE),
  77	mbAllowTimeout(TRUE),
  78	mbAlive(TRUE),
  79	mBlocked(FALSE),
  80	mPingTime(0.0),
  81	mLastPingSendTime(0.0),
  82	mLastPingReceivedTime(0.0),
  83	mNextPingSendTime(0.0),
  84	mPingsInTransit(0),
  85	mLastPingID(0),
  86	mPingDelay(INITIAL_PING_VALUE_MSEC), 
  87	mPingDelayAveraged((F32)INITIAL_PING_VALUE_MSEC), 
  88	mUnackedPacketCount(0),
  89	mUnackedPacketBytes(0),
  90	mLastPacketInTime(0.0),
  91	mLocalEndPointID(),
  92	mPacketsOut(0),
  93	mPacketsIn(0), 
  94	mPacketsLost(0),
  95	mBytesIn(0),
  96	mBytesOut(0),
  97	mLastPeriodLength(-1.f),
  98	mBytesInLastPeriod(0),
  99	mBytesOutLastPeriod(0),
 100	mBytesInThisPeriod(0),
 101	mBytesOutThisPeriod(0),
 102	mPeakBPSIn(0.f),
 103	mPeakBPSOut(0.f),
 104	mPeriodTime(0.0),
 105	mExistenceTimer(),
 106	mCurrentResendCount(0),
 107	mLastPacketGap(0),
 108	mHeartbeatInterval(circuit_heartbeat_interval), 
 109	mHeartbeatTimeout(circuit_timeout)
 110{
 111	// Need to guarantee that this time is up to date, we may be creating a circuit even though we haven't been
 112	//  running a message system loop.
 113	F64 mt_sec = LLMessageSystem::getMessageTimeSeconds(TRUE);
 114	F32 distribution_offset = ll_frand();
 115	
 116	mPingTime = mt_sec;
 117	mLastPingSendTime = mt_sec + mHeartbeatInterval * distribution_offset;
 118	mLastPingReceivedTime = mt_sec;
 119	mNextPingSendTime = mLastPingSendTime + 0.95*mHeartbeatInterval + ll_frand(0.1f*mHeartbeatInterval);
 120	mPeriodTime = mt_sec;
 121
 122	mLocalEndPointID.generate();
 123}
 124
 125
 126LLCircuitData::~LLCircuitData()
 127{
 128	LLReliablePacket *packetp = NULL;
 129
 130	// Clean up all pending transfers.
 131	gTransferManager.cleanupConnection(mHost);
 132
 133	// remove all pending reliable messages on this circuit
 134	std::vector<TPACKETID> doomed;
 135	reliable_iter iter;
 136	reliable_iter end = mUnackedPackets.end();
 137	for(iter = mUnackedPackets.begin(); iter != end; ++iter)
 138	{
 139		packetp = iter->second;
 140		gMessageSystem->mFailedResendPackets++;
 141		if(gMessageSystem->mVerboseLog)
 142		{
 143			doomed.push_back(packetp->mPacketID);
 144		}
 145		if (packetp->mCallback)
 146		{
 147			packetp->mCallback(packetp->mCallbackData,LL_ERR_CIRCUIT_GONE);
 148		}
 149
 150		// Update stats
 151		mUnackedPacketCount--;
 152		mUnackedPacketBytes -= packetp->mBufferLength;
 153
 154		delete packetp;
 155	}
 156
 157	// remove all pending final retry reliable messages on this circuit
 158	end = mFinalRetryPackets.end();
 159	for(iter = mFinalRetryPackets.begin(); iter != end; ++iter)
 160	{
 161		packetp = iter->second;
 162		gMessageSystem->mFailedResendPackets++;
 163		if(gMessageSystem->mVerboseLog)
 164		{
 165			doomed.push_back(packetp->mPacketID);
 166		}
 167		if (packetp->mCallback)
 168		{
 169			packetp->mCallback(packetp->mCallbackData,LL_ERR_CIRCUIT_GONE);
 170		}
 171
 172		// Update stats
 173		mUnackedPacketCount--;
 174		mUnackedPacketBytes -= packetp->mBufferLength;
 175
 176		delete packetp;
 177	}
 178
 179	// log aborted reliable packets for this circuit.
 180	if(gMessageSystem->mVerboseLog && !doomed.empty())
 181	{
 182		std::ostringstream str;
 183		std::ostream_iterator<TPACKETID> append(str, " ");
 184		str << "MSG: -> " << mHost << "\tABORTING RELIABLE:\t";
 185		std::copy(doomed.begin(), doomed.end(), append);
 186		llinfos << str.str() << llendl;
 187	}
 188}
 189
 190
 191void LLCircuitData::ackReliablePacket(TPACKETID packet_num)
 192{
 193	reliable_iter iter;
 194	LLReliablePacket *packetp;
 195
 196	iter = mUnackedPackets.find(packet_num);
 197	if (iter != mUnackedPackets.end())
 198	{
 199		packetp = iter->second;
 200
 201		if(gMessageSystem->mVerboseLog)
 202		{
 203			std::ostringstream str;
 204			str << "MSG: <- " << packetp->mHost << "\tRELIABLE ACKED:\t"
 205				<< packetp->mPacketID;
 206			llinfos << str.str() << llendl;
 207		}
 208		if (packetp->mCallback)
 209		{
 210			if (packetp->mTimeout < 0.f)   // negative timeout will always return timeout even for successful ack, for debugging
 211			{
 212				packetp->mCallback(packetp->mCallbackData,LL_ERR_TCP_TIMEOUT);					
 213			}
 214			else
 215			{
 216				packetp->mCallback(packetp->mCallbackData,LL_ERR_NOERR);
 217			}
 218		}
 219
 220		// Update stats
 221		mUnackedPacketCount--;
 222		mUnackedPacketBytes -= packetp->mBufferLength;
 223
 224		// Cleanup
 225		delete packetp;
 226		mUnackedPackets.erase(iter);
 227		return;
 228	}
 229
 230	iter = mFinalRetryPackets.find(packet_num);
 231	if (iter != mFinalRetryPackets.end())
 232	{
 233		packetp = iter->second;
 234		// llinfos << "Packet " << packet_num << " removed from the pending list" << llendl;
 235		if(gMessageSystem->mVerboseLog)
 236		{
 237			std::ostringstream str;
 238			str << "MSG: <- " << packetp->mHost << "\tRELIABLE ACKED:\t"
 239				<< packetp->mPacketID;
 240			llinfos << str.str() << llendl;
 241		}
 242		if (packetp->mCallback)
 243		{
 244			if (packetp->mTimeout < 0.f)   // negative timeout will always return timeout even for successful ack, for debugging
 245			{
 246				packetp->mCallback(packetp->mCallbackData,LL_ERR_TCP_TIMEOUT);					
 247			}
 248			else
 249			{
 250				packetp->mCallback(packetp->mCallbackData,LL_ERR_NOERR);
 251			}
 252		}
 253
 254		// Update stats
 255		mUnackedPacketCount--;
 256		mUnackedPacketBytes -= packetp->mBufferLength;
 257
 258		// Cleanup
 259		delete packetp;
 260		mFinalRetryPackets.erase(iter);
 261	}
 262	else
 263	{
 264		// Couldn't find this packet on either of the unacked lists.
 265		// maybe it's a duplicate ack?
 266	}
 267}
 268
 269
 270
 271S32 LLCircuitData::resendUnackedPackets(const F64 now)
 272{
 273	S32 resent_packets = 0;
 274	LLReliablePacket *packetp;
 275
 276
 277	//
 278	// Theoretically we should search through the list for the packet with the oldest
 279	// packet ID, as otherwise when we WRAP we will resend reliable packets out of order.
 280	// Since resends are ALREADY out of order, and wrapping is highly rare (16+million packets),
 281	// I'm not going to worry about this for now - djs
 282	//
 283
 284	reliable_iter iter;
 285	BOOL have_resend_overflow = FALSE;
 286	for (iter = mUnackedPackets.begin(); iter != mUnackedPackets.end();)
 287	{
 288		packetp = iter->second;
 289
 290		// Only check overflow if we haven't had one yet.
 291		if (!have_resend_overflow)
 292		{
 293			have_resend_overflow = mThrottles.checkOverflow(TC_RESEND, 0);
 294		}
 295
 296		if (have_resend_overflow)
 297		{
 298			// We've exceeded our bandwidth for resends.
 299			// Time to stop trying to send them.
 300
 301			// If we have too many unacked packets, we need to start dropping expired ones.
 302			if (mUnackedPacketBytes > 512000)
 303			{
 304				if (now > packetp->mExpirationTime)
 305				{
 306					// This circuit has overflowed.  Do not retry.  Do not pass go.
 307					packetp->mRetries = 0;
 308					// Remove it from this list and add it to the final list.
 309					mUnackedPackets.erase(iter++);
 310					mFinalRetryPackets[packetp->mPacketID] = packetp;
 311				}
 312				else
 313				{
 314					++iter;
 315				}
 316				// Move on to the next unacked packet.
 317				continue;
 318			}
 319			
 320			if (mUnackedPacketBytes > 256000 && !(getPacketsOut() % 1024))
 321			{
 322				// Warn if we've got a lot of resends waiting.
 323				llwarns << mHost << " has " << mUnackedPacketBytes 
 324						<< " bytes of reliable messages waiting" << llendl;
 325			}
 326			// Stop resending.  There are less than 512000 unacked packets.
 327			break;
 328		}
 329
 330		if (now > packetp->mExpirationTime)
 331		{
 332			packetp->mRetries--;
 333			
 334			// retry		
 335			mCurrentResendCount++;
 336
 337			gMessageSystem->mResentPackets++;
 338
 339			if(gMessageSystem->mVerboseLog)
 340			{
 341				std::ostringstream str;
 342				str << "MSG: -> " << packetp->mHost
 343					<< "\tRESENDING RELIABLE:\t" << packetp->mPacketID;
 344				llinfos << str.str() << llendl;
 345			}
 346
 347			packetp->mBuffer[0] |= LL_RESENT_FLAG;  // tag packet id as being a resend	
 348
 349			gMessageSystem->mPacketRing.sendPacket(packetp->mSocket, 
 350											   (char *)packetp->mBuffer, packetp->mBufferLength, 
 351											   packetp->mHost);
 352
 353			mThrottles.throttleOverflow(TC_RESEND, packetp->mBufferLength * 8.f);
 354
 355			// The new method, retry time based on ping
 356			if (packetp->mPingBasedRetry)
 357			{
 358				packetp->mExpirationTime = now + llmax(LL_MINIMUM_RELIABLE_TIMEOUT_SECONDS, (LL_RELIABLE_TIMEOUT_FACTOR * getPingDelayAveraged()));
 359			}
 360			else
 361			{
 362				// custom, constant retry time
 363				packetp->mExpirationTime = now + packetp->mTimeout;
 364			}
 365
 366			if (!packetp->mRetries)
 367			{
 368				// Last resend, remove it from this list and add it to the final list.
 369				mUnackedPackets.erase(iter++);
 370				mFinalRetryPackets[packetp->mPacketID] = packetp;
 371			}
 372			else
 373			{
 374				// Don't remove it yet, it still gets to try to resend at least once.
 375				++iter;
 376			}
 377			resent_packets++;
 378		}
 379		else
 380		{
 381			// Don't need to do anything with this packet, keep iterating.
 382			++iter;
 383		}
 384	}
 385
 386
 387	for (iter = mFinalRetryPackets.begin(); iter != mFinalRetryPackets.end();)
 388	{
 389		packetp = iter->second;
 390		if (now > packetp->mExpirationTime)
 391		{
 392			// fail (too many retries)
 393			//llinfos << "Packet " << packetp->mPacketID << " removed from the pending list: exceeded retry limit" << llendl;
 394			//if (packetp->mMessageName)
 395			//{
 396			//	llinfos << "Packet name " << packetp->mMessageName << llendl;
 397			//}
 398			gMessageSystem->mFailedResendPackets++;
 399
 400			if(gMessageSystem->mVerboseLog)
 401			{
 402				std::ostringstream str;
 403				str << "MSG: -> " << packetp->mHost << "\tABORTING RELIABLE:\t"
 404					<< packetp->mPacketID;
 405				llinfos << str.str() << llendl;
 406			}
 407
 408			if (packetp->mCallback)
 409			{
 410				packetp->mCallback(packetp->mCallbackData,LL_ERR_TCP_TIMEOUT);
 411			}
 412
 413			// Update stats
 414			mUnackedPacketCount--;
 415			mUnackedPacketBytes -= packetp->mBufferLength;
 416
 417			mFinalRetryPackets.erase(iter++);
 418			delete packetp;
 419		}
 420		else
 421		{
 422			++iter;
 423		}
 424	}
 425
 426	return mUnackedPacketCount;
 427}
 428
 429
 430LLCircuit::LLCircuit(const F32 circuit_heartbeat_interval, const F32 circuit_timeout) : mLastCircuit(NULL),  
 431	mHeartbeatInterval(circuit_heartbeat_interval), mHeartbeatTimeout(circuit_timeout)
 432{
 433}
 434
 435LLCircuit::~LLCircuit()
 436{
 437	// delete pointers in the map.
 438	std::for_each(mCircuitData.begin(),
 439				  mCircuitData.end(),
 440				  llcompose1(
 441					  DeletePointerFunctor<LLCircuitData>(),
 442					  llselect2nd<circuit_data_map::value_type>()));
 443}
 444
 445LLCircuitData *LLCircuit::addCircuitData(const LLHost &host, TPACKETID in_id)
 446{
 447	// This should really validate if one already exists
 448	llinfos << "LLCircuit::addCircuitData for " << host << llendl;
 449	LLCircuitData *tempp = new LLCircuitData(host, in_id, mHeartbeatInterval, mHeartbeatTimeout);
 450	mCircuitData.insert(circuit_data_map::value_type(host, tempp));
 451	mPingSet.insert(tempp);
 452
 453	mLastCircuit = tempp;
 454	return tempp;
 455}
 456
 457void LLCircuit::removeCircuitData(const LLHost &host)
 458{
 459	llinfos << "LLCircuit::removeCircuitData for " << host << llendl;
 460	mLastCircuit = NULL;
 461	circuit_data_map::iterator it = mCircuitData.find(host);
 462	if(it != mCircuitData.end())
 463	{
 464		LLCircuitData *cdp = it->second;
 465		mCircuitData.erase(it);
 466
 467		LLCircuit::ping_set_t::iterator psit = mPingSet.find(cdp);
 468		if (psit != mPingSet.end())
 469        {
 470		    mPingSet.erase(psit);
 471		}
 472		else
 473		{
 474			llwarns << "Couldn't find entry for next ping in ping set!" << llendl;
 475		}
 476
 477		// Clean up from optimization maps
 478		mUnackedCircuitMap.erase(host);
 479		mSendAckMap.erase(host);
 480		delete cdp;
 481	}
 482
 483	// This also has to happen AFTER we nuke the circuit, because various
 484	// callbacks for the circuit may result in messages being sent to
 485	// this circuit, and the setting of mLastCircuit.  We don't check
 486	// if the host matches, but we don't really care because mLastCircuit
 487	// is an optimization, and this happens VERY rarely.
 488	mLastCircuit = NULL;
 489}
 490
 491void LLCircuitData::setAlive(BOOL b_alive)
 492{
 493	if (mbAlive != b_alive)
 494	{
 495		mPacketsOutID = 0;
 496		mPacketsInID = 0;
 497		mbAlive = b_alive;
 498	}
 499	if (b_alive)
 500	{
 501		mLastPingReceivedTime = LLMessageSystem::getMessageTimeSeconds();
 502		mPingsInTransit = 0;
 503		mBlocked = FALSE;
 504	}
 505}
 506
 507
 508void LLCircuitData::setAllowTimeout(BOOL allow)
 509{
 510	mbAllowTimeout = allow;
 511
 512	if (allow)
 513	{
 514		// resuming circuit
 515		// make sure it's alive
 516		setAlive(TRUE);
 517	}
 518}
 519
 520
 521// Reset per-period counters if necessary.
 522void LLCircuitData::checkPeriodTime()
 523{
 524	F64 mt_sec = LLMessageSystem::getMessageTimeSeconds();
 525	F64 period_length = mt_sec - mPeriodTime;
 526	if ( period_length > TARGET_PERIOD_LENGTH)
 527	{
 528		F32 bps_in = (F32)(mBytesInThisPeriod * 8.f / period_length);
 529		if (bps_in > mPeakBPSIn)
 530		{
 531			mPeakBPSIn = bps_in;
 532		}
 533
 534		F32 bps_out = (F32)(mBytesOutThisPeriod * 8.f / period_length);
 535		if (bps_out > mPeakBPSOut)
 536		{
 537			mPeakBPSOut = bps_out;
 538		}
 539
 540		mBytesInLastPeriod	= mBytesInThisPeriod;
 541		mBytesOutLastPeriod	= mBytesOutThisPeriod;
 542		mBytesInThisPeriod	= 0;
 543		mBytesOutThisPeriod	= 0;
 544		mLastPeriodLength	= (F32)period_length;
 545
 546		mPeriodTime = mt_sec;
 547	}
 548}
 549
 550
 551void LLCircuitData::addBytesIn(S32 bytes)
 552{
 553	mBytesIn += bytes;
 554	mBytesInThisPeriod += bytes;
 555}
 556
 557
 558void LLCircuitData::addBytesOut(S32 bytes)
 559{
 560	mBytesOut += bytes;
 561	mBytesOutThisPeriod += bytes;
 562}
 563
 564
 565void LLCircuitData::addReliablePacket(S32 mSocket, U8 *buf_ptr, S32 buf_len, LLReliablePacketParams *params)
 566{
 567	LLReliablePacket *packet_info;
 568
 569	packet_info = new LLReliablePacket(mSocket, buf_ptr, buf_len, params);
 570
 571	mUnackedPacketCount++;
 572	mUnackedPacketBytes += packet_info->mBufferLength;
 573
 574	if (params && params->mRetries)
 575	{
 576		mUnackedPackets[packet_info->mPacketID] = packet_info;
 577	}
 578	else
 579	{
 580		mFinalRetryPackets[packet_info->mPacketID] = packet_info;
 581	}
 582}
 583
 584
 585void LLCircuit::resendUnackedPackets(S32& unacked_list_length, S32& unacked_list_size)
 586{
 587	F64 now = LLMessageSystem::getMessageTimeSeconds();
 588	unacked_list_length = 0;
 589	unacked_list_size = 0;
 590
 591	LLCircuitData* circ;
 592	circuit_data_map::iterator end = mUnackedCircuitMap.end();
 593	for(circuit_data_map::iterator it = mUnackedCircuitMap.begin(); it != end; ++it)
 594	{
 595		circ = (*it).second;
 596		unacked_list_length += circ->resendUnackedPackets(now);
 597		unacked_list_size += circ->getUnackedPacketBytes();
 598	}
 599}
 600
 601
 602BOOL LLCircuitData::isDuplicateResend(TPACKETID packetnum)
 603{
 604	return (mRecentlyReceivedReliablePackets.find(packetnum) != mRecentlyReceivedReliablePackets.end());
 605}
 606
 607
 608void LLCircuit::dumpResends()
 609{
 610	circuit_data_map::iterator end = mCircuitData.end();
 611	for(circuit_data_map::iterator it = mCircuitData.begin(); it != end; ++it)
 612	{
 613		(*it).second->dumpResendCountAndReset();
 614	}
 615}
 616
 617LLCircuitData* LLCircuit::findCircuit(const LLHost& host) const
 618{
 619	// An optimization on finding the previously found circuit.
 620	if (mLastCircuit && (mLastCircuit->mHost == host))
 621	{
 622		return mLastCircuit;
 623	}
 624
 625	circuit_data_map::const_iterator it = mCircuitData.find(host);
 626	if(it == mCircuitData.end())
 627	{
 628		return NULL;
 629	}
 630	mLastCircuit = it->second;
 631	return mLastCircuit;
 632}
 633
 634
 635BOOL LLCircuit::isCircuitAlive(const LLHost& host) const
 636{
 637	LLCircuitData *cdp = findCircuit(host);
 638	if(cdp)
 639	{
 640		return cdp->mbAlive;
 641	}
 642
 643	return FALSE;
 644}
 645
 646void LLCircuitData::setTimeoutCallback(void (*callback_func)(const LLHost &host, void *user_data), void *user_data)
 647{
 648	mTimeoutCallback = callback_func;
 649	mTimeoutUserData = user_data; 
 650}
 651
 652void LLCircuitData::checkPacketInID(TPACKETID id, BOOL receive_resent)
 653{
 654	// Done as floats so we don't have to worry about running out of room
 655	// with U32 getting poked into an S32.
 656	F32 delta = (F32)mHighestPacketID - (F32)id;
 657	if (delta > (0.5f*LL_MAX_OUT_PACKET_ID))
 658	{
 659		// We've almost definitely wrapped, reset the mLastPacketID to be low again.
 660		mHighestPacketID = id;
 661	}
 662	else if (delta < (-0.5f*LL_MAX_OUT_PACKET_ID))
 663	{
 664		// This is almost definitely an old packet coming in after a wrap, ignore it.
 665	}
 666	else
 667	{
 668		mHighestPacketID = llmax(mHighestPacketID, id);
 669	}
 670
 671	// Save packet arrival time
 672	mLastPacketInTime = LLMessageSystem::getMessageTimeSeconds();
 673
 674	// Have we received anything on this circuit yet?
 675	if (0 == mPacketsIn)
 676	{
 677		// Must be first packet from unclosed circuit.
 678		mPacketsIn++;
 679		setPacketInID((id + 1) % LL_MAX_OUT_PACKET_ID);
 680
 681        mLastPacketGap = 0;
 682        mOutOfOrderRate.count(0);
 683		return;
 684	}
 685
 686	mPacketsIn++;
 687
 688
 689	// now, check to see if we've got a gap
 690    U32 gap = 0;
 691	if ((mPacketsInID == id))
 692	{
 693		// nope! bump and wrap the counter, then return
 694		mPacketsInID++;
 695		mPacketsInID = (mPacketsInID) % LL_MAX_OUT_PACKET_ID;
 696	}
 697	else if (id < mWrapID)
 698	{
 699		// id < mWrapID will happen if the first few packets are out of order. . . 
 700		// at that point we haven't marked anything "potentially lost" and 
 701		// the out-of-order packet will cause a full wrap marking all the IDs "potentially lost"
 702
 703		// do nothing
 704	}
 705	else
 706	{
 707		// we have a gap!  if that id is in the map, remove it from the map, leave mCurrentCircuit->mPacketsInID
 708		// alone
 709		// otherwise, walk from mCurrentCircuit->mPacketsInID to id with wrapping, adding the values to the map
 710		// and setting mPacketsInID to id + 1 % LL_MAX_OUT_PACKET_ID
 711
 712        // babbage: all operands in expression are unsigned, so modular 
 713		// arithmetic will always find correct gap, regardless of wrap arounds.
 714		const U8 width = 24;
 715		gap = LLModularMath::subtract<width>(mPacketsInID, id);
 716
 717		if (mPotentialLostPackets.find(id) != mPotentialLostPackets.end())
 718		{
 719			if(gMessageSystem->mVerboseLog)
 720			{
 721				std::ostringstream str;
 722				str << "MSG: <- " << mHost << "\tRECOVERING LOST:\t" << id;
 723				llinfos << str.str() << llendl;
 724			}
 725			//			llinfos << "removing potential lost: " << id << llendl;
 726			mPotentialLostPackets.erase(id);
 727		}
 728		else if (!receive_resent) // don't freak out over out-of-order reliable resends
 729		{
 730			U64 time = LLMessageSystem::getMessageTimeUsecs();
 731			TPACKETID index = mPacketsInID;
 732			S32 gap_count = 0;
 733			if ((index < id) && ((id - index) < 16))
 734			{
 735				while (index != id)
 736				{
 737					if(gMessageSystem->mVerboseLog)
 738					{
 739						std::ostringstream str;
 740						str << "MSG: <- " << mHost << "\tPACKET GAP:\t"
 741							<< index;
 742						llinfos << str.str() << llendl;
 743					}
 744
 745//						llinfos << "adding potential lost: " << index << llendl;
 746					mPotentialLostPackets[index] = time;
 747					index++;
 748					index = index % LL_MAX_OUT_PACKET_ID;
 749					gap_count++;
 750				}
 751			}
 752			else
 753			{
 754				llinfos << "packet_out_of_order - got packet " << id << " expecting " << index << " from " << mHost << llendl;
 755				if(gMessageSystem->mVerboseLog)
 756				{
 757					std::ostringstream str;
 758					str << "MSG: <- " << mHost << "\tPACKET GAP:\t"
 759						<< id << " expected " << index;
 760					llinfos << str.str() << llendl;
 761				}
 762			}
 763				
 764			mPacketsInID = id + 1;
 765			mPacketsInID = (mPacketsInID) % LL_MAX_OUT_PACKET_ID;
 766
 767			if (gap_count > 128)
 768			{
 769				llwarns << "Packet loss gap filler running amok!" << llendl;
 770			}
 771			else if (gap_count > 16)
 772			{
 773				llwarns << "Sustaining large amounts of packet loss!" << llendl;
 774			}
 775
 776		}
 777	}
 778    mOutOfOrderRate.count(gap);
 779    mLastPacketGap = gap;
 780}
 781
 782
 783void LLCircuit::updateWatchDogTimers(LLMessageSystem *msgsys)
 784{
 785	F64 cur_time = LLMessageSystem::getMessageTimeSeconds();
 786	S32 count = mPingSet.size();
 787	S32 cur = 0;
 788
 789	// Only process each circuit once at most, stop processing if no circuits
 790	while((cur < count) && !mPingSet.empty())
 791	{
 792		cur++;
 793
 794		LLCircuit::ping_set_t::iterator psit = mPingSet.begin();
 795		LLCircuitData *cdp = *psit;
 796
 797		if (!cdp->mbAlive)
 798		{
 799			// We suspect that this case should never happen, given how
 800			// the alive status is set.
 801			// Skip over dead circuits, just add the ping interval and push it to the back
 802			// Always remember to remove it from the set before changing the sorting
 803			// key (mNextPingSendTime)
 804			mPingSet.erase(psit);
 805			cdp->mNextPingSendTime = cur_time + mHeartbeatInterval;
 806			mPingSet.insert(cdp);
 807			continue;
 808		}
 809		else
 810		{
 811			// Check to see if this needs a ping
 812			if (cur_time < cdp->mNextPingSendTime)
 813			{
 814				// This circuit doesn't need a ping, break out because
 815				// we have a sorted list, thus no more circuits need pings
 816				break;
 817			}
 818
 819			// Update watchdog timers
 820			if (cdp->updateWatchDogTimers(msgsys))
 821            {
 822				// Randomize our pings a bit by doing some up to 5% early or late
 823				F64 dt = 0.95f*mHeartbeatInterval + ll_frand(0.1f*mHeartbeatInterval);
 824
 825				// Remove it, and reinsert it with the new next ping time.
 826				// Always remove before changing the sorting key.
 827				mPingSet.erase(psit);
 828				cdp->mNextPingSendTime = cur_time + dt;
 829				mPingSet.insert(cdp);
 830    
 831			    // Update our throttles
 832			    cdp->mThrottles.dynamicAdjust();
 833    
 834			    // Update some stats, this is not terribly important
 835			    cdp->checkPeriodTime();
 836			}
 837			else
 838			{
 839				// This mPingSet.erase isn't necessary, because removing the circuit will
 840				// remove the ping set.
 841				//mPingSet.erase(psit);
 842				removeCircuitData(cdp->mHost);
 843			}
 844		}
 845	}
 846}
 847
 848
 849BOOL LLCircuitData::updateWatchDogTimers(LLMessageSystem *msgsys)
 850{
 851	F64 cur_time = LLMessageSystem::getMessageTimeSeconds();
 852	mLastPingSendTime = cur_time;
 853
 854	if (!checkCircuitTimeout())
 855	{
 856		// Pass this back to the calling LLCircuit, this circuit needs to be cleaned up.
 857		return FALSE;
 858	}
 859
 860	// WARNING!
 861	// Duplicate suppression can FAIL if packets are delivered out of
 862	// order, although it's EXTREMELY unlikely.  It would require
 863	// that the ping get delivered out of order enough that the ACK
 864	// for the packet that it was out of order with was received BEFORE
 865	// the ping was sent.
 866
 867	// Find the current oldest reliable packetID
 868	// This is to handle the case if we actually manage to wrap our
 869	// packet IDs - the oldest will actually have a higher packet ID
 870	// than the current.
 871	BOOL wrapped = FALSE;
 872	reliable_iter iter;
 873	iter = mUnackedPackets.upper_bound(getPacketOutID());
 874	if (iter == mUnackedPackets.end())
 875	{
 876		// Nothing AFTER this one, so we want the lowest packet ID
 877		// then.
 878		iter = mUnackedPackets.begin();
 879		wrapped = TRUE;
 880	}
 881
 882	TPACKETID packet_id = 0;
 883
 884	// Check against the "final" packets
 885	BOOL wrapped_final = FALSE;
 886	reliable_iter iter_final;
 887	iter_final = mFinalRetryPackets.upper_bound(getPacketOutID());
 888	if (iter_final == mFinalRetryPackets.end())
 889	{
 890		iter_final = mFinalRetryPackets.begin();
 891		wrapped_final = TRUE;
 892	}
 893
 894	//llinfos << mHost << " - unacked count " << mUnackedPackets.size() << llendl;
 895	//llinfos << mHost << " - final count " << mFinalRetryPackets.size() << llendl;
 896	if (wrapped != wrapped_final)
 897	{
 898		// One of the "unacked" or "final" lists hasn't wrapped.  Whichever one
 899		// hasn't has the oldest packet.
 900		if (!wrapped)
 901		{
 902			// Hasn't wrapped, so the one on the
 903			// unacked packet list is older
 904			packet_id = iter->first;
 905			//llinfos << mHost << ": nowrapped unacked" << llendl;
 906		}
 907		else
 908		{
 909			packet_id = iter_final->first;
 910			//llinfos << mHost << ": nowrapped final" << llendl;
 911		}
 912	}
 913	else
 914	{
 915		// They both wrapped, we can just use the minimum of the two.
 916		if ((iter == mUnackedPackets.end()) && (iter_final == mFinalRetryPackets.end()))
 917		{
 918			// Wow!  No unacked packets at all!
 919			// Send the ID of the last packet we sent out.
 920			// This will flush all of the destination's
 921			// unacked packets, theoretically.
 922			//llinfos << mHost << ": No unacked!" << llendl;
 923			packet_id = getPacketOutID();
 924		}
 925		else
 926		{
 927			BOOL had_unacked = FALSE;
 928			if (iter != mUnackedPackets.end())
 929			{
 930				// Unacked list has the lowest so far
 931				packet_id = iter->first;
 932				had_unacked = TRUE;
 933				//llinfos << mHost << ": Unacked" << llendl;
 934			}
 935
 936			if (iter_final != mFinalRetryPackets.end())
 937			{
 938				// Use the lowest of the unacked list and the final list
 939				if (had_unacked)
 940				{
 941					// Both had a packet, use the lowest.
 942					packet_id = llmin(packet_id, iter_final->first);
 943					//llinfos << mHost << ": Min of unacked/final" << llendl;
 944				}
 945				else
 946				{
 947					// Only the final had a packet, use it.
 948					packet_id = iter_final->first;
 949					//llinfos << mHost << ": Final!" << llendl;
 950				}
 951			}
 952		}
 953	}
 954
 955	// Send off the another ping.
 956	pingTimerStart();
 957	msgsys->newMessageFast(_PREHASH_StartPingCheck);
 958	msgsys->nextBlock(_PREHASH_PingID);
 959	msgsys->addU8Fast(_PREHASH_PingID, nextPingID());
 960	msgsys->addU32Fast(_PREHASH_OldestUnacked, packet_id);
 961	msgsys->sendMessage(mHost);
 962
 963	// Also do lost packet accounting.
 964	// Check to see if anything on our lost list is old enough to
 965	// be considered lost
 966
 967	LLCircuitData::packet_time_map::iterator it;
 968	U64 timeout = (U64)(1000000.0*llmin(LL_MAX_LOST_TIMEOUT, getPingDelayAveraged() * LL_LOST_TIMEOUT_FACTOR));
 969
 970	U64 mt_usec = LLMessageSystem::getMessageTimeUsecs();
 971	for (it = mPotentialLostPackets.begin(); it != mPotentialLostPackets.end(); )
 972	{
 973		U64 delta_t_usec = mt_usec - (*it).second;
 974		if (delta_t_usec > timeout)
 975		{
 976			// let's call this one a loss!
 977			mPacketsLost++;
 978			gMessageSystem->mDroppedPackets++;
 979			if(gMessageSystem->mVerboseLog)
 980			{
 981				std::ostringstream str;
 982				str << "MSG: <- " << mHost << "\tLOST PACKET:\t"
 983					<< (*it).first;
 984				llinfos << str.str() << llendl;
 985			}
 986			mPotentialLostPackets.erase(it++);
 987		}
 988		else
 989		{
 990			++it;
 991		}
 992	}
 993
 994	return TRUE;
 995}
 996
 997
 998void LLCircuitData::clearDuplicateList(TPACKETID oldest_id)
 999{
1000	// purge old data from the duplicate suppression queue
1001
1002	// we want to KEEP all x where oldest_id <= x <= last incoming packet, and delete everything else.
1003
1004	//llinfos << mHost << ": clearing before oldest " << oldest_id << llendl;
1005	//llinfos << "Recent list before: " << mRecentlyReceivedReliablePackets.size() << llendl;
1006	if (oldest_id < mHighestPacketID)
1007	{
1008		// Clean up everything with a packet ID less than oldest_id.
1009		packet_time_map::iterator pit_start;
1010		packet_time_map::iterator pit_end;
1011		pit_start = mRecentlyReceivedReliablePackets.begin();
1012		pit_end = mRecentlyReceivedReliablePackets.lower_bound(oldest_id);
1013		mRecentlyReceivedReliablePackets.erase(pit_start, pit_end);
1014	}
1015
1016	// Do timeout checks on everything with an ID > mHighestPacketID.
1017	// This should be empty except for wrapping IDs.  Thus, this should be
1018	// highly rare.
1019	U64 mt_usec = LLMessageSystem::getMessageTimeUsecs();
1020
1021	packet_time_map::iterator pit;
1022	for(pit = mRecentlyReceivedReliablePackets.upper_bound(mHighestPacketID);
1023		pit != mRecentlyReceivedReliablePackets.end(); )
1024	{
1025		// Validate that the packet ID seems far enough away
1026		if ((pit->first - mHighestPacketID) < 100)
1027		{
1028			llwarns << "Probably incorrectly timing out non-wrapped packets!" << llendl;
1029		}
1030		U64 delta_t_usec = mt_usec - (*pit).second;
1031		F64 delta_t_sec = delta_t_usec * SEC_PER_USEC;
1032		if (delta_t_sec > LL_DUPLICATE_SUPPRESSION_TIMEOUT)
1033		{
1034			// enough time has elapsed we're not likely to get a duplicate on this one
1035			llinfos << "Clearing " << pit->first << " from recent list" << llendl;
1036			mRecentlyReceivedReliablePackets.erase(pit++);
1037		}
1038		else
1039		{
1040			++pit;
1041		}
1042	}
1043	//llinfos << "Recent list after: " << mRecentlyReceivedReliablePackets.size() << llendl;
1044}
1045
1046BOOL LLCircuitData::checkCircuitTimeout()
1047{
1048	F64 time_since_last_ping = LLMessageSystem::getMessageTimeSeconds() - mLastPingReceivedTime;
1049
1050	// Nota Bene: This needs to be turned off if you are debugging multiple simulators
1051	if (time_since_last_ping > mHeartbeatTimeout)
1052	{
1053		llwarns << "LLCircuitData::checkCircuitTimeout for " << mHost << " last ping " << time_since_last_ping << " seconds ago." <<llendl;
1054		setAlive(FALSE);
1055		if (mTimeoutCallback)
1056		{
1057			llwarns << "LLCircuitData::checkCircuitTimeout for " << mHost << " calling callback." << llendl;
1058			mTimeoutCallback(mHost, mTimeoutUserData);
1059		}
1060		if (!isAlive())
1061		{
1062			// The callback didn't try and resurrect the circuit.  We should kill it.
1063			llwarns << "LLCircuitData::checkCircuitTimeout for " << mHost << " still dead, dropping." << llendl;
1064			return FALSE;
1065		}
1066	}
1067
1068	return TRUE;
1069}
1070
1071// Call this method when a reliable message comes in - this will
1072// correctly place the packet in the correct list to be acked later.
1073BOOL LLCircuitData::collectRAck(TPACKETID packet_num)
1074{
1075	if (mAcks.empty())
1076	{
1077		// First extra ack, we need to add ourselves to the list of circuits that need to send acks
1078		gMessageSystem->mCircuitInfo.mSendAckMap[mHost] = this;
1079	}
1080
1081	mAcks.push_back(packet_num);
1082	return TRUE;
1083}
1084
1085// this method is called during the message system processAcks() to
1086// send out any acks that did not get sent already.
1087void LLCircuit::sendAcks()
1088{
1089	LLCircuitData* cd;
1090	circuit_data_map::iterator end = mSendAckMap.end();
1091	for(circuit_data_map::iterator it = mSendAckMap.begin(); it != end; ++it)
1092	{
1093		cd = (*it).second;
1094
1095		S32 count = (S32)cd->mAcks.size();
1096		if(count > 0)
1097		{
1098			// send the packet acks
1099			S32 acks_this_packet = 0;
1100			for(S32 i = 0; i < count; ++i)
1101			{
1102				if(acks_this_packet == 0)
1103				{
1104					gMessageSystem->newMessageFast(_PREHASH_PacketAck);
1105				}
1106				gMessageSystem->nextBlockFast(_PREHASH_Packets);
1107				gMessageSystem->addU32Fast(_PREHASH_ID, cd->mAcks[i]);
1108				++acks_this_packet;
1109				if(acks_this_packet > 250)
1110				{
1111					gMessageSystem->sendMessage(cd->mHost);
1112					acks_this_packet = 0;
1113				}
1114			}
1115			if(acks_this_packet > 0)
1116			{
1117				gMessageSystem->sendMessage(cd->mHost);
1118			}
1119
1120			if(gMessageSystem->mVerboseLog)
1121			{
1122				std::ostringstream str;
1123				str << "MSG: -> " << cd->mHost << "\tPACKET ACKS:\t";
1124				std::ostream_iterator<TPACKETID> append(str, " ");
1125				std::copy(cd->mAcks.begin(), cd->mAcks.end(), append);
1126				llinfos << str.str() << llendl;
1127			}
1128
1129			// empty out the acks list
1130			cd->mAcks.clear();
1131		}
1132	}
1133
1134	// All acks have been sent, clear the map
1135	mSendAckMap.clear();
1136}
1137
1138
1139std::ostream& operator<<(std::ostream& s, LLCircuitData& circuit)
1140{
1141	F32 age = circuit.mExistenceTimer.getElapsedTimeF32();
1142
1143	using namespace std;
1144	s << "Circuit " << circuit.mHost << " ";
1145	s << circuit.mRemoteID << " ";
1146	s << (circuit.mbAlive ? "Alive" : "Not Alive") << " ";
1147	s << (circuit.mbAllowTimeout ? "Timeout Allowed" : "Timeout Not Allowed");
1148	s << endl;
1149
1150	s << " Packets Lost: " << circuit.mPacketsLost;
1151	s << " Measured Ping: " << circuit.mPingDelay;
1152	s << " Averaged Ping: " << circuit.mPingDelayAveraged;
1153	s << endl;
1154
1155	s << "Global In/Out " << S32(age) << " sec";
1156	s << " KBytes: " << circuit.mBytesIn / 1024 << "/" << circuit.mBytesOut / 1024;
1157	s << " Kbps: ";
1158	s << S32(circuit.mBytesIn * 8.f / circuit.mExistenceTimer.getElapsedTimeF32() / 1024.f);
1159	s << "/";
1160	s << S32(circuit.mBytesOut * 8.f / circuit.mExistenceTimer.getElapsedTimeF32() / 1024.f);
1161	s << " Packets: " << circuit.mPacketsIn << "/" << circuit.mPacketsOut;
1162	s << endl;
1163
1164	s << "Recent In/Out   " << S32(circuit.mLastPeriodLength) << " sec";
1165	s << " KBytes: ";
1166	s << circuit.mBytesInLastPeriod / 1024;
1167	s << "/";
1168	s << circuit.mBytesOutLastPeriod / 1024;
1169	s << " Kbps: ";
1170	s << S32(circuit.mBytesInLastPeriod * 8.f / circuit.mLastPeriodLength / 1024.f);
1171	s << "/";
1172	s << S32(circuit.mBytesOutLastPeriod * 8.f / circuit.mLastPeriodLength / 1024.f);
1173	s << " Peak kbps: ";
1174	s << S32(circuit.mPeakBPSIn / 1024.f);
1175	s << "/";
1176	s << S32(circuit.mPeakBPSOut / 1024.f);
1177	s << endl;
1178
1179	return s;
1180}
1181
1182void LLCircuitData::getInfo(LLSD& info) const
1183{
1184	info["Host"] = mHost.getIPandPort();
1185	info["Alive"] = mbAlive;
1186	info["Age"] = mExistenceTimer.getElapsedTimeF32();
1187}
1188
1189void LLCircuitData::dumpResendCountAndReset()
1190{
1191	if (mCurrentResendCount)
1192	{
1193		llinfos << "Circuit: " << mHost << " resent " << mCurrentResendCount << " packets" << llendl;
1194		mCurrentResendCount = 0;
1195	}
1196}
1197
1198std::ostream& operator<<(std::ostream& s, LLCircuit &circuit)
1199{
1200	s << "Circuit Info:" << std::endl;
1201	LLCircuit::circuit_data_map::iterator end = circuit.mCircuitData.end();
1202	LLCircuit::circuit_data_map::iterator it;
1203	for(it = circuit.mCircuitData.begin(); it != end; ++it)
1204	{
1205		s << *((*it).second) << std::endl;
1206	}
1207	return s;
1208}
1209
1210void LLCircuit::getInfo(LLSD& info) const
1211{
1212	LLCircuit::circuit_data_map::const_iterator end = mCircuitData.end();
1213	LLCircuit::circuit_data_map::const_iterator it;
1214	LLSD circuit_info;
1215	for(it = mCircuitData.begin(); it != end; ++it)
1216	{
1217		(*it).second->getInfo(circuit_info);
1218		info["Circuits"].append(circuit_info);
1219	}
1220}
1221
1222void LLCircuit::getCircuitRange(
1223	const LLHost& key,
1224	LLCircuit::circuit_data_map::iterator& first,
1225	LLCircuit::circuit_data_map::iterator& end)
1226{
1227	end = mCircuitData.end();
1228	first = mCircuitData.upper_bound(key);
1229}
1230
1231TPACKETID LLCircuitData::nextPacketOutID()
1232{
1233	mPacketsOut++;
1234	
1235	TPACKETID id; 
1236
1237	id = (mPacketsOutID + 1) % LL_MAX_OUT_PACKET_ID;
1238			
1239	if (id < mPacketsOutID)
1240	{
1241		// we just wrapped on a circuit, reset the wrap ID to zero
1242		mWrapID = 0;
1243	}
1244	mPacketsOutID = id;
1245	return id;
1246}
1247
1248
1249void LLCircuitData::setPacketInID(TPACKETID id)
1250{
1251	id = id % LL_MAX_OUT_PACKET_ID;
1252	mPacketsInID = id;
1253	mRecentlyReceivedReliablePackets.clear();
1254
1255	mWrapID = id;
1256}
1257
1258
1259void LLCircuitData::pingTimerStop(const U8 ping_id)
1260{
1261	F64 mt_secs = LLMessageSystem::getMessageTimeSeconds();
1262
1263	// Nota Bene: no averaging of ping times until we get a feel for how this works
1264	F64 time = mt_secs - mPingTime;
1265	if (time == 0.0)
1266	{
1267		// Ack, we got our ping response on the same frame! Sigh, let's get a real time otherwise
1268		// all of our ping calculations will be skewed.
1269		mt_secs = LLMessageSystem::getMessageTimeSeconds(TRUE);
1270	}
1271	mLastPingReceivedTime = mt_secs;
1272
1273	// If ping is longer than 1 second, we'll get sequence deltas in the ping.
1274	// Approximate by assuming each ping counts for 1 second (slightly low, probably)
1275	S32 delta_ping = (S32)mLastPingID - (S32) ping_id;
1276	if (delta_ping < 0)
1277	{
1278		delta_ping += 256;
1279	}
1280
1281	U32 msec = (U32) ((delta_ping*mHeartbeatInterval  + time) * 1000.f);
1282	setPingDelay(msec);
1283
1284	mPingsInTransit = delta_ping;
1285	if (mBlocked && (mPingsInTransit <= PING_RELEASE_BLOCK))
1286	{
1287		mBlocked = FALSE;
1288	}
1289}
1290
1291
1292void LLCircuitData::pingTimerStart()
1293{
1294	mPingTime = LLMessageSystem::getMessageTimeSeconds();
1295	mPingsInTransit++;
1296
1297	if (!mBlocked && (mPingsInTransit > PING_START_BLOCK))
1298	{
1299		mBlocked = TRUE;
1300	}
1301}
1302
1303
1304U32 LLCircuitData::getPacketsIn() const
1305{
1306	return mPacketsIn;
1307}
1308
1309
1310S32 LLCircuitData::getBytesIn() const
1311{
1312	return mBytesIn;
1313}
1314
1315
1316S32 LLCircuitData::getBytesOut() const
1317{
1318	return mBytesOut;
1319}
1320
1321
1322U32 LLCircuitData::getPacketsOut() const
1323{
1324	return mPacketsOut;
1325}
1326
1327
1328TPACKETID LLCircuitData::getPacketOutID() const
1329{
1330	return mPacketsOutID;
1331}
1332
1333
1334U32 LLCircuitData::getPacketsLost() const
1335{
1336	return mPacketsLost;
1337}
1338
1339
1340BOOL LLCircuitData::isAlive() const
1341{
1342	return mbAlive;
1343}
1344
1345
1346BOOL LLCircuitData::isBlocked() const
1347{
1348	return mBlocked;
1349}
1350
1351
1352BOOL LLCircuitData::getAllowTimeout() const
1353{
1354	return mbAllowTimeout;
1355}
1356
1357
1358U32 LLCircuitData::getPingDelay() const
1359{
1360	return mPingDelay;
1361}
1362
1363
1364F32 LLCircuitData::getPingInTransitTime()
1365{
1366	// This may be inaccurate in the case of a circuit that was "dead" and then revived,
1367	// but only until the first round trip ping is sent - djs
1368	F32 time_since_ping_was_sent = 0;
1369
1370	if (mPingsInTransit)
1371	{
1372		time_since_ping_was_sent =  (F32)((mPingsInTransit*mHeartbeatInterval - 1) 
1373			+ (LLMessageSystem::getMessageTimeSeconds() - mPingTime))*1000.f;
1374	}
1375
1376	return time_since_ping_was_sent;
1377}
1378
1379
1380void LLCircuitData::setPingDelay(U32 ping)
1381{
1382	mPingDelay = ping;
1383	mPingDelayAveraged = llmax((F32)ping, getPingDelayAveraged());
1384	mPingDelayAveraged = ((1.f - LL_AVERAGED_PING_ALPHA) * mPingDelayAveraged) 
1385						  + (LL_AVERAGED_PING_ALPHA * (F32) ping);
1386	mPingDelayAveraged = llclamp(mPingDelayAveraged, 
1387								 LL_AVERAGED_PING_MIN,
1388								 LL_AVERAGED_PING_MAX);
1389}
1390
1391
1392F32 LLCircuitData::getPingDelayAveraged()
1393{
1394	return llmin(llmax(getPingInTransitTime(), mPingDelayAveraged), LL_AVERAGED_PING_MAX);
1395}
1396
1397
1398BOOL LLCircuitData::getTrusted() const
1399{
1400	return mTrusted;
1401}
1402
1403
1404void LLCircuitData::setTrusted(BOOL t)
1405{
1406	mTrusted = t;
1407}
1408
1409F32 LLCircuitData::getAgeInSeconds() const
1410{
1411	return mExistenceTimer.getElapsedTimeF32();
1412}