diff options
added experimental packet tracker (LLPacketTracker.cs), which can be told to track a packet and if it hasn't been acked within a set time, trigger a IClientAPI event, that the application/scene can handle. Currently only terrain packet tracking is finished, Tracking for initial Prim packets (first full update for a prim) is being worked on. Future improvements would be to make it a more generic packet tracker with callback delegates instead of events.
Add a test event handler (which would fire after a minute if a terrain packet hadn't been acked) to scene to handle the OnUnackedTerrain event, which currently just resends the terrain patch.
The idea of this packet tracking is for the region level application to be able to know if the client stack gave up on sending a packet.
Diffstat (limited to 'OpenSim/Region/ClientStack/LindenUDP/LLPacketTracker.cs')
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLPacketTracker.cs | 234 |
1 files changed, 234 insertions, 0 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLPacketTracker.cs b/OpenSim/Region/ClientStack/LindenUDP/LLPacketTracker.cs new file mode 100644 index 0000000..e775a67 --- /dev/null +++ b/OpenSim/Region/ClientStack/LindenUDP/LLPacketTracker.cs | |||
@@ -0,0 +1,234 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Text; | ||
4 | using System.Threading; | ||
5 | using libsecondlife; | ||
6 | |||
7 | namespace OpenSim.Region.ClientStack.LindenUDP | ||
8 | { | ||
9 | |||
10 | public class LLPacketTracker | ||
11 | { | ||
12 | public delegate void PacketAcked(uint sequenceNumber); | ||
13 | public event PacketAcked OnPacketAcked; | ||
14 | |||
15 | protected List<uint> m_beenAcked = new List<uint>(); | ||
16 | |||
17 | protected TerrainPacketTracker[,] m_sentTerrainPackets = new TerrainPacketTracker[16, 16]; | ||
18 | protected Dictionary<LLUUID, PrimPacketTracker> m_sendPrimPackets = new Dictionary<LLUUID, PrimPacketTracker>(); | ||
19 | |||
20 | protected LLClientView m_parentClient; | ||
21 | |||
22 | public LLPacketTracker(LLClientView parent) | ||
23 | { | ||
24 | m_parentClient = parent; | ||
25 | OnPacketAcked += TerrainPacketAcked; | ||
26 | //OnPacketAcked += PrimPacketAcked; | ||
27 | } | ||
28 | |||
29 | public void PacketAck(uint sequenceNumber) | ||
30 | { | ||
31 | lock (m_beenAcked) | ||
32 | { | ||
33 | m_beenAcked.Add(sequenceNumber); | ||
34 | } | ||
35 | } | ||
36 | |||
37 | public void TrackTerrainPacket(uint sequenceNumber, int patchX, int patchY) | ||
38 | { | ||
39 | TerrainPacketTracker tracker = new TerrainPacketTracker(); | ||
40 | tracker.X = patchX; | ||
41 | tracker.Y = patchY; | ||
42 | tracker.SeqNumber = sequenceNumber; | ||
43 | tracker.TimeSent = DateTime.Now; | ||
44 | lock (m_sentTerrainPackets) | ||
45 | { | ||
46 | m_sentTerrainPackets[patchX, patchY] = tracker; | ||
47 | } | ||
48 | } | ||
49 | |||
50 | public void TrackPrimPacket(uint sequenceNumber, LLUUID primID) | ||
51 | { | ||
52 | PrimPacketTracker tracker = new PrimPacketTracker(); | ||
53 | tracker.PrimID = primID; | ||
54 | tracker.TimeSent = DateTime.Now; | ||
55 | tracker.SeqNumber = sequenceNumber; | ||
56 | lock (m_sendPrimPackets) | ||
57 | { | ||
58 | m_sendPrimPackets[primID] = tracker; | ||
59 | } | ||
60 | } | ||
61 | |||
62 | public void TerrainPacketCheck() | ||
63 | { | ||
64 | DateTime now = DateTime.Now; | ||
65 | List<TerrainPacketTracker> resendList = new List<TerrainPacketTracker>(); | ||
66 | lock (m_sentTerrainPackets) | ||
67 | { | ||
68 | for (int y = 0; y < 16; y++) | ||
69 | { | ||
70 | for (int x = 0; x < 16; x++) | ||
71 | { | ||
72 | if (m_sentTerrainPackets[x, y] != null) | ||
73 | { | ||
74 | TerrainPacketTracker tracker = m_sentTerrainPackets[x, y]; | ||
75 | if ((now - tracker.TimeSent) > TimeSpan.FromMinutes(1)) | ||
76 | { | ||
77 | tracker.TimeSent = now; | ||
78 | m_sentTerrainPackets[x, y] = null; | ||
79 | resendList.Add(tracker); | ||
80 | } | ||
81 | } | ||
82 | } | ||
83 | } | ||
84 | } | ||
85 | |||
86 | foreach (TerrainPacketTracker tracker in resendList) | ||
87 | { | ||
88 | m_parentClient.TriggerTerrainUnackedEvent(tracker.X, tracker.Y); | ||
89 | } | ||
90 | } | ||
91 | |||
92 | public void PrimPacketCheck() | ||
93 | { | ||
94 | DateTime now = DateTime.Now; | ||
95 | List<PrimPacketTracker> resendList = new List<PrimPacketTracker>(); | ||
96 | List<PrimPacketTracker> ackedList = new List<PrimPacketTracker>(); | ||
97 | |||
98 | lock (m_sendPrimPackets) | ||
99 | { | ||
100 | foreach (PrimPacketTracker tracker in m_sendPrimPackets.Values) | ||
101 | { | ||
102 | if (tracker.Acked) | ||
103 | { | ||
104 | ackedList.Add(tracker); | ||
105 | } | ||
106 | else if (((now - tracker.TimeSent) > TimeSpan.FromMinutes(1)) && (!tracker.Acked)) | ||
107 | { | ||
108 | resendList.Add(tracker); | ||
109 | } | ||
110 | } | ||
111 | } | ||
112 | |||
113 | foreach (PrimPacketTracker tracker in resendList) | ||
114 | { | ||
115 | lock (m_sendPrimPackets) | ||
116 | { | ||
117 | m_sendPrimPackets.Remove(tracker.PrimID); | ||
118 | } | ||
119 | //call event | ||
120 | Console.WriteLine("Prim packet not acked, " + tracker.PrimID.ToString()); | ||
121 | } | ||
122 | |||
123 | |||
124 | RemovePrimTrackers(ackedList); | ||
125 | } | ||
126 | |||
127 | public void PrimTrackerCleanup() | ||
128 | { | ||
129 | List<PrimPacketTracker> ackedList = new List<PrimPacketTracker>(); | ||
130 | |||
131 | lock (m_sendPrimPackets) | ||
132 | { | ||
133 | foreach (PrimPacketTracker tracker in m_sendPrimPackets.Values) | ||
134 | { | ||
135 | if (tracker.Acked) | ||
136 | { | ||
137 | ackedList.Add(tracker); | ||
138 | } | ||
139 | } | ||
140 | } | ||
141 | Thread.Sleep(15); //give a little bit of time for other code to access list before we lock it again | ||
142 | |||
143 | RemovePrimTrackers(ackedList); | ||
144 | } | ||
145 | |||
146 | protected void RemovePrimTrackers(List<PrimPacketTracker> ackedList) | ||
147 | { | ||
148 | lock (m_sendPrimPackets) | ||
149 | { | ||
150 | foreach (PrimPacketTracker tracker in ackedList) | ||
151 | { | ||
152 | m_sendPrimPackets.Remove(tracker.PrimID); | ||
153 | } | ||
154 | } | ||
155 | } | ||
156 | |||
157 | protected void TerrainPacketAcked(uint sequence) | ||
158 | { | ||
159 | lock (m_sentTerrainPackets) | ||
160 | { | ||
161 | for (int y = 0; y < 16; y++) | ||
162 | { | ||
163 | for (int x = 0; x < 16; x++) | ||
164 | { | ||
165 | if (m_sentTerrainPackets[x, y] != null) | ||
166 | { | ||
167 | if (m_sentTerrainPackets[x, y].SeqNumber == sequence) | ||
168 | { | ||
169 | m_sentTerrainPackets[x, y] = null; | ||
170 | return; | ||
171 | } | ||
172 | } | ||
173 | } | ||
174 | } | ||
175 | } | ||
176 | } | ||
177 | |||
178 | protected void PrimPacketAcked(uint sequence) | ||
179 | { | ||
180 | lock (m_sendPrimPackets) | ||
181 | { | ||
182 | foreach (PrimPacketTracker tracker in m_sendPrimPackets.Values) | ||
183 | { | ||
184 | if (tracker.SeqNumber == sequence) | ||
185 | { | ||
186 | tracker.Acked = true; | ||
187 | break; | ||
188 | } | ||
189 | } | ||
190 | } | ||
191 | } | ||
192 | |||
193 | public void Process() | ||
194 | { | ||
195 | List<uint> ackedPackets = null; | ||
196 | lock (m_beenAcked) | ||
197 | { | ||
198 | ackedPackets = new List<uint>(m_beenAcked); | ||
199 | m_beenAcked.Clear(); | ||
200 | } | ||
201 | |||
202 | if (ackedPackets != null) | ||
203 | { | ||
204 | foreach (uint packetId in ackedPackets) | ||
205 | { | ||
206 | if (OnPacketAcked != null) | ||
207 | { | ||
208 | OnPacketAcked(packetId); | ||
209 | } | ||
210 | } | ||
211 | } | ||
212 | |||
213 | // ackedPackets.Clear(); | ||
214 | ackedPackets = null; | ||
215 | } | ||
216 | |||
217 | public class TerrainPacketTracker | ||
218 | { | ||
219 | public uint SeqNumber = 0; | ||
220 | public int X; | ||
221 | public int Y; | ||
222 | public DateTime TimeSent; | ||
223 | |||
224 | } | ||
225 | |||
226 | public class PrimPacketTracker | ||
227 | { | ||
228 | public uint SeqNumber = 0; | ||
229 | public DateTime TimeSent; | ||
230 | public LLUUID PrimID; | ||
231 | public bool Acked = false; | ||
232 | } | ||
233 | } | ||
234 | } | ||