// this method is called during the message system processAcks() to
// send out any acks that did not get sent already.
void LLCircuit::sendAcks(F32 collect_time)
{
	collect_time = llclamp(collect_time, 0.f, LL_COLLECT_ACK_TIME_MAX);
	LLCircuitData* cd;
	circuit_data_map::iterator it = mSendAckMap.begin();
	while (it != mSendAckMap.end())
	{
		circuit_data_map::iterator cur_it = it++;
		cd = (*cur_it).second;
		S32 count = (S32)cd->mAcks.size();
		F32 age = cd->getAgeInSeconds() - cd->mAckCreationTime;
		if (age > collect_time || count == 0)
		{
			if (count>0)
			{
				// send the packet acks
				S32 acks_this_packet = 0;
				for(S32 i = 0; i < count; ++i)
				{
					if(acks_this_packet == 0)
					{
						gMessageSystem->newMessageFast(_PREHASH_PacketAck);
					}
					gMessageSystem->nextBlockFast(_PREHASH_Packets);
					gMessageSystem->addU32Fast(_PREHASH_ID, cd->mAcks[i]);
					++acks_this_packet;
					if(acks_this_packet > 250)
					{
						gMessageSystem->sendMessage(cd->mHost);
						acks_this_packet = 0;
					}
				}
				if(acks_this_packet > 0)
				{
					gMessageSystem->sendMessage(cd->mHost);
				}

				if(gMessageSystem->mVerboseLog)
				{
					std::ostringstream str;
					str << "MSG: -> " << cd->mHost << "\tPACKET ACKS:\t";
					std::ostream_iterator<TPACKETID> append(str, " ");
					std::copy(cd->mAcks.begin(), cd->mAcks.end(), append);
					LL_INFOS() << str.str() << LL_ENDL;
				}

				// empty out the acks list
				cd->mAcks.clear();
				cd->mAckCreationTime = 0.f;
			}
			// remove data map
			mSendAckMap.erase(cur_it);
		}
	}
}
// static
BOOL LLFloaterMessageLog::onClickCloseCircuit(void* user_data)
{
	LLNetListItem* itemp = (LLNetListItem*)user_data;
	LLCircuitData* cdp = (LLCircuitData*)itemp->mCircuitData;
	if(!cdp) return FALSE;
	LLHost myhost = cdp->getHost();
	LLSD args;
	args["MESSAGE"] = "This will delete local circuit data.\nDo you want to tell the remote host to close the circuit too?";
	LLSD payload;
	payload["circuittoclose"] = myhost.getString(); 
	LLNotificationsUtil::add("GenericAlertYesCancel", args, payload, onConfirmCloseCircuit);
	return TRUE;
}
U32 LLViewerRegion::getPacketsLost() const
{
	LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mHost);
	if (!cdp)
	{
		llinfos << "LLViewerRegion::getPacketsLost couldn't find circuit for " << mHost << llendl;
		return 0;
	}
	else
	{
		return cdp->getPacketsLost();
	}
}
Example #4
0
void LLCircuit::resendUnackedPackets(S32& unacked_list_length, S32& unacked_list_size)
{
	F64 now = LLMessageSystem::getMessageTimeSeconds();
	unacked_list_length = 0;
	unacked_list_size = 0;

	LLCircuitData* circ;
	circuit_data_map::iterator end = mUnackedCircuitMap.end();
	for(circuit_data_map::iterator it = mUnackedCircuitMap.begin(); it != end; ++it)
	{
		circ = (*it).second;
		unacked_list_length += circ->resendUnackedPackets(now);
		unacked_list_size += circ->getUnackedPacketBytes();
	}
}
Example #5
0
void LLWorld::printPacketsLost()
{
	llinfos << "Simulators:" << llendl;
	llinfos << "----------" << llendl;

	LLCircuitData *cdp = NULL;
	for (region_list_t::iterator iter = mActiveRegionList.begin();
		 iter != mActiveRegionList.end(); ++iter)
	{
		LLViewerRegion* regionp = *iter;
		cdp = gMessageSystem->mCircuitInfo.findCircuit(regionp->getHost());
		if (cdp)
		{
			LLVector3d range = regionp->getCenterGlobal() - gAgent.getPositionGlobal();
				
			llinfos << regionp->getHost() << ", range: " << range.length()
					<< " packets lost: " << cdp->getPacketsLost() << llendl;
		}
	}
}
// static
bool LLFloaterMessageLog::onConfirmCloseCircuit(const LLSD& notification, const LLSD& response )
{
	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
	LLCircuitData* cdp = gMessageSystem->mCircuitInfo.findCircuit(LLHost(notification["payload"]["circuittoclose"].asString()));
	if(!cdp) return false;
	LLViewerRegion* regionp = LLWorld::getInstance()->getRegion(cdp->getHost());
	switch(option)
	{
	case 0: // yes
		gMessageSystem->newMessageFast(_PREHASH_CloseCircuit);
		gMessageSystem->sendReliable(cdp->getHost());
		break;
	case 2: // cancel
		return false;
		break;
	case 1: // no
	default:
		break;
	}
	if(gMessageSystem->findCircuitCode(cdp->getHost()))
		gMessageSystem->disableCircuit(cdp->getHost());
	else
		gMessageSystem->mCircuitInfo.removeCircuitData(cdp->getHost());
	if(regionp)
	{
		LLHost myhost = regionp->getHost();
		LLSD args;
		args["MESSAGE"] = "That host had a region associated with it.\nDo you want to clean that up?";
		LLSD payload;
		payload["regionhost"] = myhost.getString();
		LLNotificationsUtil::add("GenericAlertYesCancel", args, payload, onConfirmRemoveRegion);
	}
	return false;
}
Example #7
0
void LLViewerRegion::updateNetStats()
{
	F32 dt = mLastNetUpdate.getElapsedTimeAndResetF32();

	LLCircuitData *cdp = LLMessageSystem::getInstance()->mCircuitInfo.findCircuit( m_host );
	if (!cdp)
	{
		mAlive = false;
		return;
	}

	mAlive = true;
	mDeltaTime = dt;

	mLastPacketsIn =	mPacketsIn;
	mLastBitsIn =		mBitsIn;
	mLastPacketsOut =	mPacketsOut;
	mLastPacketsLost =	mPacketsLost;

	mPacketsIn =				cdp->getPacketsIn();
	mBitsIn =					8 * cdp->getBytesIn();
	mPacketsOut =				cdp->getPacketsOut();
	mPacketsLost =				cdp->getPacketsLost();
	mPingDelay =				cdp->getPingDelay();

	mBitStat.addValue(mBitsIn - mLastBitsIn);
	mPacketsStat.addValue(mPacketsIn - mLastPacketsIn);
	mPacketsLostStat.addValue(mPacketsLost);
}
Example #8
0
void update_statistics(U32 frame_count)
{
	gTotalWorldBytes += gVLManager.getTotalBytes();
	gTotalObjectBytes += gObjectBits / 8;

	// make sure we have a valid time delta for this frame
	if (gFrameIntervalSeconds > 0.f)
	{
		if (gAgent.getCameraMode() == CAMERA_MODE_MOUSELOOK)
		{
			LLViewerStats::getInstance()->incStat(LLViewerStats::ST_MOUSELOOK_SECONDS, gFrameIntervalSeconds);
		}
		else if (gAgent.getCameraMode() == CAMERA_MODE_CUSTOMIZE_AVATAR)
		{
			LLViewerStats::getInstance()->incStat(LLViewerStats::ST_AVATAR_EDIT_SECONDS, gFrameIntervalSeconds);
		}
		else if (gFloaterTools && gFloaterTools->getVisible())
		{
			LLViewerStats::getInstance()->incStat(LLViewerStats::ST_TOOLBOX_SECONDS, gFrameIntervalSeconds);
		}
	}
	LLViewerStats::getInstance()->setStat(LLViewerStats::ST_ENABLE_VBO, (F64)gSavedSettings.getBOOL("RenderVBOEnable"));
	LLViewerStats::getInstance()->setStat(LLViewerStats::ST_LIGHTING_DETAIL, (F64)gSavedSettings.getS32("RenderLightingDetail"));
	LLViewerStats::getInstance()->setStat(LLViewerStats::ST_DRAW_DIST, (F64)gSavedSettings.getF32("RenderFarClip"));
	LLViewerStats::getInstance()->setStat(LLViewerStats::ST_CHAT_BUBBLES, (F64)gSavedSettings.getBOOL("UseChatBubbles"));
#if 0 // 1.9.2
	LLViewerStats::getInstance()->setStat(LLViewerStats::ST_SHADER_OBJECTS, (F64)gSavedSettings.getS32("VertexShaderLevelObject"));
	LLViewerStats::getInstance()->setStat(LLViewerStats::ST_SHADER_AVATAR, (F64)gSavedSettings.getBOOL("VertexShaderLevelAvatar"));
	LLViewerStats::getInstance()->setStat(LLViewerStats::ST_SHADER_ENVIRONMENT, (F64)gSavedSettings.getBOOL("VertexShaderLevelEnvironment"));
#endif
	LLViewerStats::getInstance()->setStat(LLViewerStats::ST_FRAME_SECS, gDebugView->mFastTimerView->getTime(LLFastTimer::FTM_FRAME));
	F64 idle_secs = gDebugView->mFastTimerView->getTime(LLFastTimer::FTM_IDLE);
	F64 network_secs = gDebugView->mFastTimerView->getTime(LLFastTimer::FTM_NETWORK);
	LLViewerStats::getInstance()->setStat(LLViewerStats::ST_UPDATE_SECS, idle_secs - network_secs);
	LLViewerStats::getInstance()->setStat(LLViewerStats::ST_NETWORK_SECS, network_secs);
	LLViewerStats::getInstance()->setStat(LLViewerStats::ST_IMAGE_SECS, gDebugView->mFastTimerView->getTime(LLFastTimer::FTM_IMAGE_UPDATE));
	LLViewerStats::getInstance()->setStat(LLViewerStats::ST_REBUILD_SECS, gDebugView->mFastTimerView->getTime(LLFastTimer::FTM_STATESORT ));
	LLViewerStats::getInstance()->setStat(LLViewerStats::ST_RENDER_SECS, gDebugView->mFastTimerView->getTime(LLFastTimer::FTM_RENDER_GEOMETRY));
		
	LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(gAgent.getRegion()->getHost());
	if (cdp)
	{
		LLViewerStats::getInstance()->mSimPingStat.addValue(cdp->getPingDelay());
		gAvgSimPing = ((gAvgSimPing * (F32)gSimPingCount) + (F32)(cdp->getPingDelay())) / ((F32)gSimPingCount + 1);
		gSimPingCount++;
	}
	else
	{
		LLViewerStats::getInstance()->mSimPingStat.addValue(10000);
	}

	LLViewerStats::getInstance()->mFPSStat.addValue(1);
	F32 layer_bits = (F32)(gVLManager.getLandBits() + gVLManager.getWindBits() + gVLManager.getCloudBits());
	LLViewerStats::getInstance()->mLayersKBitStat.addValue(layer_bits/1024.f);
	LLViewerStats::getInstance()->mObjectKBitStat.addValue(gObjectBits/1024.f);
	LLViewerStats::getInstance()->mVFSPendingOperations.addValue(LLVFile::getVFSThread()->getPending());
	LLViewerStats::getInstance()->mAssetKBitStat.addValue(gTransferManager.getTransferBitsIn(LLTCT_ASSET)/1024.f);
	gTransferManager.resetTransferBitsIn(LLTCT_ASSET);

	if (LLAppViewer::getTextureFetch()->getNumRequests() == 0)
	{
		gDebugTimers[0].pause();
	}
	else
	{
		gDebugTimers[0].unpause();
	}
	
	{
		static F32 visible_avatar_frames = 0.f;
		static F32 avg_visible_avatars = 0;
		F32 visible_avatars = (F32)LLVOAvatar::sNumVisibleAvatars;
		if (visible_avatars > 0.f)
		{
			visible_avatar_frames = 1.f;
			avg_visible_avatars = (avg_visible_avatars * (F32)(visible_avatar_frames - 1.f) + visible_avatars) / visible_avatar_frames;
		}
		LLViewerStats::getInstance()->setStat(LLViewerStats::ST_VISIBLE_AVATARS, (F64)avg_visible_avatars);
	}
	LLWorld::getInstance()->updateNetStats();
	LLWorld::getInstance()->requestCacheMisses();
	
	// Reset all of these values.
	gVLManager.resetBitCounts();
	gObjectBits = 0;
//	gDecodedBits = 0;

	// Only update texture stats ones per second so that they are less noisy
	{
		static const F32 texture_stats_freq = 1.f;
		static LLFrameTimer texture_stats_timer;
		if (texture_stats_timer.getElapsedTimeF32() >= texture_stats_freq)
		{
			LLViewerStats::getInstance()->mTextureKBitStat.addValue(LLViewerImageList::sTextureBits/1024.f);
			LLViewerStats::getInstance()->mTexturePacketsStat.addValue(LLViewerImageList::sTexturePackets);
			gTotalTextureBytes += LLViewerImageList::sTextureBits / 8;
			LLViewerImageList::sTextureBits = 0;
			LLViewerImageList::sTexturePackets = 0;
			texture_stats_timer.reset();
		}
	}

#if LL_LCD_COMPILE
	bool LCDenabled = gLcdScreen->Enabled();
	LLViewerStats::getInstance()->setStat(LLViewerStats::ST_LOGITECH_LCD, LCDenabled);
#else
	LLViewerStats::getInstance()->setStat(LLViewerStats::ST_LOGITECH_LCD, false);
#endif
}
Example #9
0
void LLCircuit::updateWatchDogTimers(LLMessageSystem *msgsys)
{
	F64 cur_time = LLMessageSystem::getMessageTimeSeconds();
	S32 count = mPingSet.size();
	S32 cur = 0;

	// Only process each circuit once at most, stop processing if no circuits
	while((cur < count) && !mPingSet.empty())
	{
		cur++;

		LLCircuit::ping_set_t::iterator psit = mPingSet.begin();
		LLCircuitData *cdp = *psit;

		if (!cdp->mbAlive)
		{
			// We suspect that this case should never happen, given how
			// the alive status is set.
			// Skip over dead circuits, just add the ping interval and push it to the back
			// Always remember to remove it from the set before changing the sorting
			// key (mNextPingSendTime)
			mPingSet.erase(psit);
			cdp->mNextPingSendTime = cur_time + PING_INTERVAL;
			mPingSet.insert(cdp);
			continue;
		}
		else
		{
			// Check to see if this needs a ping
			if (cur_time < cdp->mNextPingSendTime)
			{
				// This circuit doesn't need a ping, break out because
				// we have a sorted list, thus no more circuits need pings
				break;
			}

			// Update watchdog timers
			if (cdp->updateWatchDogTimers(msgsys))
            {
				// Randomize our pings a bit by doing some up to 5% early or late
				F64 dt = 0.95f*PING_INTERVAL + ll_frand(0.1f*PING_INTERVAL);

				// Remove it, and reinsert it with the new next ping time.
				// Always remove before changing the sorting key.
				mPingSet.erase(psit);
				cdp->mNextPingSendTime = cur_time + dt;
				mPingSet.insert(cdp);
    
			    // Update our throttles
			    cdp->mThrottles.dynamicAdjust();
    
			    // Update some stats, this is not terribly important
			    cdp->checkPeriodTime();
			}
			else
			{
				// This mPingSet.erase isn't necessary, because removing the circuit will
				// remove the ping set.
				//mPingSet.erase(psit);
				removeCircuitData(cdp->mHost);
			}
		}
	}
}
void LLFloaterMessageLog::refreshNetInfo(BOOL force)
{
	if(mNetInfoMode != NI_NET) return;
	LLScrollListCtrl* scrollp = getChild<LLScrollListCtrl>("net_list");
	LLScrollListItem* selected_itemp = scrollp->getFirstSelected();
	if(selected_itemp)
	{
		if(!force) if(getChild<LLTextEditor>("net_info")->hasSelection()) return;
		LLNetListItem* itemp = findNetListItem(selected_itemp->getUUID());
		if(itemp)
		{
			std::string info(llformat("%s\n--------------------------------\n\n", itemp->mName.c_str()));
			if(itemp->mCircuitData)
			{
				LLCircuitData* cdp = itemp->mCircuitData;
				info.append("Circuit\n--------------------------------\n");
				info.append(llformat(" * Host: %s\n", cdp->getHost().getString().c_str()));
				S32 seconds = (S32)cdp->getAgeInSeconds();
				S32 minutes = seconds / 60;
				seconds = seconds % 60;
				S32 hours = minutes / 60;
				minutes = minutes % 60;
				info.append(llformat(" * Age: %dh %dm %ds\n", hours, minutes, seconds));
				info.append(llformat(" * Alive: %s\n", cdp->isAlive() ? "yes" : "no"));
				info.append(llformat(" * Blocked: %s\n", cdp->isBlocked() ? "yes" : "no"));
				info.append(llformat(" * Allow timeout: %s\n", cdp->getAllowTimeout() ? "yes" : "no"));
				info.append(llformat(" * Trusted: %s\n", cdp->getTrusted() ? "yes" : "no"));
				info.append(llformat(" * Ping delay: %d\n", cdp->getPingDelay()));
				info.append(llformat(" * Packets out: %d\n", cdp->getPacketsOut()));
				info.append(llformat(" * Bytes out: %d\n", cdp->getBytesOut()));
				info.append(llformat(" * Packets in: %d\n", cdp->getPacketsIn()));
				info.append(llformat(" * Bytes in: %d\n", cdp->getBytesIn()));
				info.append(llformat(" * Endpoint ID: %s\n", cdp->getLocalEndPointID().asString().c_str()));
				info.append(llformat(" * Remote ID: %s\n", cdp->getRemoteID().asString().c_str()));
				info.append(llformat(" * Remote session ID: %s\n", cdp->getRemoteSessionID().asString().c_str()));
			}
			childSetText("net_info", info);
		}
		else childSetText("net_info", std::string(""));
	}
	else childSetText("net_info", std::string(""));
}
void update_statistics()
{
    gTotalWorldBytes += gVLManager.getTotalBytes();
    gTotalObjectBytes += gObjectBits / 8;

    LLViewerStats& stats = LLViewerStats::instance();

    // make sure we have a valid time delta for this frame
    if (gFrameIntervalSeconds > 0.f)
    {
        if (gAgentCamera.getCameraMode() == CAMERA_MODE_MOUSELOOK)
        {
            LLViewerStats::getInstance()->incStat(LLViewerStats::ST_MOUSELOOK_SECONDS, gFrameIntervalSeconds);
        }
        else if (gAgentCamera.getCameraMode() == CAMERA_MODE_CUSTOMIZE_AVATAR)
        {
            LLViewerStats::getInstance()->incStat(LLViewerStats::ST_AVATAR_EDIT_SECONDS, gFrameIntervalSeconds);
        }
        else if (gFloaterTools && gFloaterTools->getVisible())
        {
            LLViewerStats::getInstance()->incStat(LLViewerStats::ST_TOOLBOX_SECONDS, gFrameIntervalSeconds);
        }
    }
    stats.setStat(LLViewerStats::ST_ENABLE_VBO, (F64)gSavedSettings.getBOOL("RenderVBOEnable"));
    stats.setStat(LLViewerStats::ST_LIGHTING_DETAIL, (F64)gPipeline.getLightingDetail());
    stats.setStat(LLViewerStats::ST_DRAW_DIST, (F64)gSavedSettings.getF32("RenderFarClip"));
    stats.setStat(LLViewerStats::ST_CHAT_BUBBLES, (F64)gSavedSettings.getBOOL("UseChatBubbles"));
#if 0 // 1.9.2
    LLViewerStats::getInstance()->setStat(LLViewerStats::ST_SHADER_OBJECTS, (F64)gSavedSettings.getS32("VertexShaderLevelObject"));
    LLViewerStats::getInstance()->setStat(LLViewerStats::ST_SHADER_AVATAR, (F64)gSavedSettings.getBOOL("VertexShaderLevelAvatar"));
    LLViewerStats::getInstance()->setStat(LLViewerStats::ST_SHADER_ENVIRONMENT, (F64)gSavedSettings.getBOOL("VertexShaderLevelEnvironment"));
#endif
    stats.setStat(LLViewerStats::ST_FRAME_SECS, gDebugView->mFastTimerView->getTime("Frame"));
    F64 idle_secs = gDebugView->mFastTimerView->getTime("Idle");
    F64 network_secs = gDebugView->mFastTimerView->getTime("Network");
    stats.setStat(LLViewerStats::ST_UPDATE_SECS, idle_secs - network_secs);
    stats.setStat(LLViewerStats::ST_NETWORK_SECS, network_secs);
    stats.setStat(LLViewerStats::ST_IMAGE_SECS, gDebugView->mFastTimerView->getTime("Update Images"));
    stats.setStat(LLViewerStats::ST_REBUILD_SECS, gDebugView->mFastTimerView->getTime("Sort Draw State"));
    stats.setStat(LLViewerStats::ST_RENDER_SECS, gDebugView->mFastTimerView->getTime("Geometry"));

    LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(gAgent.getRegion()->getHost());
    if (cdp)
    {
        stats.mSimPingStat.addValue(cdp->getPingDelay());
        gAvgSimPing = ((gAvgSimPing * (F32)gSimPingCount) + (F32)(cdp->getPingDelay())) / ((F32)gSimPingCount + 1);
        gSimPingCount++;
    }
    else
    {
        stats.mSimPingStat.addValue(10000);
    }

    stats.mFPSStat.addValue(1);
    F32 layer_bits = (F32)(gVLManager.getLandBits() + gVLManager.getWindBits() + gVLManager.getCloudBits());
    stats.mLayersKBitStat.addValue(layer_bits/1024.f);
    stats.mObjectKBitStat.addValue(gObjectBits/1024.f);
    stats.mVFSPendingOperations.addValue(LLVFile::getVFSThread()->getPending());
    stats.mAssetKBitStat.addValue(gTransferManager.getTransferBitsIn(LLTCT_ASSET)/1024.f);
    gTransferManager.resetTransferBitsIn(LLTCT_ASSET);

    if (LLAppViewer::getTextureFetch()->getNumRequests() == 0)
    {
        gTextureTimer.pause();
    }
    else
    {
        gTextureTimer.unpause();
    }

    {
        static F32 visible_avatar_frames = 0.f;
        static F32 avg_visible_avatars = 0;
        F32 visible_avatars = (F32)LLVOAvatar::sNumVisibleAvatars;
        if (visible_avatars > 0.f)
        {
            visible_avatar_frames = 1.f;
            avg_visible_avatars = (avg_visible_avatars * (F32)(visible_avatar_frames - 1.f) + visible_avatars) / visible_avatar_frames;
        }
        stats.setStat(LLViewerStats::ST_VISIBLE_AVATARS, (F64)avg_visible_avatars);
    }
    LLWorld::getInstance()->updateNetStats();
    LLWorld::getInstance()->requestCacheMisses();

    // Reset all of these values.
    gVLManager.resetBitCounts();
    gObjectBits = 0;
//	gDecodedBits = 0;

    // Only update texture stats periodically so that they are less noisy
    {
        static const F32 texture_stats_freq = 0.25f;
        static LLFrameTimer texture_stats_timer;
        if (texture_stats_timer.getElapsedTimeF32() >= texture_stats_freq)
        {
            stats.mHTTPTextureKBitStat.addValue(AICurlInterface::getHTTPBandwidth()/125.f);
            stats.mUDPTextureKBitStat.addValue(LLViewerTextureList::sTextureBits/1024.f);
            stats.mTexturePacketsStat.addValue(LLViewerTextureList::sTexturePackets);
            gTotalTextureBytes += LLViewerTextureList::sTextureBits / 8;
            LLViewerTextureList::sTextureBits = 0;
            LLViewerTextureList::sTexturePackets = 0;
            texture_stats_timer.reset();
        }
    }

    {
        static const F32 mem_stats_freq = 10.f;
        static LLFrameTimer mem_stats_timer;
        if (mem_stats_timer.getElapsedTimeF32() >= mem_stats_freq)
        {
            stats.mMallocStat.addValue(SGMemStat::getMalloc()/1024.f/1024.f);
            mem_stats_timer.reset();
        }
    }
}
void LLTransferSourceChannel::updateTransfers()
{
	// Actually, this should do the following:
	// Decide if we can actually send data.
	// If so, update priorities so we know who gets to send it.
	// Send data from the sources, while updating until we've sent our throttle allocation.

	LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(getHost());
	if (!cdp)
	{
		return;
	}

	if (cdp->isBlocked())
	{
		// *NOTE: We need to make sure that the throttle bits
		// available gets reset.

		// We DON'T want to send any packets if they're blocked, they'll just end up
		// piling up on the other end.
		//llwarns << "Blocking transfers due to blocked circuit for " << getHost() << llendl;
		return;
	}

	const S32 throttle_id = mThrottleID;

	LLThrottleGroup &tg = cdp->getThrottleGroup();

	if (tg.checkOverflow(throttle_id, 0.f))
	{
		return;
	}

	LLPriQueueMap<LLTransferSource *>::pqm_iter iter, next;

	BOOL done = FALSE;
	for (iter = mTransferSources.mMap.begin(); (iter != mTransferSources.mMap.end()) && !done;)
	{
		//llinfos << "LLTransferSourceChannel::updateTransfers()" << llendl;
		// Do stuff. 
		next = iter;
		next++;

		LLTransferSource *tsp = iter->second;
		U8 *datap = NULL;
		S32 data_size = 0;
		BOOL delete_data = FALSE;
		S32 packet_id = 0;
		S32 sent_bytes = 0;
		LLTSCode status = LLTS_OK;

		// Get the packetID for the next packet that we're transferring.
		packet_id = tsp->getNextPacketID();
		status = tsp->dataCallback(packet_id, DEFAULT_PACKET_SIZE, &datap, data_size, delete_data);

		if (status == LLTS_SKIP)
		{
			// We don't have any data, but we're not done, just go on.
			// This will presumably be used for streaming or async transfers that
			// are stalled waiting for data from another source.
			iter=next;
			continue;
		}

		LLUUID *cb_uuid = new LLUUID(tsp->getID());
		LLUUID transaction_id = tsp->getID();

		// Send the data now, even if it's an error.
		// The status code will tell the other end what to do.
		gMessageSystem->newMessage("TransferPacket");
		gMessageSystem->nextBlock("TransferData");
		gMessageSystem->addUUID("TransferID", tsp->getID());
		gMessageSystem->addS32("ChannelType", getChannelType());
		gMessageSystem->addS32("Packet", packet_id);	// HACK!  Need to put in a REAL packet id
		gMessageSystem->addS32("Status", status);
		gMessageSystem->addBinaryData("Data", datap, data_size);
		sent_bytes = gMessageSystem->getCurrentSendTotal();
		gMessageSystem->sendReliable(getHost(), LL_DEFAULT_RELIABLE_RETRIES, TRUE, 0.f,
									 LLTransferManager::reliablePacketCallback, (void**)cb_uuid);

		// Do bookkeeping for the throttle
		done = tg.throttleOverflow(throttle_id, sent_bytes*8.f);
		gTransferManager.addTransferBitsOut(mChannelType, sent_bytes*8);

		// Clean up our temporary data.
		if (delete_data)
		{
			delete[] datap;
			datap = NULL;
		}

		if (findTransferSource(transaction_id) == NULL)
		{
			//Warning!  In the case of an aborted transfer, the sendReliable call above calls 
			//AbortTransfer which in turn calls deleteTransfer which means that somewhere way 
			//down the chain our current iter can get invalidated resulting in an infrequent
			//sim crash.  This check gets us to a valid transfer source in this event.
			iter=next;
			continue;
		}

		// Update the packet counter
		tsp->setLastPacketID(packet_id);

		switch (status)
		{
		case LLTS_OK:
			// We're OK, don't need to do anything.  Keep sending data.
			break;
		case LLTS_ERROR:
			llwarns << "Error in transfer dataCallback!" << llendl;
			// fall through
		case LLTS_DONE:
			// We need to clean up this transfer source.
			//llinfos << "LLTransferSourceChannel::updateTransfers() " << tsp->getID() << " done" << llendl;
			tsp->completionCallback(status);
			delete tsp;
			
			mTransferSources.mMap.erase(iter);
			iter = next;
			break;
		default:
			llerrs << "Unknown transfer error code!" << llendl;
		}

		// At this point, we should do priority adjustment (since some transfers like
		// streaming transfers will adjust priority based on how much they've sent and time,
		// but I'm not going to bother yet. - djs.
	}
}