using System; using System.Collections.Generic; using System.Text; using System.Threading; using libsecondlife; using libsecondlife.Packets; using OpenSim.Framework; namespace OpenSim.Region.ClientStack.LindenUDP { public class LLPacketTracker { public delegate void PacketAcked(uint sequenceNumber); public event PacketAcked OnPacketAcked; protected List m_beenAcked = new List(); protected TerrainPacketTracker[,] m_sentTerrainPackets = new TerrainPacketTracker[16, 16]; protected Dictionary m_sendPrimPackets = new Dictionary(); protected LLClientView m_parentClient; public LLPacketTracker(LLClientView parent) { m_parentClient = parent; OnPacketAcked += TerrainPacketAcked; //OnPacketAcked += PrimPacketAcked; } public void PacketAck(uint sequenceNumber) { lock (m_beenAcked) { m_beenAcked.Add(sequenceNumber); } } public void TrackTerrainPacket(uint sequenceNumber, int patchX, int patchY) { TrackTerrainPacket(sequenceNumber, patchX, patchY, false, null); } public void TrackTerrainPacket(uint sequenceNumber, int patchX, int patchY, bool keepResending, LayerDataPacket packet) { TerrainPacketTracker tracker = new TerrainPacketTracker(); tracker.X = patchX; tracker.Y = patchY; tracker.SeqNumber = sequenceNumber; tracker.TimeSent = DateTime.Now; tracker.KeepResending = keepResending; tracker.Packet = packet; lock (m_sentTerrainPackets) { m_sentTerrainPackets[patchX, patchY] = tracker; } } public void TrackPrimPacket(uint sequenceNumber, LLUUID primID) { PrimPacketTracker tracker = new PrimPacketTracker(); tracker.PrimID = primID; tracker.TimeSent = DateTime.Now; tracker.SeqNumber = sequenceNumber; lock (m_sendPrimPackets) { m_sendPrimPackets[primID] = tracker; } } public void TerrainPacketCheck() { DateTime now = DateTime.Now; List resendList = new List(); lock (m_sentTerrainPackets) { for (int y = 0; y < 16; y++) { for (int x = 0; x < 16; x++) { if (m_sentTerrainPackets[x, y] != null) { TerrainPacketTracker tracker = m_sentTerrainPackets[x, y]; if ((now - tracker.TimeSent) > TimeSpan.FromMinutes(1)) { tracker.TimeSent = now; m_sentTerrainPackets[x, y] = null; resendList.Add(tracker); } } } } } foreach (TerrainPacketTracker tracker in resendList) { if (!tracker.KeepResending) { m_parentClient.TriggerTerrainUnackedEvent(tracker.X, tracker.Y); } else { if (tracker.Packet != null) { tracker.Packet.Header.Resent = true; m_parentClient.OutPacket(tracker.Packet, ThrottleOutPacketType.Resend); tracker.TimeSent = DateTime.Now; lock (m_sentTerrainPackets) { if (m_sentTerrainPackets[tracker.X, tracker.Y] == null) { m_sentTerrainPackets[tracker.X, tracker.Y] = tracker; } } } } } } public void PrimPacketCheck() { DateTime now = DateTime.Now; List resendList = new List(); List ackedList = new List(); lock (m_sendPrimPackets) { foreach (PrimPacketTracker tracker in m_sendPrimPackets.Values) { if (tracker.Acked) { ackedList.Add(tracker); } else if (((now - tracker.TimeSent) > TimeSpan.FromMinutes(1)) && (!tracker.Acked)) { resendList.Add(tracker); } } } foreach (PrimPacketTracker tracker in resendList) { lock (m_sendPrimPackets) { m_sendPrimPackets.Remove(tracker.PrimID); } //call event Console.WriteLine("Prim packet not acked, " + tracker.PrimID.ToString()); } RemovePrimTrackers(ackedList); } public void PrimTrackerCleanup() { List ackedList = new List(); lock (m_sendPrimPackets) { foreach (PrimPacketTracker tracker in m_sendPrimPackets.Values) { if (tracker.Acked) { ackedList.Add(tracker); } } } Thread.Sleep(15); //give a little bit of time for other code to access list before we lock it again RemovePrimTrackers(ackedList); } protected void RemovePrimTrackers(List ackedList) { lock (m_sendPrimPackets) { foreach (PrimPacketTracker tracker in ackedList) { m_sendPrimPackets.Remove(tracker.PrimID); } } } protected void TerrainPacketAcked(uint sequence) { lock (m_sentTerrainPackets) { for (int y = 0; y < 16; y++) { for (int x = 0; x < 16; x++) { if (m_sentTerrainPackets[x, y] != null) { if (m_sentTerrainPackets[x, y].SeqNumber == sequence) { m_sentTerrainPackets[x, y] = null; return; } } } } } } protected void PrimPacketAcked(uint sequence) { lock (m_sendPrimPackets) { foreach (PrimPacketTracker tracker in m_sendPrimPackets.Values) { if (tracker.SeqNumber == sequence) { tracker.Acked = true; break; } } } } public void Process() { List ackedPackets = null; lock (m_beenAcked) { ackedPackets = new List(m_beenAcked); m_beenAcked.Clear(); } if (ackedPackets != null) { foreach (uint packetId in ackedPackets) { if (OnPacketAcked != null) { OnPacketAcked(packetId); } } } // ackedPackets.Clear(); ackedPackets = null; } public class TerrainPacketTracker { public uint SeqNumber = 0; public int X; public int Y; public DateTime TimeSent; public LayerDataPacket Packet; public bool KeepResending; } public class PrimPacketTracker { public uint SeqNumber = 0; public DateTime TimeSent; public LLUUID PrimID; public bool Acked = false; } } }