aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/Linden/UDP
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/IncomingPacket.cs63
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/IncomingPacketHistoryCollection.cs73
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs438
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs13256
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs360
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs842
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs2216
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs901
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs504
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/OutgoingPacket.cs75
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs299
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs33
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs272
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs174
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs104
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/Resources/4-tile2.jp2bin0 -> 24410 bytes
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs427
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs126
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs464
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs243
20 files changed, 20870 insertions, 0 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/IncomingPacket.cs b/OpenSim/Region/ClientStack/Linden/UDP/IncomingPacket.cs
new file mode 100644
index 0000000..e22670b
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/IncomingPacket.cs
@@ -0,0 +1,63 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using OpenSim.Framework;
30using OpenMetaverse;
31using OpenMetaverse.Packets;
32
33namespace OpenSim.Region.ClientStack.LindenUDP
34{
35 /// <summary>
36 /// Holds a reference to a <seealso cref="LLUDPClient"/> and a <seealso cref="Packet"/>
37 /// for incoming packets
38 /// </summary>
39 public sealed class IncomingPacket
40 {
41 /// <summary>Client this packet came from</summary>
42 public LLClientView Client;
43
44 /// <summary>Packet data that has been received</summary>
45 public Packet Packet;
46
47 /// <summary>
48 /// No arg constructor.
49 /// </summary>
50 public IncomingPacket() {}
51
52 /// <summary>
53 /// Constructor
54 /// </summary>
55 /// <param name="client">Reference to the client this packet came from</param>
56 /// <param name="packet">Packet data</param>
57 public IncomingPacket(LLClientView client, Packet packet)
58 {
59 Client = client;
60 Packet = packet;
61 }
62 }
63}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/IncomingPacketHistoryCollection.cs b/OpenSim/Region/ClientStack/Linden/UDP/IncomingPacketHistoryCollection.cs
new file mode 100644
index 0000000..1f73a1d
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/IncomingPacketHistoryCollection.cs
@@ -0,0 +1,73 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30
31namespace OpenSim.Region.ClientStack.LindenUDP
32{
33 /// <summary>
34 /// A circular buffer and hashset for tracking incoming packet sequence
35 /// numbers
36 /// </summary>
37 public sealed class IncomingPacketHistoryCollection
38 {
39 private readonly uint[] m_items;
40 private HashSet<uint> m_hashSet;
41 private int m_first;
42 private int m_next;
43 private int m_capacity;
44
45 public IncomingPacketHistoryCollection(int capacity)
46 {
47 this.m_capacity = capacity;
48 m_items = new uint[capacity];
49 m_hashSet = new HashSet<uint>();
50 }
51
52 public bool TryEnqueue(uint ack)
53 {
54 lock (m_hashSet)
55 {
56 if (m_hashSet.Add(ack))
57 {
58 m_items[m_next] = ack;
59 m_next = (m_next + 1) % m_capacity;
60 if (m_next == m_first)
61 {
62 m_hashSet.Remove(m_items[m_first]);
63 m_first = (m_first + 1) % m_capacity;
64 }
65
66 return true;
67 }
68 }
69
70 return false;
71 }
72 }
73}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
new file mode 100644
index 0000000..4d0568d
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
@@ -0,0 +1,438 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using OpenMetaverse;
31using OpenMetaverse.Imaging;
32using OpenSim.Framework;
33using OpenSim.Region.Framework.Interfaces;
34using OpenSim.Services.Interfaces;
35using log4net;
36using System.Reflection;
37
38namespace OpenSim.Region.ClientStack.LindenUDP
39{
40 /// <summary>
41 /// Stores information about a current texture download and a reference to the texture asset
42 /// </summary>
43 public class J2KImage
44 {
45 private const int IMAGE_PACKET_SIZE = 1000;
46 private const int FIRST_PACKET_SIZE = 600;
47
48 /// <summary>
49 /// If we've requested an asset but not received it in this ticks timeframe, then allow a duplicate
50 /// request from the client to trigger a fresh asset request.
51 /// </summary>
52 /// <remarks>
53 /// There are 10,000 ticks in a millisecond
54 /// </remarks>
55 private const int ASSET_REQUEST_TIMEOUT = 100000000;
56
57 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
58
59 public uint LastSequence;
60 public float Priority;
61 public uint StartPacket;
62 public sbyte DiscardLevel;
63 public UUID TextureID;
64 public IJ2KDecoder J2KDecoder;
65 public IAssetService AssetService;
66 public UUID AgentID;
67 public IInventoryAccessModule InventoryAccessModule;
68 private OpenJPEG.J2KLayerInfo[] m_layers;
69
70 /// <summary>
71 /// Has this request decoded the asset data?
72 /// </summary>
73 public bool IsDecoded { get; private set; }
74
75 /// <summary>
76 /// Has this request received the required asset data?
77 /// </summary>
78 public bool HasAsset { get; private set; }
79
80 /// <summary>
81 /// Time in milliseconds at which the asset was requested.
82 /// </summary>
83 public long AssetRequestTime { get; private set; }
84
85 public C5.IPriorityQueueHandle<J2KImage> PriorityQueueHandle;
86
87 private uint m_currentPacket;
88 private bool m_decodeRequested;
89 private bool m_assetRequested;
90 private bool m_sentInfo;
91 private uint m_stopPacket;
92 private byte[] m_asset;
93 private LLImageManager m_imageManager;
94
95 public J2KImage(LLImageManager imageManager)
96 {
97 m_imageManager = imageManager;
98 }
99
100 /// <summary>
101 /// Sends packets for this texture to a client until packetsToSend is
102 /// hit or the transfer completes
103 /// </summary>
104 /// <param name="client">Reference to the client that the packets are destined for</param>
105 /// <param name="packetsToSend">Maximum number of packets to send during this call</param>
106 /// <param name="packetsSent">Number of packets sent during this call</param>
107 /// <returns>True if the transfer completes at the current discard level, otherwise false</returns>
108 public bool SendPackets(IClientAPI client, int packetsToSend, out int packetsSent)
109 {
110 packetsSent = 0;
111
112 if (m_currentPacket <= m_stopPacket)
113 {
114 bool sendMore = true;
115
116 if (!m_sentInfo || (m_currentPacket == 0))
117 {
118 sendMore = !SendFirstPacket(client);
119
120 m_sentInfo = true;
121 ++m_currentPacket;
122 ++packetsSent;
123 }
124 if (m_currentPacket < 2)
125 {
126 m_currentPacket = 2;
127 }
128
129 while (sendMore && packetsSent < packetsToSend && m_currentPacket <= m_stopPacket)
130 {
131 sendMore = SendPacket(client);
132 ++m_currentPacket;
133 ++packetsSent;
134 }
135 }
136
137 return (m_currentPacket > m_stopPacket);
138 }
139
140 /// <summary>
141 /// This is where we decide what we need to update
142 /// and assign the real discardLevel and packetNumber
143 /// assuming of course that the connected client might be bonkers
144 /// </summary>
145 public void RunUpdate()
146 {
147 if (!HasAsset)
148 {
149 if (!m_assetRequested || DateTime.UtcNow.Ticks > AssetRequestTime + ASSET_REQUEST_TIMEOUT)
150 {
151// m_log.DebugFormat(
152// "[J2KIMAGE]: Requesting asset {0} from request in packet {1}, already requested? {2}, due to timeout? {3}",
153// TextureID, LastSequence, m_assetRequested, DateTime.UtcNow.Ticks > AssetRequestTime + ASSET_REQUEST_TIMEOUT);
154
155 m_assetRequested = true;
156 AssetRequestTime = DateTime.UtcNow.Ticks;
157
158 AssetService.Get(TextureID.ToString(), this, AssetReceived);
159 }
160 }
161 else
162 {
163 if (!IsDecoded)
164 {
165 //We need to decode the requested image first
166 if (!m_decodeRequested)
167 {
168 //Request decode
169 m_decodeRequested = true;
170
171// m_log.DebugFormat("[J2KIMAGE]: Requesting decode of asset {0}", TextureID);
172
173 // Do we have a jpeg decoder?
174 if (J2KDecoder != null)
175 {
176 if (m_asset == null)
177 {
178 J2KDecodedCallback(TextureID, new OpenJPEG.J2KLayerInfo[0]);
179 }
180 else
181 {
182 // Send it off to the jpeg decoder
183 J2KDecoder.BeginDecode(TextureID, m_asset, J2KDecodedCallback);
184 }
185 }
186 else
187 {
188 J2KDecodedCallback(TextureID, new OpenJPEG.J2KLayerInfo[0]);
189 }
190 }
191 }
192 else
193 {
194 // Check for missing image asset data
195 if (m_asset == null)
196 {
197 m_log.Warn("[J2KIMAGE]: RunUpdate() called with missing asset data (no missing image texture?). Canceling texture transfer");
198 m_currentPacket = m_stopPacket;
199 return;
200 }
201
202 if (DiscardLevel >= 0 || m_stopPacket == 0)
203 {
204 // This shouldn't happen, but if it does, we really can't proceed
205 if (m_layers == null)
206 {
207 m_log.Warn("[J2KIMAGE]: RunUpdate() called with missing Layers. Canceling texture transfer");
208 m_currentPacket = m_stopPacket;
209 return;
210 }
211
212 int maxDiscardLevel = Math.Max(0, m_layers.Length - 1);
213
214 // Treat initial texture downloads with a DiscardLevel of -1 a request for the highest DiscardLevel
215 if (DiscardLevel < 0 && m_stopPacket == 0)
216 DiscardLevel = (sbyte)maxDiscardLevel;
217
218 // Clamp at the highest discard level
219 DiscardLevel = (sbyte)Math.Min(DiscardLevel, maxDiscardLevel);
220
221 //Calculate the m_stopPacket
222 if (m_layers.Length > 0)
223 {
224 m_stopPacket = (uint)GetPacketForBytePosition(m_layers[(m_layers.Length - 1) - DiscardLevel].End);
225 //I don't know why, but the viewer seems to expect the final packet if the file
226 //is just one packet bigger.
227 if (TexturePacketCount() == m_stopPacket + 1)
228 {
229 m_stopPacket = TexturePacketCount();
230 }
231 }
232 else
233 {
234 m_stopPacket = TexturePacketCount();
235 }
236
237 m_currentPacket = StartPacket;
238 }
239 }
240 }
241 }
242
243 private bool SendFirstPacket(IClientAPI client)
244 {
245 if (client == null)
246 return false;
247
248 if (m_asset == null)
249 {
250 m_log.Warn("[J2KIMAGE]: Sending ImageNotInDatabase for texture " + TextureID);
251 client.SendImageNotFound(TextureID);
252 return true;
253 }
254 else if (m_asset.Length <= FIRST_PACKET_SIZE)
255 {
256 // We have less then one packet's worth of data
257 client.SendImageFirstPart(1, TextureID, (uint)m_asset.Length, m_asset, 2);
258 m_stopPacket = 0;
259 return true;
260 }
261 else
262 {
263 // This is going to be a multi-packet texture download
264 byte[] firstImageData = new byte[FIRST_PACKET_SIZE];
265
266 try { Buffer.BlockCopy(m_asset, 0, firstImageData, 0, FIRST_PACKET_SIZE); }
267 catch (Exception)
268 {
269 m_log.ErrorFormat("[J2KIMAGE]: Texture block copy for the first packet failed. textureid={0}, assetlength={1}", TextureID, m_asset.Length);
270 return true;
271 }
272
273 client.SendImageFirstPart(TexturePacketCount(), TextureID, (uint)m_asset.Length, firstImageData, (byte)ImageCodec.J2C);
274 }
275 return false;
276 }
277
278 private bool SendPacket(IClientAPI client)
279 {
280 if (client == null)
281 return false;
282
283 bool complete = false;
284 int imagePacketSize = ((int)m_currentPacket == (TexturePacketCount())) ? LastPacketSize() : IMAGE_PACKET_SIZE;
285
286 try
287 {
288 if ((CurrentBytePosition() + IMAGE_PACKET_SIZE) > m_asset.Length)
289 {
290 imagePacketSize = LastPacketSize();
291 complete = true;
292 if ((CurrentBytePosition() + imagePacketSize) > m_asset.Length)
293 {
294 imagePacketSize = m_asset.Length - CurrentBytePosition();
295 complete = true;
296 }
297 }
298
299 // It's concievable that the client might request packet one
300 // from a one packet image, which is really packet 0,
301 // which would leave us with a negative imagePacketSize..
302 if (imagePacketSize > 0)
303 {
304 byte[] imageData = new byte[imagePacketSize];
305 int currentPosition = CurrentBytePosition();
306
307 try { Buffer.BlockCopy(m_asset, currentPosition, imageData, 0, imagePacketSize); }
308 catch (Exception e)
309 {
310 m_log.ErrorFormat("[J2KIMAGE]: Texture block copy for the first packet failed. textureid={0}, assetlength={1}, currentposition={2}, imagepacketsize={3}, exception={4}",
311 TextureID, m_asset.Length, currentPosition, imagePacketSize, e.Message);
312 return false;
313 }
314
315 //Send the packet
316 client.SendImageNextPart((ushort)(m_currentPacket - 1), TextureID, imageData);
317 }
318
319 return !complete;
320 }
321 catch (Exception)
322 {
323 return false;
324 }
325 }
326
327 private ushort TexturePacketCount()
328 {
329 if (!IsDecoded)
330 return 0;
331
332 if (m_asset == null)
333 return 0;
334
335 if (m_asset.Length <= FIRST_PACKET_SIZE)
336 return 1;
337
338 return (ushort)(((m_asset.Length - FIRST_PACKET_SIZE + IMAGE_PACKET_SIZE - 1) / IMAGE_PACKET_SIZE) + 1);
339 }
340
341 private int GetPacketForBytePosition(int bytePosition)
342 {
343 return ((bytePosition - FIRST_PACKET_SIZE + IMAGE_PACKET_SIZE - 1) / IMAGE_PACKET_SIZE) + 1;
344 }
345
346 private int LastPacketSize()
347 {
348 if (m_currentPacket == 1)
349 return m_asset.Length;
350 int lastsize = (m_asset.Length - FIRST_PACKET_SIZE) % IMAGE_PACKET_SIZE;
351 //If the last packet size is zero, it's really cImagePacketSize, it sits on the boundary
352 if (lastsize == 0)
353 {
354 lastsize = IMAGE_PACKET_SIZE;
355 }
356 return lastsize;
357 }
358
359 private int CurrentBytePosition()
360 {
361 if (m_currentPacket == 0)
362 return 0;
363
364 if (m_currentPacket == 1)
365 return FIRST_PACKET_SIZE;
366
367 int result = FIRST_PACKET_SIZE + ((int)m_currentPacket - 2) * IMAGE_PACKET_SIZE;
368
369 if (result < 0)
370 result = FIRST_PACKET_SIZE;
371
372 return result;
373 }
374
375 private void J2KDecodedCallback(UUID AssetId, OpenJPEG.J2KLayerInfo[] layers)
376 {
377 m_layers = layers;
378 IsDecoded = true;
379 RunUpdate();
380 }
381
382 private void AssetDataCallback(UUID AssetID, AssetBase asset)
383 {
384 HasAsset = true;
385
386 if (asset == null || asset.Data == null)
387 {
388 if (m_imageManager.MissingImage != null)
389 {
390 m_asset = m_imageManager.MissingImage.Data;
391 }
392 else
393 {
394 m_asset = null;
395 IsDecoded = true;
396 }
397 }
398 else
399 {
400 m_asset = asset.Data;
401 }
402
403 RunUpdate();
404 }
405
406 private void AssetReceived(string id, Object sender, AssetBase asset)
407 {
408// m_log.DebugFormat(
409// "[J2KIMAGE]: Received asset {0} ({1} bytes)", id, asset != null ? asset.Data.Length.ToString() : "n/a");
410
411 UUID assetID = UUID.Zero;
412 if (asset != null)
413 {
414 assetID = asset.FullID;
415 }
416 else if ((InventoryAccessModule != null) && (sender != InventoryAccessModule))
417 {
418 // Unfortunately we need this here, there's no other way.
419 // This is due to the fact that textures opened directly from the agent's inventory
420 // don't have any distinguishing feature. As such, in order to serve those when the
421 // foreign user is visiting, we need to try again after the first fail to the local
422 // asset service.
423 string assetServerURL = string.Empty;
424 if (InventoryAccessModule.IsForeignUser(AgentID, out assetServerURL) && !string.IsNullOrEmpty(assetServerURL))
425 {
426 if (!assetServerURL.EndsWith("/") && !assetServerURL.EndsWith("="))
427 assetServerURL = assetServerURL + "/";
428
429// m_log.DebugFormat("[J2KIMAGE]: texture {0} not found in local asset storage. Trying user's storage.", assetServerURL + id);
430 AssetService.Get(assetServerURL + id, InventoryAccessModule, AssetReceived);
431 return;
432 }
433 }
434
435 AssetDataCallback(assetID, asset);
436 }
437 }
438}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
new file mode 100644
index 0000000..e7dd9d3
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -0,0 +1,13256 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Net;
32using System.Reflection;
33using System.Text;
34using System.Threading;
35using System.Timers;
36using System.Xml;
37
38using log4net;
39using OpenMetaverse;
40using OpenMetaverse.Packets;
41using OpenMetaverse.Messages.Linden;
42using OpenMetaverse.StructuredData;
43
44using OpenSim.Framework;
45using OpenSim.Framework.Client;
46using OpenSim.Framework.Monitoring;
47using OpenSim.Region.Framework.Interfaces;
48using OpenSim.Region.Framework.Scenes;
49using OpenSim.Services.Interfaces;
50using Timer = System.Timers.Timer;
51using AssetLandmark = OpenSim.Framework.AssetLandmark;
52using RegionFlags = OpenMetaverse.RegionFlags;
53
54using System.IO;
55using PermissionMask = OpenSim.Framework.PermissionMask;
56
57namespace OpenSim.Region.ClientStack.LindenUDP
58{
59 public delegate bool PacketMethod(IClientAPI simClient, Packet packet);
60
61 /// <summary>
62 /// Handles new client connections
63 /// Constructor takes a single Packet and authenticates everything
64 /// </summary>
65 public class LLClientView : IClientAPI, IClientCore, IClientIM, IClientChat, IClientInventory, IStatsCollector
66 {
67 /// <value>
68 /// Debug packet level. See OpenSim.RegisterConsoleCommands() for more details.
69 /// </value>
70 public int DebugPacketLevel { get; set; }
71
72 #region Events
73
74 public event BinaryGenericMessage OnBinaryGenericMessage;
75 public event Action<IClientAPI> OnLogout;
76 public event ObjectPermissions OnObjectPermissions;
77 public event Action<IClientAPI> OnConnectionClosed;
78 public event ViewerEffectEventHandler OnViewerEffect;
79 public event ImprovedInstantMessage OnInstantMessage;
80 public event ChatMessage OnChatFromClient;
81 public event RezObject OnRezObject;
82 public event DeRezObject OnDeRezObject;
83 public event ModifyTerrain OnModifyTerrain;
84 public event Action<IClientAPI> OnRegionHandShakeReply;
85 public event GenericCall1 OnRequestWearables;
86 public event SetAppearance OnSetAppearance;
87 public event AvatarNowWearing OnAvatarNowWearing;
88 public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv;
89 public event RezMultipleAttachmentsFromInv OnRezMultipleAttachmentsFromInv;
90 public event UUIDNameRequest OnDetachAttachmentIntoInv;
91 public event ObjectAttach OnObjectAttach;
92 public event ObjectDeselect OnObjectDetach;
93 public event ObjectDrop OnObjectDrop;
94 public event Action<IClientAPI, bool> OnCompleteMovementToRegion;
95 public event UpdateAgent OnPreAgentUpdate;
96 public event UpdateAgent OnAgentUpdate;
97 public event UpdateAgent OnAgentCameraUpdate;
98 public event AgentRequestSit OnAgentRequestSit;
99 public event AgentSit OnAgentSit;
100 public event AvatarPickerRequest OnAvatarPickerRequest;
101 public event StartAnim OnStartAnim;
102 public event StopAnim OnStopAnim;
103 public event Action<IClientAPI> OnRequestAvatarsData;
104 public event LinkObjects OnLinkObjects;
105 public event DelinkObjects OnDelinkObjects;
106 public event GrabObject OnGrabObject;
107 public event DeGrabObject OnDeGrabObject;
108 public event SpinStart OnSpinStart;
109 public event SpinStop OnSpinStop;
110 public event ObjectDuplicate OnObjectDuplicate;
111 public event ObjectDuplicateOnRay OnObjectDuplicateOnRay;
112 public event MoveObject OnGrabUpdate;
113 public event SpinObject OnSpinUpdate;
114 public event AddNewPrim OnAddPrim;
115 public event RequestGodlikePowers OnRequestGodlikePowers;
116 public event GodKickUser OnGodKickUser;
117 public event ObjectExtraParams OnUpdateExtraParams;
118 public event UpdateShape OnUpdatePrimShape;
119 public event ObjectRequest OnObjectRequest;
120 public event ObjectSelect OnObjectSelect;
121 public event ObjectDeselect OnObjectDeselect;
122 public event GenericCall7 OnObjectDescription;
123 public event GenericCall7 OnObjectName;
124 public event GenericCall7 OnObjectClickAction;
125 public event GenericCall7 OnObjectMaterial;
126 public event ObjectIncludeInSearch OnObjectIncludeInSearch;
127 public event RequestObjectPropertiesFamily OnRequestObjectPropertiesFamily;
128 public event UpdatePrimFlags OnUpdatePrimFlags;
129 public event UpdatePrimTexture OnUpdatePrimTexture;
130 public event UpdateVector OnUpdatePrimGroupPosition;
131 public event UpdateVector OnUpdatePrimSinglePosition;
132 public event UpdatePrimRotation OnUpdatePrimGroupRotation;
133 public event UpdatePrimSingleRotation OnUpdatePrimSingleRotation;
134 public event UpdatePrimSingleRotationPosition OnUpdatePrimSingleRotationPosition;
135 public event UpdatePrimGroupRotation OnUpdatePrimGroupMouseRotation;
136 public event UpdateVector OnUpdatePrimScale;
137 public event UpdateVector OnUpdatePrimGroupScale;
138 public event RequestMapBlocks OnRequestMapBlocks;
139 public event RequestMapName OnMapNameRequest;
140 public event TeleportLocationRequest OnTeleportLocationRequest;
141 public event TeleportLandmarkRequest OnTeleportLandmarkRequest;
142 public event TeleportCancel OnTeleportCancel;
143 public event RequestAvatarProperties OnRequestAvatarProperties;
144 public event SetAlwaysRun OnSetAlwaysRun;
145 public event FetchInventory OnAgentDataUpdateRequest;
146 public event TeleportLocationRequest OnSetStartLocationRequest;
147 public event UpdateAvatarProperties OnUpdateAvatarProperties;
148 public event CreateNewInventoryItem OnCreateNewInventoryItem;
149 public event LinkInventoryItem OnLinkInventoryItem;
150 public event CreateInventoryFolder OnCreateNewInventoryFolder;
151 public event UpdateInventoryFolder OnUpdateInventoryFolder;
152 public event MoveInventoryFolder OnMoveInventoryFolder;
153 public event FetchInventoryDescendents OnFetchInventoryDescendents;
154 public event PurgeInventoryDescendents OnPurgeInventoryDescendents;
155 public event FetchInventory OnFetchInventory;
156 public event RequestTaskInventory OnRequestTaskInventory;
157 public event UpdateInventoryItem OnUpdateInventoryItem;
158 public event CopyInventoryItem OnCopyInventoryItem;
159 public event MoveInventoryItem OnMoveInventoryItem;
160 public event RemoveInventoryItem OnRemoveInventoryItem;
161 public event RemoveInventoryFolder OnRemoveInventoryFolder;
162 public event UDPAssetUploadRequest OnAssetUploadRequest;
163 public event XferReceive OnXferReceive;
164 public event RequestXfer OnRequestXfer;
165 public event ConfirmXfer OnConfirmXfer;
166 public event AbortXfer OnAbortXfer;
167 public event RequestTerrain OnRequestTerrain;
168 public event RezScript OnRezScript;
169 public event UpdateTaskInventory OnUpdateTaskInventory;
170 public event MoveTaskInventory OnMoveTaskItem;
171 public event RemoveTaskInventory OnRemoveTaskItem;
172 public event UUIDNameRequest OnNameFromUUIDRequest;
173 public event ParcelAccessListRequest OnParcelAccessListRequest;
174 public event ParcelAccessListUpdateRequest OnParcelAccessListUpdateRequest;
175 public event ParcelPropertiesRequest OnParcelPropertiesRequest;
176 public event ParcelDivideRequest OnParcelDivideRequest;
177 public event ParcelJoinRequest OnParcelJoinRequest;
178 public event ParcelPropertiesUpdateRequest OnParcelPropertiesUpdateRequest;
179 public event ParcelSelectObjects OnParcelSelectObjects;
180 public event ParcelObjectOwnerRequest OnParcelObjectOwnerRequest;
181 public event ParcelAbandonRequest OnParcelAbandonRequest;
182 public event ParcelGodForceOwner OnParcelGodForceOwner;
183 public event ParcelReclaim OnParcelReclaim;
184 public event ParcelReturnObjectsRequest OnParcelReturnObjectsRequest;
185 public event ParcelDeedToGroup OnParcelDeedToGroup;
186 public event RegionInfoRequest OnRegionInfoRequest;
187 public event EstateCovenantRequest OnEstateCovenantRequest;
188 public event FriendActionDelegate OnApproveFriendRequest;
189 public event FriendActionDelegate OnDenyFriendRequest;
190 public event FriendshipTermination OnTerminateFriendship;
191 public event GrantUserFriendRights OnGrantUserRights;
192 public event MoneyTransferRequest OnMoneyTransferRequest;
193 public event EconomyDataRequest OnEconomyDataRequest;
194 public event MoneyBalanceRequest OnMoneyBalanceRequest;
195 public event ParcelBuy OnParcelBuy;
196 public event UUIDNameRequest OnTeleportHomeRequest;
197 public event UUIDNameRequest OnUUIDGroupNameRequest;
198 public event ScriptAnswer OnScriptAnswer;
199 public event RequestPayPrice OnRequestPayPrice;
200 public event ObjectSaleInfo OnObjectSaleInfo;
201 public event ObjectBuy OnObjectBuy;
202 public event AgentSit OnUndo;
203 public event AgentSit OnRedo;
204 public event LandUndo OnLandUndo;
205 public event ForceReleaseControls OnForceReleaseControls;
206 public event GodLandStatRequest OnLandStatRequest;
207 public event RequestObjectPropertiesFamily OnObjectGroupRequest;
208 public event DetailedEstateDataRequest OnDetailedEstateDataRequest;
209 public event SetEstateFlagsRequest OnSetEstateFlagsRequest;
210 public event SetEstateTerrainDetailTexture OnSetEstateTerrainDetailTexture;
211 public event SetEstateTerrainTextureHeights OnSetEstateTerrainTextureHeights;
212 public event CommitEstateTerrainTextureRequest OnCommitEstateTerrainTextureRequest;
213 public event SetRegionTerrainSettings OnSetRegionTerrainSettings;
214 public event BakeTerrain OnBakeTerrain;
215 public event RequestTerrain OnUploadTerrain;
216 public event EstateChangeInfo OnEstateChangeInfo;
217 public event EstateManageTelehub OnEstateManageTelehub;
218 public event EstateRestartSimRequest OnEstateRestartSimRequest;
219 public event EstateChangeCovenantRequest OnEstateChangeCovenantRequest;
220 public event UpdateEstateAccessDeltaRequest OnUpdateEstateAccessDeltaRequest;
221 public event SimulatorBlueBoxMessageRequest OnSimulatorBlueBoxMessageRequest;
222 public event EstateBlueBoxMessageRequest OnEstateBlueBoxMessageRequest;
223 public event EstateDebugRegionRequest OnEstateDebugRegionRequest;
224 public event EstateTeleportOneUserHomeRequest OnEstateTeleportOneUserHomeRequest;
225 public event EstateTeleportAllUsersHomeRequest OnEstateTeleportAllUsersHomeRequest;
226 public event RegionHandleRequest OnRegionHandleRequest;
227 public event ParcelInfoRequest OnParcelInfoRequest;
228 public event ScriptReset OnScriptReset;
229 public event GetScriptRunning OnGetScriptRunning;
230 public event SetScriptRunning OnSetScriptRunning;
231 public event Action<Vector3, bool, bool> OnAutoPilotGo;
232 public event ActivateGesture OnActivateGesture;
233 public event DeactivateGesture OnDeactivateGesture;
234 public event ObjectOwner OnObjectOwner;
235 public event DirPlacesQuery OnDirPlacesQuery;
236 public event DirFindQuery OnDirFindQuery;
237 public event DirLandQuery OnDirLandQuery;
238 public event DirPopularQuery OnDirPopularQuery;
239 public event DirClassifiedQuery OnDirClassifiedQuery;
240 public event EventInfoRequest OnEventInfoRequest;
241 public event ParcelSetOtherCleanTime OnParcelSetOtherCleanTime;
242 public event MapItemRequest OnMapItemRequest;
243 public event OfferCallingCard OnOfferCallingCard;
244 public event AcceptCallingCard OnAcceptCallingCard;
245 public event DeclineCallingCard OnDeclineCallingCard;
246 public event SoundTrigger OnSoundTrigger;
247 public event StartLure OnStartLure;
248 public event TeleportLureRequest OnTeleportLureRequest;
249 public event NetworkStats OnNetworkStatsUpdate;
250 public event ClassifiedInfoRequest OnClassifiedInfoRequest;
251 public event ClassifiedInfoUpdate OnClassifiedInfoUpdate;
252 public event ClassifiedDelete OnClassifiedDelete;
253 public event ClassifiedDelete OnClassifiedGodDelete;
254 public event EventNotificationAddRequest OnEventNotificationAddRequest;
255 public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest;
256 public event EventGodDelete OnEventGodDelete;
257 public event ParcelDwellRequest OnParcelDwellRequest;
258 public event UserInfoRequest OnUserInfoRequest;
259 public event UpdateUserInfo OnUpdateUserInfo;
260 public event RetrieveInstantMessages OnRetrieveInstantMessages;
261 public event PickDelete OnPickDelete;
262 public event PickGodDelete OnPickGodDelete;
263 public event PickInfoUpdate OnPickInfoUpdate;
264 public event AvatarNotesUpdate OnAvatarNotesUpdate;
265 public event MuteListRequest OnMuteListRequest;
266 public event AvatarInterestUpdate OnAvatarInterestUpdate;
267 public event PlacesQuery OnPlacesQuery;
268 public event AgentFOV OnAgentFOV;
269 public event FindAgentUpdate OnFindAgent;
270 public event TrackAgentUpdate OnTrackAgent;
271 public event NewUserReport OnUserReport;
272 public event SaveStateHandler OnSaveState;
273 public event GroupAccountSummaryRequest OnGroupAccountSummaryRequest;
274 public event GroupAccountDetailsRequest OnGroupAccountDetailsRequest;
275 public event GroupAccountTransactionsRequest OnGroupAccountTransactionsRequest;
276 public event FreezeUserUpdate OnParcelFreezeUser;
277 public event EjectUserUpdate OnParcelEjectUser;
278 public event ParcelBuyPass OnParcelBuyPass;
279 public event ParcelGodMark OnParcelGodMark;
280 public event GroupActiveProposalsRequest OnGroupActiveProposalsRequest;
281 public event GroupVoteHistoryRequest OnGroupVoteHistoryRequest;
282 public event SimWideDeletesDelegate OnSimWideDeletes;
283 public event SendPostcard OnSendPostcard;
284 public event MuteListEntryUpdate OnUpdateMuteListEntry;
285 public event MuteListEntryRemove OnRemoveMuteListEntry;
286 public event GodlikeMessage onGodlikeMessage;
287 public event GodUpdateRegionInfoUpdate OnGodUpdateRegionInfoUpdate;
288
289#pragma warning disable 0067
290 public event GenericMessage OnGenericMessage;
291 public event TextureRequest OnRequestTexture;
292 public event StatusChange OnChildAgentStatus;
293 public event GenericCall2 OnStopMovement;
294 public event Action<UUID> OnRemoveAvatar;
295 public event DisconnectUser OnDisconnectUser;
296 public event RequestAsset OnRequestAsset;
297 public event BuyObjectInventory OnBuyObjectInventory;
298 public event SetEstateTerrainBaseTexture OnSetEstateTerrainBaseTexture;
299 public event TerrainUnacked OnUnackedTerrain;
300 public event CachedTextureRequest OnCachedTextureRequest;
301#pragma warning restore 0067
302
303 #endregion Events
304
305 #region Class Members
306
307 // LLClientView Only
308 public delegate void BinaryGenericMessage(Object sender, string method, byte[][] args);
309
310 /// <summary>Used to adjust Sun Orbit values so Linden based viewers properly position sun</summary>
311 private const float m_sunPainDaHalfOrbitalCutoff = 4.712388980384689858f;
312
313 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
314 private static string LogHeader = "[LLCLIENTVIEW]";
315 protected static Dictionary<PacketType, PacketMethod> PacketHandlers = new Dictionary<PacketType, PacketMethod>(); //Global/static handlers for all clients
316
317 /// <summary>
318 /// Handles UDP texture download.
319 /// </summary>
320 public LLImageManager ImageManager { get; private set; }
321
322 private readonly LLUDPServer m_udpServer;
323 private readonly LLUDPClient m_udpClient;
324 private readonly UUID m_sessionId;
325 private readonly UUID m_secureSessionId;
326 protected readonly UUID m_agentId;
327 private readonly uint m_circuitCode;
328 private readonly byte[] m_channelVersion = Utils.EmptyBytes;
329 private readonly IGroupsModule m_GroupsModule;
330
331 private int m_cachedTextureSerial;
332 private PriorityQueue m_entityUpdates;
333 private PriorityQueue m_entityProps;
334 private Prioritizer m_prioritizer;
335 private bool m_disableFacelights = false;
336 private volatile bool m_justEditedTerrain = false;
337 /// <value>
338 /// List used in construction of data blocks for an object update packet. This is to stop us having to
339 /// continually recreate it.
340 /// </value>
341 protected List<ObjectUpdatePacket.ObjectDataBlock> m_fullUpdateDataBlocksBuilder;
342
343 /// <value>
344 /// Maintain a record of all the objects killed. This allows us to stop an update being sent from the
345 /// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an
346 /// ownerless phantom.
347 ///
348 /// All manipulation of this set has to occur under a lock
349 ///
350 /// </value>
351 protected HashSet<uint> m_killRecord;
352
353// protected HashSet<uint> m_attachmentsSent;
354
355 private int m_animationSequenceNumber = 1;
356 private bool m_SendLogoutPacketWhenClosing = true;
357
358 /// <summary>
359 /// We retain a single AgentUpdateArgs so that we can constantly reuse it rather than construct a new one for
360 /// every single incoming AgentUpdate. Every client sends 10 AgentUpdate UDP messages per second, even if it
361 /// is doing absolutely nothing.
362 /// </summary>
363 /// <remarks>
364 /// This does mean that agent updates must be processed synchronously, at least for each client, and called methods
365 /// cannot retain a reference to it outside of that method.
366 /// </remarks>
367 private AgentUpdateArgs m_thisAgentUpdateArgs = new AgentUpdateArgs();
368
369 protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>();
370 protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers
371 protected Scene m_scene;
372 protected string m_firstName;
373 protected string m_lastName;
374 protected Thread m_clientThread;
375 protected Vector3 m_startpos;
376 protected UUID m_activeGroupID;
377 protected string m_activeGroupName = String.Empty;
378 protected ulong m_activeGroupPowers;
379 protected Dictionary<UUID, ulong> m_groupPowers = new Dictionary<UUID, ulong>();
380 protected int m_terrainCheckerCount;
381 protected uint m_agentFOVCounter;
382
383 protected IAssetService m_assetService;
384 private const bool m_checkPackets = true;
385
386 #endregion Class Members
387
388 #region Properties
389
390 public LLUDPClient UDPClient { get { return m_udpClient; } }
391 public LLUDPServer UDPServer { get { return m_udpServer; } }
392 public IPEndPoint RemoteEndPoint { get { return m_udpClient.RemoteEndPoint; } }
393 public UUID SecureSessionId { get { return m_secureSessionId; } }
394 public IScene Scene { get { return m_scene; } }
395 public UUID SessionId { get { return m_sessionId; } }
396 public Vector3 StartPos
397 {
398 get { return m_startpos; }
399 set { m_startpos = value; }
400 }
401 public UUID AgentId { get { return m_agentId; } }
402 public ISceneAgent SceneAgent { get; set; }
403 public UUID ActiveGroupId { get { return m_activeGroupID; } private set { m_activeGroupID = value; } }
404 public string ActiveGroupName { get { return m_activeGroupName; } private set { m_activeGroupName = value; } }
405 public ulong ActiveGroupPowers { get { return m_activeGroupPowers; } private set { m_activeGroupPowers = value; } }
406 public bool IsGroupMember(UUID groupID) { return m_groupPowers.ContainsKey(groupID); }
407
408 /// <summary>
409 /// Entity update queues
410 /// </summary>
411 public PriorityQueue EntityUpdateQueue { get { return m_entityUpdates; } }
412
413 /// <summary>
414 /// First name of the agent/avatar represented by the client
415 /// </summary>
416 public string FirstName { get { return m_firstName; } }
417
418 /// <summary>
419 /// Last name of the agent/avatar represented by the client
420 /// </summary>
421 public string LastName { get { return m_lastName; } }
422
423 /// <summary>
424 /// Full name of the client (first name and last name)
425 /// </summary>
426 public string Name { get { return FirstName + " " + LastName; } }
427
428 public uint CircuitCode { get { return m_circuitCode; } }
429 public int NextAnimationSequenceNumber { get { return m_animationSequenceNumber++; } }
430
431 /// <summary>
432 /// As well as it's function in IClientAPI, in LLClientView we are locking on this property in order to
433 /// prevent race conditions by different threads calling Close().
434 /// </summary>
435 public bool IsActive { get; set; }
436
437 /// <summary>
438 /// Used to synchronise threads when client is being closed.
439 /// </summary>
440 public Object CloseSyncLock { get; private set; }
441
442 public bool IsLoggingOut { get; set; }
443
444 public bool DisableFacelights
445 {
446 get { return m_disableFacelights; }
447 set { m_disableFacelights = value; }
448 }
449
450 public bool SendLogoutPacketWhenClosing { set { m_SendLogoutPacketWhenClosing = value; } }
451
452 #endregion Properties
453
454// ~LLClientView()
455// {
456// m_log.DebugFormat("{0} Destructor called for {1}, circuit code {2}", LogHeader, Name, CircuitCode);
457// }
458
459 /// <summary>
460 /// Constructor
461 /// </summary>
462 public LLClientView(Scene scene, LLUDPServer udpServer, LLUDPClient udpClient, AuthenticateResponse sessionInfo,
463 UUID agentId, UUID sessionId, uint circuitCode)
464 {
465// DebugPacketLevel = 1;
466
467 CloseSyncLock = new Object();
468
469 RegisterInterface<IClientIM>(this);
470 RegisterInterface<IClientInventory>(this);
471 RegisterInterface<IClientChat>(this);
472
473 m_scene = scene;
474 m_entityUpdates = new PriorityQueue(m_scene.Entities.Count);
475 m_entityProps = new PriorityQueue(m_scene.Entities.Count);
476 m_fullUpdateDataBlocksBuilder = new List<ObjectUpdatePacket.ObjectDataBlock>();
477 m_killRecord = new HashSet<uint>();
478// m_attachmentsSent = new HashSet<uint>();
479
480 m_assetService = m_scene.RequestModuleInterface<IAssetService>();
481 m_GroupsModule = scene.RequestModuleInterface<IGroupsModule>();
482 ImageManager = new LLImageManager(this, m_assetService, Scene.RequestModuleInterface<IJ2KDecoder>());
483 m_channelVersion = Util.StringToBytes256(scene.GetSimulatorVersion());
484 m_agentId = agentId;
485 m_sessionId = sessionId;
486 m_secureSessionId = sessionInfo.LoginInfo.SecureSession;
487 m_circuitCode = circuitCode;
488 m_firstName = sessionInfo.LoginInfo.First;
489 m_lastName = sessionInfo.LoginInfo.Last;
490 m_startpos = sessionInfo.LoginInfo.StartPos;
491
492 m_udpServer = udpServer;
493 m_udpClient = udpClient;
494 m_udpClient.OnQueueEmpty += HandleQueueEmpty;
495 m_udpClient.HasUpdates += HandleHasUpdates;
496 m_udpClient.OnPacketStats += PopulateStats;
497
498 m_prioritizer = new Prioritizer(m_scene);
499
500 RegisterLocalPacketHandlers();
501
502 IsActive = true;
503 }
504
505 #region Client Methods
506
507 public void Close()
508 {
509 Close(false);
510 }
511
512 public void Close(bool force)
513 {
514 // We lock here to prevent race conditions between two threads calling close simultaneously (e.g.
515 // a simultaneous relog just as a client is being closed out due to no packet ack from the old connection.
516 lock (CloseSyncLock)
517 {
518 // We still perform a force close inside the sync lock since this is intended to attempt close where
519 // there is some unidentified connection problem, not where we have issues due to deadlock
520 if (!IsActive && !force)
521 {
522 m_log.DebugFormat( "{0} Not attempting to close inactive client {1} in {2} since force flag is not set",
523 LogHeader, Name, m_scene.Name);
524
525 return;
526 }
527
528 IsActive = false;
529 CloseWithoutChecks();
530 }
531 }
532
533 /// <summary>
534 /// Closes down the client view without first checking whether it is active.
535 /// </summary>
536 /// <remarks>
537 /// This exists because LLUDPServer has to set IsActive = false in earlier synchronous code before calling
538 /// CloseWithoutIsActiveCheck asynchronously.
539 ///
540 /// Callers must lock ClosingSyncLock before calling.
541 /// </remarks>
542 public void CloseWithoutChecks()
543 {
544 m_log.DebugFormat(
545 "[CLIENT]: Close has been called for {0} attached to scene {1}",
546 Name, m_scene.RegionInfo.RegionName);
547
548 // Shutdown the image manager
549 ImageManager.Close();
550
551 // Fire the callback for this connection closing
552 if (OnConnectionClosed != null)
553 OnConnectionClosed(this);
554
555 // Flush all of the packets out of the UDP server for this client
556 if (m_udpServer != null)
557 m_udpServer.Flush(m_udpClient);
558
559 // Remove ourselves from the scene
560 m_scene.RemoveClient(AgentId, true);
561 SceneAgent = null;
562
563 // We can't reach into other scenes and close the connection
564 // We need to do this over grid communications
565 //m_scene.CloseAllAgents(CircuitCode);
566
567 // Disable UDP handling for this client
568 m_udpClient.Shutdown();
569
570 //m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false));
571 //GC.Collect();
572 //m_log.InfoFormat("[CLIENTVIEW] Memory post GC {0}", System.GC.GetTotalMemory(true));
573 }
574
575 public void Kick(string message)
576 {
577 if (!SceneAgent.IsChildAgent)
578 {
579 KickUserPacket kupack = (KickUserPacket)PacketPool.Instance.GetPacket(PacketType.KickUser);
580 kupack.UserInfo.AgentID = AgentId;
581 kupack.UserInfo.SessionID = SessionId;
582 kupack.TargetBlock.TargetIP = 0;
583 kupack.TargetBlock.TargetPort = 0;
584 kupack.UserInfo.Reason = Util.StringToBytes256(message);
585 OutPacket(kupack, ThrottleOutPacketType.Task);
586 // You must sleep here or users get no message!
587 Thread.Sleep(500);
588 }
589 }
590
591 public void Stop()
592 {
593
594 }
595
596 #endregion Client Methods
597
598 #region Packet Handling
599
600 public void PopulateStats(int inPackets, int outPackets, int unAckedBytes)
601 {
602 NetworkStats handlerNetworkStatsUpdate = OnNetworkStatsUpdate;
603 if (handlerNetworkStatsUpdate != null)
604 {
605 handlerNetworkStatsUpdate(inPackets, outPackets, unAckedBytes);
606 }
607 }
608
609 public static bool AddPacketHandler(PacketType packetType, PacketMethod handler)
610 {
611 bool result = false;
612 lock (PacketHandlers)
613 {
614 if (!PacketHandlers.ContainsKey(packetType))
615 {
616 PacketHandlers.Add(packetType, handler);
617 result = true;
618 }
619 }
620 return result;
621 }
622
623 /// <summary>
624 /// Add a handler for the given packet type.
625 /// </summary>
626 /// <remarks>
627 /// The packet is handled on its own thread. If packets must be handled in the order in which they
628 /// are received then please use the synchronous version of this method.
629 /// </remarks>
630 /// <param name="packetType"></param>
631 /// <param name="handler"></param>
632 /// <returns>true if the handler was added. This is currently always the case.</returns>
633 public bool AddLocalPacketHandler(PacketType packetType, PacketMethod handler)
634 {
635 return AddLocalPacketHandler(packetType, handler, true);
636 }
637
638 /// <summary>
639 /// Add a handler for the given packet type.
640 /// </summary>
641 /// <param name="packetType"></param>
642 /// <param name="handler"></param>
643 /// <param name="doAsync">
644 /// If true, when the packet is received it is handled on its own thread rather than on the main inward bound
645 /// packet handler thread. This vastly increases respnosiveness but some packets need to be handled
646 /// synchronously.
647 /// </param>
648 /// <returns>true if the handler was added. This is currently always the case.</returns>
649 public bool AddLocalPacketHandler(PacketType packetType, PacketMethod handler, bool doAsync)
650 {
651 return AddLocalPacketHandler(packetType, handler, doAsync, false);
652 }
653
654 /// <summary>
655 /// Add a handler for the given packet type.
656 /// </summary>
657 /// <param name="packetType"></param>
658 /// <param name="handler"></param>
659 /// <param name="doAsync">
660 /// If true, when the packet is received handle it on a different thread. Whether this is given direct to
661 /// a threadpool thread or placed in a queue depends on the inEngine parameter.
662 /// </param>
663 /// <param name="inEngine">
664 /// If async is false then this parameter is ignored.
665 /// If async is true and inEngine is false, then the packet is sent directly to a
666 /// threadpool thread.
667 /// If async is true and inEngine is true, then the packet is sent to the IncomingPacketAsyncHandlingEngine.
668 /// This may result in slower handling but reduces the risk of overloading the simulator when there are many
669 /// simultaneous async requests.
670 /// </param>
671 /// <returns>true if the handler was added. This is currently always the case.</returns>
672 public bool AddLocalPacketHandler(PacketType packetType, PacketMethod handler, bool doAsync, bool inEngine)
673 {
674 bool result = false;
675 lock (m_packetHandlers)
676 {
677 if (!m_packetHandlers.ContainsKey(packetType))
678 {
679 m_packetHandlers.Add(
680 packetType, new PacketProcessor() { method = handler, Async = doAsync, InEngine = inEngine });
681 result = true;
682 }
683 }
684
685 return result;
686 }
687
688 public bool AddGenericPacketHandler(string MethodName, GenericMessage handler)
689 {
690 MethodName = MethodName.ToLower().Trim();
691
692 bool result = false;
693 lock (m_genericPacketHandlers)
694 {
695 if (!m_genericPacketHandlers.ContainsKey(MethodName))
696 {
697 m_genericPacketHandlers.Add(MethodName, handler);
698 result = true;
699 }
700 }
701 return result;
702 }
703
704 /// <summary>
705 /// Try to process a packet using registered packet handlers
706 /// </summary>
707 /// <param name="packet"></param>
708 /// <returns>True if a handler was found which successfully processed the packet.</returns>
709 protected virtual bool ProcessPacketMethod(Packet packet)
710 {
711 bool result = false;
712 PacketProcessor pprocessor;
713 if (m_packetHandlers.TryGetValue(packet.Type, out pprocessor))
714 {
715 ClientInfo cinfo = UDPClient.GetClientInfo();
716
717 //there is a local handler for this packet type
718 if (pprocessor.Async)
719 {
720 if (!cinfo.AsyncRequests.ContainsKey(packet.Type.ToString()))
721 cinfo.AsyncRequests[packet.Type.ToString()] = 0;
722 cinfo.AsyncRequests[packet.Type.ToString()]++;
723
724 object obj = new AsyncPacketProcess(this, pprocessor.method, packet);
725
726 if (pprocessor.InEngine)
727 m_udpServer.IpahEngine.QueueJob(packet.Type.ToString(), () => ProcessSpecificPacketAsync(obj));
728 else
729 Util.FireAndForget(ProcessSpecificPacketAsync, obj, packet.Type.ToString());
730
731 result = true;
732 }
733 else
734 {
735 if (!cinfo.SyncRequests.ContainsKey(packet.Type.ToString()))
736 cinfo.SyncRequests[packet.Type.ToString()] = 0;
737 cinfo.SyncRequests[packet.Type.ToString()]++;
738
739 result = pprocessor.method(this, packet);
740 }
741 }
742 else
743 {
744 //there is not a local handler so see if there is a Global handler
745 PacketMethod method = null;
746 bool found;
747 lock (PacketHandlers)
748 {
749 found = PacketHandlers.TryGetValue(packet.Type, out method);
750 }
751 if (found)
752 {
753 ClientInfo cinfo = UDPClient.GetClientInfo();
754 if (!cinfo.GenericRequests.ContainsKey(packet.Type.ToString()))
755 cinfo.GenericRequests[packet.Type.ToString()] = 0;
756 cinfo.GenericRequests[packet.Type.ToString()]++;
757
758 result = method(this, packet);
759 }
760 }
761 return result;
762 }
763
764 public void ProcessSpecificPacketAsync(object state)
765 {
766 AsyncPacketProcess packetObject = (AsyncPacketProcess)state;
767
768 try
769 {
770 packetObject.result = packetObject.Method(packetObject.ClientView, packetObject.Pack);
771 }
772 catch (Exception e)
773 {
774 // Make sure that we see any exception caused by the asynchronous operation.
775 m_log.Error(
776 string.Format(
777 "[LLCLIENTVIEW]: Caught exception while processing {0} for {1} ", packetObject.Pack, Name),
778 e);
779 }
780 }
781
782 #endregion Packet Handling
783
784 # region Setup
785
786 public virtual void Start()
787 {
788 m_scene.AddNewAgent(this, PresenceType.User);
789
790 RefreshGroupMembership();
791 }
792
793 # endregion
794
795 public void ActivateGesture(UUID assetId, UUID gestureId)
796 {
797 }
798
799 public void DeactivateGesture(UUID assetId, UUID gestureId)
800 {
801 }
802
803 // Sound
804 public void SoundTrigger(UUID soundId, UUID owerid, UUID Objectid, UUID ParentId, float Gain, Vector3 Position, UInt64 Handle)
805 {
806 }
807
808 #region Scene/Avatar to Client
809
810 public void SendRegionHandshake(RegionInfo regionInfo, RegionHandshakeArgs args)
811 {
812 RegionHandshakePacket handshake = (RegionHandshakePacket)PacketPool.Instance.GetPacket(PacketType.RegionHandshake);
813 handshake.RegionInfo = new RegionHandshakePacket.RegionInfoBlock();
814 handshake.RegionInfo.BillableFactor = args.billableFactor;
815 handshake.RegionInfo.IsEstateManager = args.isEstateManager;
816 handshake.RegionInfo.TerrainHeightRange00 = args.terrainHeightRange0;
817 handshake.RegionInfo.TerrainHeightRange01 = args.terrainHeightRange1;
818 handshake.RegionInfo.TerrainHeightRange10 = args.terrainHeightRange2;
819 handshake.RegionInfo.TerrainHeightRange11 = args.terrainHeightRange3;
820 handshake.RegionInfo.TerrainStartHeight00 = args.terrainStartHeight0;
821 handshake.RegionInfo.TerrainStartHeight01 = args.terrainStartHeight1;
822 handshake.RegionInfo.TerrainStartHeight10 = args.terrainStartHeight2;
823 handshake.RegionInfo.TerrainStartHeight11 = args.terrainStartHeight3;
824 handshake.RegionInfo.SimAccess = args.simAccess;
825 handshake.RegionInfo.WaterHeight = args.waterHeight;
826
827 handshake.RegionInfo.RegionFlags = args.regionFlags;
828 handshake.RegionInfo.SimName = Util.StringToBytes256(args.regionName);
829 handshake.RegionInfo.SimOwner = args.SimOwner;
830 handshake.RegionInfo.TerrainBase0 = args.terrainBase0;
831 handshake.RegionInfo.TerrainBase1 = args.terrainBase1;
832 handshake.RegionInfo.TerrainBase2 = args.terrainBase2;
833 handshake.RegionInfo.TerrainBase3 = args.terrainBase3;
834 handshake.RegionInfo.TerrainDetail0 = args.terrainDetail0;
835 handshake.RegionInfo.TerrainDetail1 = args.terrainDetail1;
836 handshake.RegionInfo.TerrainDetail2 = args.terrainDetail2;
837 handshake.RegionInfo.TerrainDetail3 = args.terrainDetail3;
838 handshake.RegionInfo.CacheID = UUID.Random(); //I guess this is for the client to remember an old setting?
839 handshake.RegionInfo2 = new RegionHandshakePacket.RegionInfo2Block();
840 handshake.RegionInfo2.RegionID = regionInfo.RegionID;
841
842 handshake.RegionInfo3 = new RegionHandshakePacket.RegionInfo3Block();
843 handshake.RegionInfo3.CPUClassID = 9;
844 handshake.RegionInfo3.CPURatio = 1;
845
846 handshake.RegionInfo3.ColoName = Utils.EmptyBytes;
847 handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType);
848 handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes;
849
850 handshake.RegionInfo4 = new RegionHandshakePacket.RegionInfo4Block[1];
851 handshake.RegionInfo4[0] = new RegionHandshakePacket.RegionInfo4Block();
852 handshake.RegionInfo4[0].RegionFlagsExtended = args.regionFlags;
853 handshake.RegionInfo4[0].RegionProtocols = 0; // 1 here would indicate that SSB is supported
854
855 OutPacket(handshake, ThrottleOutPacketType.Unknown);
856 }
857
858
859 public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look)
860 {
861 AgentMovementCompletePacket mov = (AgentMovementCompletePacket)PacketPool.Instance.GetPacket(PacketType.AgentMovementComplete);
862 mov.SimData.ChannelVersion = m_channelVersion;
863 mov.AgentData.SessionID = m_sessionId;
864 mov.AgentData.AgentID = AgentId;
865 mov.Data.RegionHandle = regInfo.RegionHandle;
866 mov.Data.Timestamp = (uint)Util.UnixTimeSinceEpoch();
867
868 if ((pos.X == 0) && (pos.Y == 0) && (pos.Z == 0))
869 {
870 mov.Data.Position = m_startpos;
871 }
872 else
873 {
874 mov.Data.Position = pos;
875 }
876 mov.Data.LookAt = look;
877
878 // Hack to get this out immediately and skip the throttles
879 OutPacket(mov, ThrottleOutPacketType.Unknown);
880 }
881
882 public void SendChatMessage(
883 string message, byte type, Vector3 fromPos, string fromName,
884 UUID fromAgentID, UUID ownerID, byte source, byte audible)
885 {
886 ChatFromSimulatorPacket reply = (ChatFromSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.ChatFromSimulator);
887 reply.ChatData.Audible = audible;
888 reply.ChatData.Message = Util.StringToBytes1024(message);
889 reply.ChatData.ChatType = type;
890 reply.ChatData.SourceType = source;
891 reply.ChatData.Position = fromPos;
892 reply.ChatData.FromName = Util.StringToBytes256(fromName);
893 reply.ChatData.OwnerID = ownerID;
894 reply.ChatData.SourceID = fromAgentID;
895
896 OutPacket(reply, ThrottleOutPacketType.Task);
897 }
898
899 /// <summary>
900 /// Send an instant message to this client
901 /// </summary>
902 //
903 // Don't remove transaction ID! Groups and item gives need to set it!
904 public void SendInstantMessage(GridInstantMessage im)
905 {
906 if (((Scene)(m_scene)).Permissions.CanInstantMessage(new UUID(im.fromAgentID), new UUID(im.toAgentID)))
907 {
908 ImprovedInstantMessagePacket msg
909 = (ImprovedInstantMessagePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedInstantMessage);
910
911 msg.AgentData.AgentID = new UUID(im.fromAgentID);
912 msg.AgentData.SessionID = UUID.Zero;
913 msg.MessageBlock.FromAgentName = Util.StringToBytes256(im.fromAgentName);
914 msg.MessageBlock.Dialog = im.dialog;
915 msg.MessageBlock.FromGroup = im.fromGroup;
916 if (im.imSessionID == UUID.Zero.Guid)
917 msg.MessageBlock.ID = new UUID(im.fromAgentID) ^ new UUID(im.toAgentID);
918 else
919 msg.MessageBlock.ID = new UUID(im.imSessionID);
920 msg.MessageBlock.Offline = im.offline;
921 msg.MessageBlock.ParentEstateID = im.ParentEstateID;
922 msg.MessageBlock.Position = im.Position;
923 msg.MessageBlock.RegionID = new UUID(im.RegionID);
924 msg.MessageBlock.Timestamp = im.timestamp;
925 msg.MessageBlock.ToAgentID = new UUID(im.toAgentID);
926 msg.MessageBlock.Message = Util.StringToBytes1024(im.message);
927 msg.MessageBlock.BinaryBucket = im.binaryBucket;
928
929 if (im.message.StartsWith("[grouptest]"))
930 { // this block is test code for implementing group IM - delete when group IM is finished
931 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>();
932 if (eq != null)
933 {
934 im.dialog = 17;
935
936 //eq.ChatterboxInvitation(
937 // new UUID("00000000-68f9-1111-024e-222222111123"),
938 // "OpenSimulator Testing", im.fromAgentID, im.message, im.toAgentID, im.fromAgentName, im.dialog, 0,
939 // false, 0, new Vector3(), 1, im.imSessionID, im.fromGroup, im.binaryBucket);
940
941 eq.ChatterboxInvitation(
942 new UUID("00000000-68f9-1111-024e-222222111123"),
943 "OpenSimulator Testing", new UUID(im.fromAgentID), im.message, new UUID(im.toAgentID), im.fromAgentName, im.dialog, 0,
944 false, 0, new Vector3(), 1, new UUID(im.imSessionID), im.fromGroup, Util.StringToBytes256("OpenSimulator Testing"));
945
946 eq.ChatterBoxSessionAgentListUpdates(
947 new UUID("00000000-68f9-1111-024e-222222111123"),
948 new UUID(im.fromAgentID), new UUID(im.toAgentID), false, false, false);
949 }
950
951 Console.WriteLine("SendInstantMessage: " + msg);
952 }
953 else
954 OutPacket(msg, ThrottleOutPacketType.Task);
955 }
956 }
957
958 public void SendGenericMessage(string method, UUID invoice, List<string> message)
959 {
960 GenericMessagePacket gmp = new GenericMessagePacket();
961
962 gmp.AgentData.AgentID = AgentId;
963 gmp.AgentData.SessionID = m_sessionId;
964 gmp.AgentData.TransactionID = invoice;
965
966 gmp.MethodData.Method = Util.StringToBytes256(method);
967 gmp.ParamList = new GenericMessagePacket.ParamListBlock[message.Count];
968 int i = 0;
969 foreach (string val in message)
970 {
971 gmp.ParamList[i] = new GenericMessagePacket.ParamListBlock();
972 gmp.ParamList[i++].Parameter = Util.StringToBytes256(val);
973 }
974
975 OutPacket(gmp, ThrottleOutPacketType.Task);
976 }
977
978 public void SendGenericMessage(string method, UUID invoice, List<byte[]> message)
979 {
980 GenericMessagePacket gmp = new GenericMessagePacket();
981
982 gmp.AgentData.AgentID = AgentId;
983 gmp.AgentData.SessionID = m_sessionId;
984 gmp.AgentData.TransactionID = invoice;
985
986 gmp.MethodData.Method = Util.StringToBytes256(method);
987 gmp.ParamList = new GenericMessagePacket.ParamListBlock[message.Count];
988 int i = 0;
989 foreach (byte[] val in message)
990 {
991 gmp.ParamList[i] = new GenericMessagePacket.ParamListBlock();
992 gmp.ParamList[i++].Parameter = val;
993 }
994
995 OutPacket(gmp, ThrottleOutPacketType.Task);
996 }
997
998 public void SendGroupActiveProposals(UUID groupID, UUID transactionID, GroupActiveProposals[] Proposals)
999 {
1000 int i = 0;
1001 foreach (GroupActiveProposals Proposal in Proposals)
1002 {
1003 GroupActiveProposalItemReplyPacket GAPIRP = new GroupActiveProposalItemReplyPacket();
1004
1005 GAPIRP.AgentData.AgentID = AgentId;
1006 GAPIRP.AgentData.GroupID = groupID;
1007 GAPIRP.TransactionData.TransactionID = transactionID;
1008 GAPIRP.TransactionData.TotalNumItems = ((uint)i+1);
1009 GroupActiveProposalItemReplyPacket.ProposalDataBlock ProposalData = new GroupActiveProposalItemReplyPacket.ProposalDataBlock();
1010 GAPIRP.ProposalData = new GroupActiveProposalItemReplyPacket.ProposalDataBlock[1];
1011 ProposalData.VoteCast = Utils.StringToBytes("false");
1012 ProposalData.VoteID = new UUID(Proposal.VoteID);
1013 ProposalData.VoteInitiator = new UUID(Proposal.VoteInitiator);
1014 ProposalData.Majority = (float)Convert.ToInt32(Proposal.Majority);
1015 ProposalData.Quorum = Convert.ToInt32(Proposal.Quorum);
1016 ProposalData.TerseDateID = Utils.StringToBytes(Proposal.TerseDateID);
1017 ProposalData.StartDateTime = Utils.StringToBytes(Proposal.StartDateTime);
1018 ProposalData.EndDateTime = Utils.StringToBytes(Proposal.EndDateTime);
1019 ProposalData.ProposalText = Utils.StringToBytes(Proposal.ProposalText);
1020 ProposalData.AlreadyVoted = false;
1021 GAPIRP.ProposalData[i] = ProposalData;
1022 OutPacket(GAPIRP, ThrottleOutPacketType.Task);
1023 i++;
1024 }
1025 if (Proposals.Length == 0)
1026 {
1027 GroupActiveProposalItemReplyPacket GAPIRP = new GroupActiveProposalItemReplyPacket();
1028
1029 GAPIRP.AgentData.AgentID = AgentId;
1030 GAPIRP.AgentData.GroupID = groupID;
1031 GAPIRP.TransactionData.TransactionID = transactionID;
1032 GAPIRP.TransactionData.TotalNumItems = 1;
1033 GroupActiveProposalItemReplyPacket.ProposalDataBlock ProposalData = new GroupActiveProposalItemReplyPacket.ProposalDataBlock();
1034 GAPIRP.ProposalData = new GroupActiveProposalItemReplyPacket.ProposalDataBlock[1];
1035 ProposalData.VoteCast = Utils.StringToBytes("false");
1036 ProposalData.VoteID = UUID.Zero;
1037 ProposalData.VoteInitiator = UUID.Zero;
1038 ProposalData.Majority = 0;
1039 ProposalData.Quorum = 0;
1040 ProposalData.TerseDateID = Utils.StringToBytes("");
1041 ProposalData.StartDateTime = Utils.StringToBytes("");
1042 ProposalData.EndDateTime = Utils.StringToBytes("");
1043 ProposalData.ProposalText = Utils.StringToBytes("");
1044 ProposalData.AlreadyVoted = false;
1045 GAPIRP.ProposalData[0] = ProposalData;
1046 OutPacket(GAPIRP, ThrottleOutPacketType.Task);
1047 }
1048 }
1049
1050 public void SendGroupVoteHistory(UUID groupID, UUID transactionID, GroupVoteHistory[] Votes)
1051 {
1052 int i = 0;
1053 foreach (GroupVoteHistory Vote in Votes)
1054 {
1055 GroupVoteHistoryItemReplyPacket GVHIRP = new GroupVoteHistoryItemReplyPacket();
1056
1057 GVHIRP.AgentData.AgentID = AgentId;
1058 GVHIRP.AgentData.GroupID = groupID;
1059 GVHIRP.TransactionData.TransactionID = transactionID;
1060 GVHIRP.TransactionData.TotalNumItems = ((uint)i+1);
1061 GVHIRP.HistoryItemData.VoteID = new UUID(Vote.VoteID);
1062 GVHIRP.HistoryItemData.VoteInitiator = new UUID(Vote.VoteInitiator);
1063 GVHIRP.HistoryItemData.Majority = (float)Convert.ToInt32(Vote.Majority);
1064 GVHIRP.HistoryItemData.Quorum = Convert.ToInt32(Vote.Quorum);
1065 GVHIRP.HistoryItemData.TerseDateID = Utils.StringToBytes(Vote.TerseDateID);
1066 GVHIRP.HistoryItemData.StartDateTime = Utils.StringToBytes(Vote.StartDateTime);
1067 GVHIRP.HistoryItemData.EndDateTime = Utils.StringToBytes(Vote.EndDateTime);
1068 GVHIRP.HistoryItemData.VoteType = Utils.StringToBytes(Vote.VoteType);
1069 GVHIRP.HistoryItemData.VoteResult = Utils.StringToBytes(Vote.VoteResult);
1070 GVHIRP.HistoryItemData.ProposalText = Utils.StringToBytes(Vote.ProposalText);
1071 GroupVoteHistoryItemReplyPacket.VoteItemBlock VoteItem = new GroupVoteHistoryItemReplyPacket.VoteItemBlock();
1072 GVHIRP.VoteItem = new GroupVoteHistoryItemReplyPacket.VoteItemBlock[1];
1073 VoteItem.CandidateID = UUID.Zero;
1074 VoteItem.NumVotes = 0; //TODO: FIX THIS!!!
1075 VoteItem.VoteCast = Utils.StringToBytes("Yes");
1076 GVHIRP.VoteItem[i] = VoteItem;
1077 OutPacket(GVHIRP, ThrottleOutPacketType.Task);
1078 i++;
1079 }
1080 if (Votes.Length == 0)
1081 {
1082 GroupVoteHistoryItemReplyPacket GVHIRP = new GroupVoteHistoryItemReplyPacket();
1083
1084 GVHIRP.AgentData.AgentID = AgentId;
1085 GVHIRP.AgentData.GroupID = groupID;
1086 GVHIRP.TransactionData.TransactionID = transactionID;
1087 GVHIRP.TransactionData.TotalNumItems = 0;
1088 GVHIRP.HistoryItemData.VoteID = UUID.Zero;
1089 GVHIRP.HistoryItemData.VoteInitiator = UUID.Zero;
1090 GVHIRP.HistoryItemData.Majority = 0;
1091 GVHIRP.HistoryItemData.Quorum = 0;
1092 GVHIRP.HistoryItemData.TerseDateID = Utils.StringToBytes("");
1093 GVHIRP.HistoryItemData.StartDateTime = Utils.StringToBytes("");
1094 GVHIRP.HistoryItemData.EndDateTime = Utils.StringToBytes("");
1095 GVHIRP.HistoryItemData.VoteType = Utils.StringToBytes("");
1096 GVHIRP.HistoryItemData.VoteResult = Utils.StringToBytes("");
1097 GVHIRP.HistoryItemData.ProposalText = Utils.StringToBytes("");
1098 GroupVoteHistoryItemReplyPacket.VoteItemBlock VoteItem = new GroupVoteHistoryItemReplyPacket.VoteItemBlock();
1099 GVHIRP.VoteItem = new GroupVoteHistoryItemReplyPacket.VoteItemBlock[1];
1100 VoteItem.CandidateID = UUID.Zero;
1101 VoteItem.NumVotes = 0; //TODO: FIX THIS!!!
1102 VoteItem.VoteCast = Utils.StringToBytes("No");
1103 GVHIRP.VoteItem[0] = VoteItem;
1104 OutPacket(GVHIRP, ThrottleOutPacketType.Task);
1105 }
1106 }
1107
1108 public void SendGroupAccountingDetails(IClientAPI sender,UUID groupID, UUID transactionID, UUID sessionID, int amt)
1109 {
1110 GroupAccountDetailsReplyPacket GADRP = new GroupAccountDetailsReplyPacket();
1111 GADRP.AgentData = new GroupAccountDetailsReplyPacket.AgentDataBlock();
1112 GADRP.AgentData.AgentID = sender.AgentId;
1113 GADRP.AgentData.GroupID = groupID;
1114 GADRP.HistoryData = new GroupAccountDetailsReplyPacket.HistoryDataBlock[1];
1115 GroupAccountDetailsReplyPacket.HistoryDataBlock History = new GroupAccountDetailsReplyPacket.HistoryDataBlock();
1116 GADRP.MoneyData = new GroupAccountDetailsReplyPacket.MoneyDataBlock();
1117 GADRP.MoneyData.CurrentInterval = 0;
1118 GADRP.MoneyData.IntervalDays = 7;
1119 GADRP.MoneyData.RequestID = transactionID;
1120 GADRP.MoneyData.StartDate = Utils.StringToBytes(DateTime.Today.ToString());
1121 History.Amount = amt;
1122 History.Description = Utils.StringToBytes("");
1123 GADRP.HistoryData[0] = History;
1124 OutPacket(GADRP, ThrottleOutPacketType.Task);
1125 }
1126
1127 public void SendGroupAccountingSummary(IClientAPI sender,UUID groupID, uint moneyAmt, int totalTier, int usedTier)
1128 {
1129 GroupAccountSummaryReplyPacket GASRP =
1130 (GroupAccountSummaryReplyPacket)PacketPool.Instance.GetPacket(
1131 PacketType.GroupAccountSummaryReply);
1132
1133 GASRP.AgentData = new GroupAccountSummaryReplyPacket.AgentDataBlock();
1134 GASRP.AgentData.AgentID = sender.AgentId;
1135 GASRP.AgentData.GroupID = groupID;
1136 GASRP.MoneyData = new GroupAccountSummaryReplyPacket.MoneyDataBlock();
1137 GASRP.MoneyData.Balance = (int)moneyAmt;
1138 GASRP.MoneyData.TotalCredits = totalTier;
1139 GASRP.MoneyData.TotalDebits = usedTier;
1140 GASRP.MoneyData.StartDate = new byte[1];
1141 GASRP.MoneyData.CurrentInterval = 1;
1142 GASRP.MoneyData.GroupTaxCurrent = 0;
1143 GASRP.MoneyData.GroupTaxEstimate = 0;
1144 GASRP.MoneyData.IntervalDays = 0;
1145 GASRP.MoneyData.LandTaxCurrent = 0;
1146 GASRP.MoneyData.LandTaxEstimate = 0;
1147 GASRP.MoneyData.LastTaxDate = new byte[1];
1148 GASRP.MoneyData.LightTaxCurrent = 0;
1149 GASRP.MoneyData.TaxDate = new byte[1];
1150 GASRP.MoneyData.RequestID = sender.AgentId;
1151 GASRP.MoneyData.ParcelDirFeeEstimate = 0;
1152 GASRP.MoneyData.ParcelDirFeeCurrent = 0;
1153 GASRP.MoneyData.ObjectTaxEstimate = 0;
1154 GASRP.MoneyData.NonExemptMembers = 0;
1155 GASRP.MoneyData.ObjectTaxCurrent = 0;
1156 GASRP.MoneyData.LightTaxEstimate = 0;
1157 OutPacket(GASRP, ThrottleOutPacketType.Task);
1158 }
1159
1160 public void SendGroupTransactionsSummaryDetails(IClientAPI sender,UUID groupID, UUID transactionID, UUID sessionID, int amt)
1161 {
1162 GroupAccountTransactionsReplyPacket GATRP =
1163 (GroupAccountTransactionsReplyPacket)PacketPool.Instance.GetPacket(
1164 PacketType.GroupAccountTransactionsReply);
1165
1166 GATRP.AgentData = new GroupAccountTransactionsReplyPacket.AgentDataBlock();
1167 GATRP.AgentData.AgentID = sender.AgentId;
1168 GATRP.AgentData.GroupID = groupID;
1169 GATRP.MoneyData = new GroupAccountTransactionsReplyPacket.MoneyDataBlock();
1170 GATRP.MoneyData.CurrentInterval = 0;
1171 GATRP.MoneyData.IntervalDays = 7;
1172 GATRP.MoneyData.RequestID = transactionID;
1173 GATRP.MoneyData.StartDate = Utils.StringToBytes(DateTime.Today.ToString());
1174 GATRP.HistoryData = new GroupAccountTransactionsReplyPacket.HistoryDataBlock[1];
1175 GroupAccountTransactionsReplyPacket.HistoryDataBlock History = new GroupAccountTransactionsReplyPacket.HistoryDataBlock();
1176 History.Amount = 0;
1177 History.Item = Utils.StringToBytes("");
1178 History.Time = Utils.StringToBytes("");
1179 History.Type = 0;
1180 History.User = Utils.StringToBytes("");
1181 GATRP.HistoryData[0] = History;
1182 OutPacket(GATRP, ThrottleOutPacketType.Task);
1183 }
1184
1185 /// <summary>
1186 /// Send the region heightmap to the client
1187 /// This method is only called when not doing intellegent terrain patch sending and
1188 /// is only called when the scene presence is initially created and sends all of the
1189 /// region's patches to the client.
1190 /// </summary>
1191 /// <param name="map">heightmap</param>
1192 public virtual void SendLayerData(float[] map)
1193 {
1194 Util.FireAndForget(DoSendLayerData, m_scene.Heightmap.GetTerrainData(), "LLClientView.DoSendLayerData");
1195 }
1196
1197 /// <summary>
1198 /// Send terrain layer information to the client.
1199 /// </summary>
1200 /// <param name="o"></param>
1201 private void DoSendLayerData(object o)
1202 {
1203 TerrainData map = (TerrainData)o;
1204
1205 try
1206 {
1207 // Send LayerData in typerwriter pattern
1208 //for (int y = 0; y < 16; y++)
1209 //{
1210 // for (int x = 0; x < 16; x++)
1211 // {
1212 // SendLayerData(x, y, map);
1213 // }
1214 //}
1215
1216 // Send LayerData in a spiral pattern. Fun!
1217 SendLayerTopRight(map, 0, 0, map.SizeX/Constants.TerrainPatchSize-1, map.SizeY/Constants.TerrainPatchSize-1);
1218 }
1219 catch (Exception e)
1220 {
1221 m_log.Error("[CLIENT]: SendLayerData() Failed with exception: " + e.Message, e);
1222 }
1223 }
1224
1225 private void SendLayerTopRight(TerrainData map, int x1, int y1, int x2, int y2)
1226 {
1227 // Row
1228 for (int i = x1; i <= x2; i++)
1229 SendLayerData(i, y1, map);
1230
1231 // Column
1232 for (int j = y1 + 1; j <= y2; j++)
1233 SendLayerData(x2, j, map);
1234
1235 if (x2 - x1 > 0 && y2 - y1 > 0)
1236 SendLayerBottomLeft(map, x1, y1 + 1, x2 - 1, y2);
1237 }
1238
1239 void SendLayerBottomLeft(TerrainData map, int x1, int y1, int x2, int y2)
1240 {
1241 // Row in reverse
1242 for (int i = x2; i >= x1; i--)
1243 SendLayerData(i, y2, map);
1244
1245 // Column in reverse
1246 for (int j = y2 - 1; j >= y1; j--)
1247 SendLayerData(x1, j, map);
1248
1249 if (x2 - x1 > 0 && y2 - y1 > 0)
1250 SendLayerTopRight(map, x1 + 1, y1, x2, y2 - 1);
1251 }
1252
1253 /// <summary>
1254 /// Sends a set of four patches (x, x+1, ..., x+3) to the client
1255 /// </summary>
1256 /// <param name="map">heightmap</param>
1257 /// <param name="px">X coordinate for patches 0..12</param>
1258 /// <param name="py">Y coordinate for patches 0..15</param>
1259 // private void SendLayerPacket(float[] map, int y, int x)
1260 // {
1261 // int[] patches = new int[4];
1262 // patches[0] = x + 0 + y * 16;
1263 // patches[1] = x + 1 + y * 16;
1264 // patches[2] = x + 2 + y * 16;
1265 // patches[3] = x + 3 + y * 16;
1266
1267 // Packet layerpack = LLClientView.TerrainManager.CreateLandPacket(map, patches);
1268 // OutPacket(layerpack, ThrottleOutPacketType.Land);
1269 // }
1270
1271 // Legacy form of invocation that passes around a bare data array.
1272 // Just ignore what was passed and use the real terrain info that is part of the scene.
1273 // As a HORRIBLE kludge in an attempt to not change the definition of IClientAPI,
1274 // there is a special form for specifying multiple terrain patches to send.
1275 // The form is to pass 'px' as negative the number of patches to send and to
1276 // pass the float array as pairs of patch X and Y coordinates. So, passing 'px'
1277 // as -2 and map= [3, 5, 8, 4] would mean to send two terrain heightmap patches
1278 // and the patches to send are <3,5> and <8,4>.
1279 public void SendLayerData(int px, int py, float[] map)
1280 {
1281 if (px >= 0)
1282 {
1283 SendLayerData(px, py, m_scene.Heightmap.GetTerrainData());
1284 }
1285 else
1286 {
1287 int numPatches = -px;
1288 int[] xPatches = new int[numPatches];
1289 int[] yPatches = new int[numPatches];
1290 for (int pp = 0; pp < numPatches; pp++)
1291 {
1292 xPatches[pp] = (int)map[pp * 2];
1293 yPatches[pp] = (int)map[pp * 2 + 1];
1294 }
1295
1296 // DebugSendingPatches("SendLayerData", xPatches, yPatches);
1297
1298 SendLayerData(xPatches, yPatches, m_scene.Heightmap.GetTerrainData());
1299 }
1300 }
1301
1302 private void DebugSendingPatches(string pWho, int[] pX, int[] pY)
1303 {
1304 if (m_log.IsDebugEnabled)
1305 {
1306 int numPatches = pX.Length;
1307 string Xs = "";
1308 string Ys = "";
1309 for (int pp = 0; pp < numPatches; pp++)
1310 {
1311 Xs += String.Format("{0}", (int)pX[pp]) + ",";
1312 Ys += String.Format("{0}", (int)pY[pp]) + ",";
1313 }
1314 m_log.DebugFormat("{0} {1}: numPatches={2}, X={3}, Y={4}", LogHeader, pWho, numPatches, Xs, Ys);
1315 }
1316 }
1317
1318 /// <summary>
1319 /// Sends a terrain packet for the point specified.
1320 /// This is a legacy call that has refarbed the terrain into a flat map of floats.
1321 /// We just use the terrain from the region we know about.
1322 /// </summary>
1323 /// <param name="px">Patch coordinate (x) 0..15</param>
1324 /// <param name="py">Patch coordinate (y) 0..15</param>
1325 /// <param name="map">heightmap</param>
1326 public void SendLayerData(int px, int py, TerrainData terrData)
1327 {
1328 int[] xPatches = new[] { px };
1329 int[] yPatches = new[] { py };
1330 SendLayerData(xPatches, yPatches, terrData);
1331 }
1332
1333 private void SendLayerData(int[] px, int[] py, TerrainData terrData)
1334 {
1335 try
1336 {
1337 /* test code using the terrain compressor in libOpenMetaverse
1338 int[] patchInd = new int[1];
1339 patchInd[0] = px + (py * Constants.TerrainPatchSize);
1340 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(terrData.GetFloatsSerialized(), patchInd);
1341 */
1342 // Many, many patches could have been passed to us. Since the patches will be compressed
1343 // into variable sized blocks, we cannot pre-compute how many will fit into one
1344 // packet. While some fancy packing algorithm is possible, 4 seems to always fit.
1345 int PatchesAssumedToFit = 4;
1346 for (int pcnt = 0; pcnt < px.Length; pcnt += PatchesAssumedToFit)
1347 {
1348 int remaining = Math.Min(px.Length - pcnt, PatchesAssumedToFit);
1349 int[] xPatches = new int[remaining];
1350 int[] yPatches = new int[remaining];
1351 for (int ii = 0; ii < remaining; ii++)
1352 {
1353 xPatches[ii] = px[pcnt + ii];
1354 yPatches[ii] = py[pcnt + ii];
1355 }
1356 LayerDataPacket layerpack = OpenSimTerrainCompressor.CreateLandPacket(terrData, xPatches, yPatches);
1357 // DebugSendingPatches("SendLayerDataInternal", xPatches, yPatches);
1358
1359 SendTheLayerPacket(layerpack);
1360 }
1361 // LayerDataPacket layerpack = OpenSimTerrainCompressor.CreateLandPacket(terrData, px, py);
1362
1363 }
1364 catch (Exception e)
1365 {
1366 m_log.Error("[CLIENT]: SendLayerData() Failed with exception: " + e.Message, e);
1367 }
1368 }
1369
1370 // When a user edits the terrain, so much data is sent, the data queues up fast and presents a
1371 // sub optimal editing experience. To alleviate this issue, when the user edits the terrain, we
1372 // start skipping the queues until they're done editing the terrain. We also make them
1373 // unreliable because it's extremely likely that multiple packets will be sent for a terrain patch
1374 // area invalidating previous packets for that area.
1375
1376 // It's possible for an editing user to flood themselves with edited packets but the majority
1377 // of use cases are such that only a tiny percentage of users will be editing the terrain.
1378 // Other, non-editing users will see the edits much slower.
1379
1380 // One last note on this topic, by the time users are going to be editing the terrain, it's
1381 // extremely likely that the sim will have rezzed already and therefore this is not likely going
1382 // to cause any additional issues with lost packets, objects or terrain patches.
1383
1384 // m_justEditedTerrain is volatile, so test once and duplicate two affected statements so we
1385 // only have one cache miss.
1386 private void SendTheLayerPacket(LayerDataPacket layerpack)
1387 {
1388 if (m_justEditedTerrain)
1389 {
1390 layerpack.Header.Reliable = false;
1391 OutPacket(layerpack, ThrottleOutPacketType.Unknown );
1392 }
1393 else
1394 {
1395 layerpack.Header.Reliable = true;
1396 OutPacket(layerpack, ThrottleOutPacketType.Land);
1397 }
1398 }
1399
1400 /// <summary>
1401 /// Send the wind matrix to the client
1402 /// </summary>
1403 /// <param name="windSpeeds">16x16 array of wind speeds</param>
1404 public virtual void SendWindData(Vector2[] windSpeeds)
1405 {
1406 Util.FireAndForget(DoSendWindData, windSpeeds, "LLClientView.SendWindData");
1407 }
1408
1409 /// <summary>
1410 /// Send the cloud matrix to the client
1411 /// </summary>
1412 /// <param name="windSpeeds">16x16 array of cloud densities</param>
1413 public virtual void SendCloudData(float[] cloudDensity)
1414 {
1415 Util.FireAndForget(DoSendCloudData, cloudDensity, "LLClientView.SendCloudData");
1416 }
1417
1418 /// <summary>
1419 /// Send wind layer information to the client.
1420 /// </summary>
1421 /// <param name="o"></param>
1422 private void DoSendWindData(object o)
1423 {
1424 Vector2[] windSpeeds = (Vector2[])o;
1425 TerrainPatch[] patches = new TerrainPatch[2];
1426 patches[0] = new TerrainPatch { Data = new float[16 * 16] };
1427 patches[1] = new TerrainPatch { Data = new float[16 * 16] };
1428
1429 for (int x = 0; x < 16 * 16; x++)
1430 {
1431 patches[0].Data[x] = windSpeeds[x].X;
1432 patches[1].Data[x] = windSpeeds[x].Y;
1433 }
1434
1435 byte layerType = (byte)TerrainPatch.LayerType.Wind;
1436 if (m_scene.RegionInfo.RegionSizeX > Constants.RegionSize || m_scene.RegionInfo.RegionSizeY > Constants.RegionSize)
1437 layerType = (byte)TerrainPatch.LayerType.WindExtended;
1438
1439 // LayerDataPacket layerpack = TerrainCompressor.CreateLayerDataPacket(patches, (TerrainPatch.LayerType)layerType);
1440 LayerDataPacket layerpack = OpenSimTerrainCompressor.CreateLayerDataPacket(patches, layerType,
1441 (int)m_scene.RegionInfo.RegionSizeX, (int)m_scene.RegionInfo.RegionSizeY);
1442 layerpack.Header.Zerocoded = true;
1443 OutPacket(layerpack, ThrottleOutPacketType.Wind);
1444 }
1445
1446 /// <summary>
1447 /// Send cloud layer information to the client.
1448 /// </summary>
1449 /// <param name="o"></param>
1450 private void DoSendCloudData(object o)
1451 {
1452 float[] cloudCover = (float[])o;
1453 TerrainPatch[] patches = new TerrainPatch[1];
1454 patches[0] = new TerrainPatch();
1455 patches[0].Data = new float[16 * 16];
1456
1457 for (int y = 0; y < 16; y++)
1458 {
1459 for (int x = 0; x < 16; x++)
1460 {
1461 patches[0].Data[y * 16 + x] = cloudCover[y * 16 + x];
1462 }
1463 }
1464
1465 byte layerType = (byte)TerrainPatch.LayerType.Cloud;
1466 if (m_scene.RegionInfo.RegionSizeX > Constants.RegionSize || m_scene.RegionInfo.RegionSizeY > Constants.RegionSize)
1467 layerType = (byte)TerrainPatch.LayerType.CloudExtended;
1468
1469 // LayerDataPacket layerpack = TerrainCompressor.CreateLayerDataPacket(patches, (TerrainPatch.LayerType)layerType);
1470 LayerDataPacket layerpack = OpenSimTerrainCompressor.CreateLayerDataPacket(patches, layerType,
1471 (int)m_scene.RegionInfo.RegionSizeX, (int)m_scene.RegionInfo.RegionSizeY);
1472 layerpack.Header.Zerocoded = true;
1473 OutPacket(layerpack, ThrottleOutPacketType.Cloud);
1474 }
1475
1476 /// <summary>
1477 /// Tell the client that the given neighbour region is ready to receive a child agent.
1478 /// </summary>
1479 public virtual void InformClientOfNeighbour(ulong neighbourHandle, IPEndPoint neighbourEndPoint)
1480 {
1481 IPAddress neighbourIP = neighbourEndPoint.Address;
1482 ushort neighbourPort = (ushort)neighbourEndPoint.Port;
1483
1484 EnableSimulatorPacket enablesimpacket = (EnableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.EnableSimulator);
1485 // TODO: don't create new blocks if recycling an old packet
1486 enablesimpacket.SimulatorInfo = new EnableSimulatorPacket.SimulatorInfoBlock();
1487 enablesimpacket.SimulatorInfo.Handle = neighbourHandle;
1488
1489 byte[] byteIP = neighbourIP.GetAddressBytes();
1490 enablesimpacket.SimulatorInfo.IP = (uint)byteIP[3] << 24;
1491 enablesimpacket.SimulatorInfo.IP += (uint)byteIP[2] << 16;
1492 enablesimpacket.SimulatorInfo.IP += (uint)byteIP[1] << 8;
1493 enablesimpacket.SimulatorInfo.IP += (uint)byteIP[0];
1494 enablesimpacket.SimulatorInfo.Port = neighbourPort;
1495
1496 enablesimpacket.Header.Reliable = true; // ESP's should be reliable.
1497
1498 OutPacket(enablesimpacket, ThrottleOutPacketType.Task);
1499 }
1500
1501 public AgentCircuitData RequestClientInfo()
1502 {
1503 AgentCircuitData agentData = new AgentCircuitData();
1504 agentData.AgentID = AgentId;
1505 agentData.SessionID = m_sessionId;
1506 agentData.SecureSessionID = SecureSessionId;
1507 agentData.circuitcode = m_circuitCode;
1508 agentData.child = false;
1509 agentData.firstname = m_firstName;
1510 agentData.lastname = m_lastName;
1511
1512 ICapabilitiesModule capsModule = m_scene.RequestModuleInterface<ICapabilitiesModule>();
1513
1514 if (capsModule == null) // can happen when shutting down.
1515 return agentData;
1516
1517 agentData.CapsPath = capsModule.GetCapsPath(m_agentId);
1518 agentData.ChildrenCapSeeds = new Dictionary<ulong, string>(capsModule.GetChildrenSeeds(m_agentId));
1519
1520 return agentData;
1521 }
1522
1523 public virtual void CrossRegion(ulong newRegionHandle, Vector3 pos, Vector3 lookAt, IPEndPoint externalIPEndPoint,
1524 string capsURL)
1525 {
1526 Vector3 look = new Vector3(lookAt.X * 10, lookAt.Y * 10, lookAt.Z * 10);
1527
1528 //CrossedRegionPacket newSimPack = (CrossedRegionPacket)PacketPool.Instance.GetPacket(PacketType.CrossedRegion);
1529 CrossedRegionPacket newSimPack = new CrossedRegionPacket();
1530 // TODO: don't create new blocks if recycling an old packet
1531 newSimPack.AgentData = new CrossedRegionPacket.AgentDataBlock();
1532 newSimPack.AgentData.AgentID = AgentId;
1533 newSimPack.AgentData.SessionID = m_sessionId;
1534 newSimPack.Info = new CrossedRegionPacket.InfoBlock();
1535 newSimPack.Info.Position = pos;
1536 newSimPack.Info.LookAt = look;
1537 newSimPack.RegionData = new CrossedRegionPacket.RegionDataBlock();
1538 newSimPack.RegionData.RegionHandle = newRegionHandle;
1539 byte[] byteIP = externalIPEndPoint.Address.GetAddressBytes();
1540 newSimPack.RegionData.SimIP = (uint)byteIP[3] << 24;
1541 newSimPack.RegionData.SimIP += (uint)byteIP[2] << 16;
1542 newSimPack.RegionData.SimIP += (uint)byteIP[1] << 8;
1543 newSimPack.RegionData.SimIP += (uint)byteIP[0];
1544 newSimPack.RegionData.SimPort = (ushort)externalIPEndPoint.Port;
1545 newSimPack.RegionData.SeedCapability = Util.StringToBytes256(capsURL);
1546
1547 // Hack to get this out immediately and skip throttles
1548 OutPacket(newSimPack, ThrottleOutPacketType.Unknown);
1549 }
1550
1551 internal void SendMapBlockSplit(List<MapBlockData> mapBlocks, uint flag)
1552 {
1553 MapBlockReplyPacket mapReply = (MapBlockReplyPacket)PacketPool.Instance.GetPacket(PacketType.MapBlockReply);
1554 // TODO: don't create new blocks if recycling an old packet
1555
1556 MapBlockData[] mapBlocks2 = mapBlocks.ToArray();
1557
1558 mapReply.AgentData.AgentID = AgentId;
1559 mapReply.Data = new MapBlockReplyPacket.DataBlock[mapBlocks2.Length];
1560 mapReply.Size = new MapBlockReplyPacket.SizeBlock[mapBlocks2.Length];
1561 mapReply.AgentData.Flags = flag;
1562
1563 for (int i = 0; i < mapBlocks2.Length; i++)
1564 {
1565 mapReply.Data[i] = new MapBlockReplyPacket.DataBlock();
1566 mapReply.Data[i].MapImageID = mapBlocks2[i].MapImageId;
1567 //m_log.Warn(mapBlocks2[i].MapImageId.ToString());
1568 mapReply.Data[i].X = mapBlocks2[i].X;
1569 mapReply.Data[i].Y = mapBlocks2[i].Y;
1570 mapReply.Data[i].WaterHeight = mapBlocks2[i].WaterHeight;
1571 mapReply.Data[i].Name = Utils.StringToBytes(mapBlocks2[i].Name);
1572 mapReply.Data[i].RegionFlags = mapBlocks2[i].RegionFlags;
1573 mapReply.Data[i].Access = mapBlocks2[i].Access;
1574 mapReply.Data[i].Agents = mapBlocks2[i].Agents;
1575
1576 mapReply.Size[i] = new MapBlockReplyPacket.SizeBlock();
1577 mapReply.Size[i].SizeX = mapBlocks2[i].SizeX;
1578 mapReply.Size[i].SizeY = mapBlocks2[i].SizeY;
1579 }
1580 OutPacket(mapReply, ThrottleOutPacketType.Land);
1581 }
1582
1583 public void SendMapBlock(List<MapBlockData> mapBlocks, uint flag)
1584 {
1585 MapBlockData[] mapBlocks2 = mapBlocks.ToArray();
1586
1587 int maxsend = 10;
1588
1589 //int packets = Math.Ceiling(mapBlocks2.Length / maxsend);
1590
1591 List<MapBlockData> sendingBlocks = new List<MapBlockData>();
1592
1593 for (int i = 0; i < mapBlocks2.Length; i++)
1594 {
1595 sendingBlocks.Add(mapBlocks2[i]);
1596 if (((i + 1) == mapBlocks2.Length) || (((i + 1) % maxsend) == 0))
1597 {
1598 SendMapBlockSplit(sendingBlocks, flag);
1599 sendingBlocks = new List<MapBlockData>();
1600 }
1601 }
1602 }
1603
1604 public void SendLocalTeleport(Vector3 position, Vector3 lookAt, uint flags)
1605 {
1606 TeleportLocalPacket tpLocal = (TeleportLocalPacket)PacketPool.Instance.GetPacket(PacketType.TeleportLocal);
1607 tpLocal.Info.AgentID = AgentId;
1608 tpLocal.Info.TeleportFlags = flags;
1609 tpLocal.Info.LocationID = 2;
1610 tpLocal.Info.LookAt = lookAt;
1611 tpLocal.Info.Position = position;
1612
1613 // Hack to get this out immediately and skip throttles
1614 OutPacket(tpLocal, ThrottleOutPacketType.Unknown);
1615 }
1616
1617 public virtual void SendRegionTeleport(ulong regionHandle, byte simAccess, IPEndPoint newRegionEndPoint, uint locationID,
1618 uint flags, string capsURL)
1619 {
1620 //TeleportFinishPacket teleport = (TeleportFinishPacket)PacketPool.Instance.GetPacket(PacketType.TeleportFinish);
1621
1622 TeleportFinishPacket teleport = new TeleportFinishPacket();
1623 teleport.Info.AgentID = AgentId;
1624 teleport.Info.RegionHandle = regionHandle;
1625 teleport.Info.SimAccess = simAccess;
1626
1627 teleport.Info.SeedCapability = Util.StringToBytes256(capsURL);
1628
1629 IPAddress oIP = newRegionEndPoint.Address;
1630 byte[] byteIP = oIP.GetAddressBytes();
1631 uint ip = (uint)byteIP[3] << 24;
1632 ip += (uint)byteIP[2] << 16;
1633 ip += (uint)byteIP[1] << 8;
1634 ip += (uint)byteIP[0];
1635
1636 teleport.Info.SimIP = ip;
1637 teleport.Info.SimPort = (ushort)newRegionEndPoint.Port;
1638 teleport.Info.LocationID = 4;
1639 teleport.Info.TeleportFlags = 1 << 4;
1640
1641 // Hack to get this out immediately and skip throttles.
1642 OutPacket(teleport, ThrottleOutPacketType.Unknown);
1643 }
1644
1645 /// <summary>
1646 /// Inform the client that a teleport attempt has failed
1647 /// </summary>
1648 public void SendTeleportFailed(string reason)
1649 {
1650 TeleportFailedPacket tpFailed = (TeleportFailedPacket)PacketPool.Instance.GetPacket(PacketType.TeleportFailed);
1651 tpFailed.Info.AgentID = AgentId;
1652 tpFailed.Info.Reason = Util.StringToBytes256(reason);
1653 tpFailed.AlertInfo = new TeleportFailedPacket.AlertInfoBlock[0];
1654
1655 // Hack to get this out immediately and skip throttles
1656 OutPacket(tpFailed, ThrottleOutPacketType.Unknown);
1657 }
1658
1659 /// <summary>
1660 ///
1661 /// </summary>
1662 public void SendTeleportStart(uint flags)
1663 {
1664 TeleportStartPacket tpStart = (TeleportStartPacket)PacketPool.Instance.GetPacket(PacketType.TeleportStart);
1665 //TeleportStartPacket tpStart = new TeleportStartPacket();
1666 tpStart.Info.TeleportFlags = flags; //16; // Teleport via location
1667
1668 // Hack to get this out immediately and skip throttles
1669 OutPacket(tpStart, ThrottleOutPacketType.Unknown);
1670 }
1671
1672 public void SendTeleportProgress(uint flags, string message)
1673 {
1674 TeleportProgressPacket tpProgress = (TeleportProgressPacket)PacketPool.Instance.GetPacket(PacketType.TeleportProgress);
1675 tpProgress.AgentData.AgentID = this.AgentId;
1676 tpProgress.Info.TeleportFlags = flags;
1677 tpProgress.Info.Message = Util.StringToBytes256(message);
1678
1679 // Hack to get this out immediately and skip throttles
1680 OutPacket(tpProgress, ThrottleOutPacketType.Unknown);
1681 }
1682
1683 public void SendMoneyBalance(UUID transaction, bool success, byte[] description, int balance, int transactionType, UUID sourceID, bool sourceIsGroup, UUID destID, bool destIsGroup, int amount, string item)
1684 {
1685 MoneyBalanceReplyPacket money = (MoneyBalanceReplyPacket)PacketPool.Instance.GetPacket(PacketType.MoneyBalanceReply);
1686 money.MoneyData.AgentID = AgentId;
1687 money.MoneyData.TransactionID = transaction;
1688 money.MoneyData.TransactionSuccess = success;
1689 money.MoneyData.Description = description;
1690 money.MoneyData.MoneyBalance = balance;
1691 money.TransactionInfo.TransactionType = transactionType;
1692 money.TransactionInfo.SourceID = sourceID;
1693 money.TransactionInfo.IsSourceGroup = sourceIsGroup;
1694 money.TransactionInfo.DestID = destID;
1695 money.TransactionInfo.IsDestGroup = destIsGroup;
1696 money.TransactionInfo.Amount = amount;
1697 money.TransactionInfo.ItemDescription = Util.StringToBytes256(item);
1698
1699 OutPacket(money, ThrottleOutPacketType.Task);
1700 }
1701
1702 public void SendPayPrice(UUID objectID, int[] payPrice)
1703 {
1704 if (payPrice[0] == 0 &&
1705 payPrice[1] == 0 &&
1706 payPrice[2] == 0 &&
1707 payPrice[3] == 0 &&
1708 payPrice[4] == 0)
1709 return;
1710
1711 PayPriceReplyPacket payPriceReply = (PayPriceReplyPacket)PacketPool.Instance.GetPacket(PacketType.PayPriceReply);
1712 payPriceReply.ObjectData.ObjectID = objectID;
1713 payPriceReply.ObjectData.DefaultPayPrice = payPrice[0];
1714
1715 payPriceReply.ButtonData = new PayPriceReplyPacket.ButtonDataBlock[4];
1716 payPriceReply.ButtonData[0] = new PayPriceReplyPacket.ButtonDataBlock();
1717 payPriceReply.ButtonData[0].PayButton = payPrice[1];
1718 payPriceReply.ButtonData[1] = new PayPriceReplyPacket.ButtonDataBlock();
1719 payPriceReply.ButtonData[1].PayButton = payPrice[2];
1720 payPriceReply.ButtonData[2] = new PayPriceReplyPacket.ButtonDataBlock();
1721 payPriceReply.ButtonData[2].PayButton = payPrice[3];
1722 payPriceReply.ButtonData[3] = new PayPriceReplyPacket.ButtonDataBlock();
1723 payPriceReply.ButtonData[3].PayButton = payPrice[4];
1724
1725 OutPacket(payPriceReply, ThrottleOutPacketType.Task);
1726 }
1727
1728 public void SendStartPingCheck(byte seq)
1729 {
1730 StartPingCheckPacket pc = (StartPingCheckPacket)PacketPool.Instance.GetPacket(PacketType.StartPingCheck);
1731 pc.Header.Reliable = false;
1732
1733 pc.PingID.PingID = seq;
1734 // We *could* get OldestUnacked, but it would hurt performance and not provide any benefit
1735 pc.PingID.OldestUnacked = 0;
1736
1737 OutPacket(pc, ThrottleOutPacketType.Unknown);
1738 }
1739
1740 public void SendKillObject(List<uint> localIDs)
1741 {
1742// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, localID, regionHandle);
1743
1744 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject);
1745 // TODO: don't create new blocks if recycling an old packet
1746 kill.ObjectData = new KillObjectPacket.ObjectDataBlock[localIDs.Count];
1747 for (int i = 0 ; i < localIDs.Count ; i++ )
1748 {
1749 kill.ObjectData[i] = new KillObjectPacket.ObjectDataBlock();
1750 kill.ObjectData[i].ID = localIDs[i];
1751 }
1752 kill.Header.Reliable = true;
1753 kill.Header.Zerocoded = true;
1754
1755 if (localIDs.Count == 1 && m_scene.GetScenePresence(localIDs[0]) != null)
1756 {
1757 OutPacket(kill, ThrottleOutPacketType.Task);
1758 }
1759 else
1760 {
1761 // We MUST lock for both manipulating the kill record and sending the packet, in order to avoid a race
1762 // condition where a kill can be processed before an out-of-date update for the same object.
1763 // ProcessEntityUpdates() also takes the m_killRecord lock.
1764 lock (m_killRecord)
1765 {
1766 foreach (uint localID in localIDs)
1767 m_killRecord.Add(localID);
1768
1769 // The throttle queue used here must match that being used for updates. Otherwise, there is a
1770 // chance that a kill packet put on a separate queue will be sent to the client before an existing
1771 // update packet on another queue. Receiving updates after kills results in unowned and undeletable
1772 // scene objects in a viewer until that viewer is relogged in.
1773 OutPacket(kill, ThrottleOutPacketType.Task);
1774 }
1775 }
1776 }
1777
1778 /// <summary>
1779 /// Send information about the items contained in a folder to the client.
1780 /// </summary>
1781 /// <remarks>
1782 /// XXX This method needs some refactoring loving
1783 /// </remarks>
1784 /// <param name="ownerID">The owner of the folder</param>
1785 /// <param name="folderID">The id of the folder</param>
1786 /// <param name="items">The items contained in the folder identified by folderID</param>
1787 /// <param name="folders"></param>
1788 /// <param name="fetchFolders">Do we need to send folder information?</param>
1789 /// <param name="fetchItems">Do we need to send item information?</param>
1790 public void SendInventoryFolderDetails(UUID ownerID, UUID folderID, List<InventoryItemBase> items,
1791 List<InventoryFolderBase> folders, int version,
1792 bool fetchFolders, bool fetchItems)
1793 {
1794 // An inventory descendents packet consists of a single agent section and an inventory details
1795 // section for each inventory item. The size of each inventory item is approximately 550 bytes.
1796 // In theory, UDP has a maximum packet size of 64k, so it should be possible to send descendent
1797 // packets containing metadata for in excess of 100 items. But in practice, there may be other
1798 // factors (e.g. firewalls) restraining the maximum UDP packet size. See,
1799 //
1800 // http://opensimulator.org/mantis/view.php?id=226
1801 //
1802 // for one example of this kind of thing. In fact, the Linden servers appear to only send about
1803 // 6 to 7 items at a time, so let's stick with 6
1804 int MAX_ITEMS_PER_PACKET = 5;
1805 int MAX_FOLDERS_PER_PACKET = 6;
1806
1807 int totalItems = fetchItems ? items.Count : 0;
1808 int totalFolders = fetchFolders ? folders.Count : 0;
1809 int itemsSent = 0;
1810 int foldersSent = 0;
1811 int foldersToSend = 0;
1812 int itemsToSend = 0;
1813
1814 InventoryDescendentsPacket currentPacket = null;
1815
1816 // Handle empty folders
1817 //
1818 if (totalItems == 0 && totalFolders == 0)
1819 currentPacket = CreateInventoryDescendentsPacket(ownerID, folderID, version, items.Count + folders.Count, 0, 0);
1820
1821 // To preserve SL compatibility, we will NOT combine folders and items in one packet
1822 //
1823 while (itemsSent < totalItems || foldersSent < totalFolders)
1824 {
1825 if (currentPacket == null) // Start a new packet
1826 {
1827 foldersToSend = totalFolders - foldersSent;
1828 if (foldersToSend > MAX_FOLDERS_PER_PACKET)
1829 foldersToSend = MAX_FOLDERS_PER_PACKET;
1830
1831 if (foldersToSend == 0)
1832 {
1833 itemsToSend = totalItems - itemsSent;
1834 if (itemsToSend > MAX_ITEMS_PER_PACKET)
1835 itemsToSend = MAX_ITEMS_PER_PACKET;
1836 }
1837
1838 currentPacket = CreateInventoryDescendentsPacket(ownerID, folderID, version, items.Count + folders.Count, foldersToSend, itemsToSend);
1839 }
1840
1841 if (foldersToSend-- > 0)
1842 currentPacket.FolderData[foldersSent % MAX_FOLDERS_PER_PACKET] = CreateFolderDataBlock(folders[foldersSent++]);
1843 else if (itemsToSend-- > 0)
1844 currentPacket.ItemData[itemsSent % MAX_ITEMS_PER_PACKET] = CreateItemDataBlock(items[itemsSent++]);
1845 else
1846 {
1847// m_log.DebugFormat(
1848// "[LLCLIENTVIEW]: Sending inventory folder details packet to {0} for folder {1}", Name, folderID);
1849 OutPacket(currentPacket, ThrottleOutPacketType.Asset, false);
1850 currentPacket = null;
1851 }
1852 }
1853
1854 if (currentPacket != null)
1855 {
1856// m_log.DebugFormat(
1857// "[LLCLIENTVIEW]: Sending inventory folder details packet to {0} for folder {1}", Name, folderID);
1858 OutPacket(currentPacket, ThrottleOutPacketType.Asset, false);
1859 }
1860 }
1861
1862 private InventoryDescendentsPacket.FolderDataBlock CreateFolderDataBlock(InventoryFolderBase folder)
1863 {
1864 InventoryDescendentsPacket.FolderDataBlock newBlock = new InventoryDescendentsPacket.FolderDataBlock();
1865 newBlock.FolderID = folder.ID;
1866 newBlock.Name = Util.StringToBytes256(folder.Name);
1867 newBlock.ParentID = folder.ParentID;
1868 newBlock.Type = (sbyte)folder.Type;
1869 //if (newBlock.Type == InventoryItemBase.SUITCASE_FOLDER_TYPE)
1870 // newBlock.Type = InventoryItemBase.SUITCASE_FOLDER_FAKE_TYPE;
1871
1872 return newBlock;
1873 }
1874
1875 private InventoryDescendentsPacket.ItemDataBlock CreateItemDataBlock(InventoryItemBase item)
1876 {
1877 InventoryDescendentsPacket.ItemDataBlock newBlock = new InventoryDescendentsPacket.ItemDataBlock();
1878 newBlock.ItemID = item.ID;
1879 newBlock.AssetID = item.AssetID;
1880 newBlock.CreatorID = item.CreatorIdAsUuid;
1881 newBlock.BaseMask = item.BasePermissions;
1882 newBlock.Description = Util.StringToBytes256(item.Description);
1883 newBlock.EveryoneMask = item.EveryOnePermissions;
1884 newBlock.OwnerMask = item.CurrentPermissions;
1885 newBlock.FolderID = item.Folder;
1886 newBlock.InvType = (sbyte)item.InvType;
1887 newBlock.Name = Util.StringToBytes256(item.Name);
1888 newBlock.NextOwnerMask = item.NextPermissions;
1889 newBlock.OwnerID = item.Owner;
1890 newBlock.Type = (sbyte)item.AssetType;
1891
1892 newBlock.GroupID = item.GroupID;
1893 newBlock.GroupOwned = item.GroupOwned;
1894 newBlock.GroupMask = item.GroupPermissions;
1895 newBlock.CreationDate = item.CreationDate;
1896 newBlock.SalePrice = item.SalePrice;
1897 newBlock.SaleType = item.SaleType;
1898 newBlock.Flags = item.Flags;
1899
1900 newBlock.CRC =
1901 Helpers.InventoryCRC(newBlock.CreationDate, newBlock.SaleType,
1902 newBlock.InvType, newBlock.Type,
1903 newBlock.AssetID, newBlock.GroupID,
1904 newBlock.SalePrice,
1905 newBlock.OwnerID, newBlock.CreatorID,
1906 newBlock.ItemID, newBlock.FolderID,
1907 newBlock.EveryoneMask,
1908 newBlock.Flags, newBlock.OwnerMask,
1909 newBlock.GroupMask, newBlock.NextOwnerMask);
1910
1911 return newBlock;
1912 }
1913
1914 private void AddNullFolderBlockToDecendentsPacket(ref InventoryDescendentsPacket packet)
1915 {
1916 packet.FolderData = new InventoryDescendentsPacket.FolderDataBlock[1];
1917 packet.FolderData[0] = new InventoryDescendentsPacket.FolderDataBlock();
1918 packet.FolderData[0].FolderID = UUID.Zero;
1919 packet.FolderData[0].ParentID = UUID.Zero;
1920 packet.FolderData[0].Type = -1;
1921 packet.FolderData[0].Name = new byte[0];
1922 }
1923
1924 private void AddNullItemBlockToDescendentsPacket(ref InventoryDescendentsPacket packet)
1925 {
1926 packet.ItemData = new InventoryDescendentsPacket.ItemDataBlock[1];
1927 packet.ItemData[0] = new InventoryDescendentsPacket.ItemDataBlock();
1928 packet.ItemData[0].ItemID = UUID.Zero;
1929 packet.ItemData[0].AssetID = UUID.Zero;
1930 packet.ItemData[0].CreatorID = UUID.Zero;
1931 packet.ItemData[0].BaseMask = 0;
1932 packet.ItemData[0].Description = new byte[0];
1933 packet.ItemData[0].EveryoneMask = 0;
1934 packet.ItemData[0].OwnerMask = 0;
1935 packet.ItemData[0].FolderID = UUID.Zero;
1936 packet.ItemData[0].InvType = (sbyte)0;
1937 packet.ItemData[0].Name = new byte[0];
1938 packet.ItemData[0].NextOwnerMask = 0;
1939 packet.ItemData[0].OwnerID = UUID.Zero;
1940 packet.ItemData[0].Type = -1;
1941
1942 packet.ItemData[0].GroupID = UUID.Zero;
1943 packet.ItemData[0].GroupOwned = false;
1944 packet.ItemData[0].GroupMask = 0;
1945 packet.ItemData[0].CreationDate = 0;
1946 packet.ItemData[0].SalePrice = 0;
1947 packet.ItemData[0].SaleType = 0;
1948 packet.ItemData[0].Flags = 0;
1949
1950 // No need to add CRC
1951 }
1952
1953 private InventoryDescendentsPacket CreateInventoryDescendentsPacket(UUID ownerID, UUID folderID, int version, int descendents, int folders, int items)
1954 {
1955 InventoryDescendentsPacket descend = (InventoryDescendentsPacket)PacketPool.Instance.GetPacket(PacketType.InventoryDescendents);
1956 descend.Header.Zerocoded = true;
1957 descend.AgentData.AgentID = AgentId;
1958 descend.AgentData.OwnerID = ownerID;
1959 descend.AgentData.FolderID = folderID;
1960 descend.AgentData.Version = version;
1961 descend.AgentData.Descendents = descendents;
1962
1963 if (folders > 0)
1964 descend.FolderData = new InventoryDescendentsPacket.FolderDataBlock[folders];
1965 else
1966 AddNullFolderBlockToDecendentsPacket(ref descend);
1967
1968 if (items > 0)
1969 descend.ItemData = new InventoryDescendentsPacket.ItemDataBlock[items];
1970 else
1971 AddNullItemBlockToDescendentsPacket(ref descend);
1972
1973 return descend;
1974 }
1975
1976 public void SendInventoryItemDetails(UUID ownerID, InventoryItemBase item)
1977 {
1978 // Fudge this value. It's only needed to make the CRC anyway
1979 const uint FULL_MASK_PERMISSIONS = (uint)0x7fffffff;
1980
1981 FetchInventoryReplyPacket inventoryReply = (FetchInventoryReplyPacket)PacketPool.Instance.GetPacket(PacketType.FetchInventoryReply);
1982 // TODO: don't create new blocks if recycling an old packet
1983 inventoryReply.AgentData.AgentID = AgentId;
1984 inventoryReply.InventoryData = new FetchInventoryReplyPacket.InventoryDataBlock[1];
1985 inventoryReply.InventoryData[0] = new FetchInventoryReplyPacket.InventoryDataBlock();
1986 inventoryReply.InventoryData[0].ItemID = item.ID;
1987 inventoryReply.InventoryData[0].AssetID = item.AssetID;
1988 inventoryReply.InventoryData[0].CreatorID = item.CreatorIdAsUuid;
1989 inventoryReply.InventoryData[0].BaseMask = item.BasePermissions;
1990 inventoryReply.InventoryData[0].CreationDate = item.CreationDate;
1991
1992 inventoryReply.InventoryData[0].Description = Util.StringToBytes256(item.Description);
1993 inventoryReply.InventoryData[0].EveryoneMask = item.EveryOnePermissions;
1994 inventoryReply.InventoryData[0].FolderID = item.Folder;
1995 inventoryReply.InventoryData[0].InvType = (sbyte)item.InvType;
1996 inventoryReply.InventoryData[0].Name = Util.StringToBytes256(item.Name);
1997 inventoryReply.InventoryData[0].NextOwnerMask = item.NextPermissions;
1998 inventoryReply.InventoryData[0].OwnerID = item.Owner;
1999 inventoryReply.InventoryData[0].OwnerMask = item.CurrentPermissions;
2000 inventoryReply.InventoryData[0].Type = (sbyte)item.AssetType;
2001
2002 inventoryReply.InventoryData[0].GroupID = item.GroupID;
2003 inventoryReply.InventoryData[0].GroupOwned = item.GroupOwned;
2004 inventoryReply.InventoryData[0].GroupMask = item.GroupPermissions;
2005 inventoryReply.InventoryData[0].Flags = item.Flags;
2006 inventoryReply.InventoryData[0].SalePrice = item.SalePrice;
2007 inventoryReply.InventoryData[0].SaleType = item.SaleType;
2008
2009 inventoryReply.InventoryData[0].CRC =
2010 Helpers.InventoryCRC(
2011 1000, 0, inventoryReply.InventoryData[0].InvType,
2012 inventoryReply.InventoryData[0].Type, inventoryReply.InventoryData[0].AssetID,
2013 inventoryReply.InventoryData[0].GroupID, 100,
2014 inventoryReply.InventoryData[0].OwnerID, inventoryReply.InventoryData[0].CreatorID,
2015 inventoryReply.InventoryData[0].ItemID, inventoryReply.InventoryData[0].FolderID,
2016 FULL_MASK_PERMISSIONS, 1, FULL_MASK_PERMISSIONS, FULL_MASK_PERMISSIONS,
2017 FULL_MASK_PERMISSIONS);
2018 inventoryReply.Header.Zerocoded = true;
2019 OutPacket(inventoryReply, ThrottleOutPacketType.Asset);
2020 }
2021
2022 protected void SendBulkUpdateInventoryFolder(InventoryFolderBase folderBase)
2023 {
2024 // We will use the same transaction id for all the separate packets to be sent out in this update.
2025 UUID transactionId = UUID.Random();
2026
2027 List<BulkUpdateInventoryPacket.FolderDataBlock> folderDataBlocks
2028 = new List<BulkUpdateInventoryPacket.FolderDataBlock>();
2029
2030 SendBulkUpdateInventoryFolderRecursive(folderBase, ref folderDataBlocks, transactionId);
2031
2032 if (folderDataBlocks.Count > 0)
2033 {
2034 // We'll end up with some unsent folder blocks if there were some empty folders at the end of the list
2035 // Send these now
2036 BulkUpdateInventoryPacket bulkUpdate
2037 = (BulkUpdateInventoryPacket)PacketPool.Instance.GetPacket(PacketType.BulkUpdateInventory);
2038 bulkUpdate.Header.Zerocoded = true;
2039
2040 bulkUpdate.AgentData.AgentID = AgentId;
2041 bulkUpdate.AgentData.TransactionID = transactionId;
2042 bulkUpdate.FolderData = folderDataBlocks.ToArray();
2043 List<BulkUpdateInventoryPacket.ItemDataBlock> foo = new List<BulkUpdateInventoryPacket.ItemDataBlock>();
2044 bulkUpdate.ItemData = foo.ToArray();
2045
2046 //m_log.Debug("SendBulkUpdateInventory :" + bulkUpdate);
2047 OutPacket(bulkUpdate, ThrottleOutPacketType.Asset);
2048 }
2049 }
2050
2051 /// <summary>
2052 /// Recursively construct bulk update packets to send folders and items
2053 /// </summary>
2054 /// <param name="folder"></param>
2055 /// <param name="folderDataBlocks"></param>
2056 /// <param name="transactionId"></param>
2057 private void SendBulkUpdateInventoryFolderRecursive(
2058 InventoryFolderBase folder, ref List<BulkUpdateInventoryPacket.FolderDataBlock> folderDataBlocks,
2059 UUID transactionId)
2060 {
2061 folderDataBlocks.Add(GenerateBulkUpdateFolderDataBlock(folder));
2062
2063 const int MAX_ITEMS_PER_PACKET = 5;
2064
2065 IInventoryService invService = m_scene.RequestModuleInterface<IInventoryService>();
2066 // If there are any items then we have to start sending them off in this packet - the next folder will have
2067 // to be in its own bulk update packet. Also, we can only fit 5 items in a packet (at least this was the limit
2068 // being used on the Linden grid at 20081203).
2069 InventoryCollection contents = invService.GetFolderContent(AgentId, folder.ID); // folder.RequestListOfItems();
2070 List<InventoryItemBase> items = contents.Items;
2071 while (items.Count > 0)
2072 {
2073 BulkUpdateInventoryPacket bulkUpdate
2074 = (BulkUpdateInventoryPacket)PacketPool.Instance.GetPacket(PacketType.BulkUpdateInventory);
2075 bulkUpdate.Header.Zerocoded = true;
2076
2077 bulkUpdate.AgentData.AgentID = AgentId;
2078 bulkUpdate.AgentData.TransactionID = transactionId;
2079 bulkUpdate.FolderData = folderDataBlocks.ToArray();
2080
2081 int itemsToSend = (items.Count > MAX_ITEMS_PER_PACKET ? MAX_ITEMS_PER_PACKET : items.Count);
2082 bulkUpdate.ItemData = new BulkUpdateInventoryPacket.ItemDataBlock[itemsToSend];
2083
2084 for (int i = 0; i < itemsToSend; i++)
2085 {
2086 // Remove from the end of the list so that we don't incur a performance penalty
2087 bulkUpdate.ItemData[i] = GenerateBulkUpdateItemDataBlock(items[items.Count - 1]);
2088 items.RemoveAt(items.Count - 1);
2089 }
2090
2091 //m_log.Debug("SendBulkUpdateInventoryRecursive :" + bulkUpdate);
2092 OutPacket(bulkUpdate, ThrottleOutPacketType.Asset);
2093
2094 folderDataBlocks = new List<BulkUpdateInventoryPacket.FolderDataBlock>();
2095
2096 // If we're going to be sending another items packet then it needs to contain just the folder to which those
2097 // items belong.
2098 if (items.Count > 0)
2099 folderDataBlocks.Add(GenerateBulkUpdateFolderDataBlock(folder));
2100 }
2101
2102 List<InventoryFolderBase> subFolders = contents.Folders;
2103 foreach (InventoryFolderBase subFolder in subFolders)
2104 {
2105 SendBulkUpdateInventoryFolderRecursive(subFolder, ref folderDataBlocks, transactionId);
2106 }
2107 }
2108
2109 /// <summary>
2110 /// Generate a bulk update inventory data block for the given folder
2111 /// </summary>
2112 /// <param name="folder"></param>
2113 /// <returns></returns>
2114 private BulkUpdateInventoryPacket.FolderDataBlock GenerateBulkUpdateFolderDataBlock(InventoryFolderBase folder)
2115 {
2116 BulkUpdateInventoryPacket.FolderDataBlock folderBlock = new BulkUpdateInventoryPacket.FolderDataBlock();
2117
2118 folderBlock.FolderID = folder.ID;
2119 folderBlock.ParentID = folder.ParentID;
2120 folderBlock.Type = (sbyte)folder.Type;
2121 // Leaving this here for now, just in case we need to do this for a while
2122 //if (folderBlock.Type == InventoryItemBase.SUITCASE_FOLDER_TYPE)
2123 // folderBlock.Type = InventoryItemBase.SUITCASE_FOLDER_FAKE_TYPE;
2124 folderBlock.Name = Util.StringToBytes256(folder.Name);
2125
2126 return folderBlock;
2127 }
2128
2129 /// <summary>
2130 /// Generate a bulk update inventory data block for the given item
2131 /// </summary>
2132 /// <param name="item"></param>
2133 /// <returns></returns>
2134 private BulkUpdateInventoryPacket.ItemDataBlock GenerateBulkUpdateItemDataBlock(InventoryItemBase item)
2135 {
2136 BulkUpdateInventoryPacket.ItemDataBlock itemBlock = new BulkUpdateInventoryPacket.ItemDataBlock();
2137
2138 itemBlock.ItemID = item.ID;
2139 itemBlock.AssetID = item.AssetID;
2140 itemBlock.CreatorID = item.CreatorIdAsUuid;
2141 itemBlock.BaseMask = item.BasePermissions;
2142 itemBlock.Description = Util.StringToBytes256(item.Description);
2143 itemBlock.EveryoneMask = item.EveryOnePermissions;
2144 itemBlock.FolderID = item.Folder;
2145 itemBlock.InvType = (sbyte)item.InvType;
2146 itemBlock.Name = Util.StringToBytes256(item.Name);
2147 itemBlock.NextOwnerMask = item.NextPermissions;
2148 itemBlock.OwnerID = item.Owner;
2149 itemBlock.OwnerMask = item.CurrentPermissions;
2150 itemBlock.Type = (sbyte)item.AssetType;
2151 itemBlock.GroupID = item.GroupID;
2152 itemBlock.GroupOwned = item.GroupOwned;
2153 itemBlock.GroupMask = item.GroupPermissions;
2154 itemBlock.Flags = item.Flags;
2155 itemBlock.SalePrice = item.SalePrice;
2156 itemBlock.SaleType = item.SaleType;
2157 itemBlock.CreationDate = item.CreationDate;
2158
2159 itemBlock.CRC =
2160 Helpers.InventoryCRC(
2161 1000, 0, itemBlock.InvType,
2162 itemBlock.Type, itemBlock.AssetID,
2163 itemBlock.GroupID, 100,
2164 itemBlock.OwnerID, itemBlock.CreatorID,
2165 itemBlock.ItemID, itemBlock.FolderID,
2166 (uint)PermissionMask.All, 1, (uint)PermissionMask.All, (uint)PermissionMask.All,
2167 (uint)PermissionMask.All);
2168
2169 return itemBlock;
2170 }
2171
2172 public void SendBulkUpdateInventory(InventoryNodeBase node)
2173 {
2174 if (node is InventoryItemBase)
2175 SendBulkUpdateInventoryItem((InventoryItemBase)node);
2176 else if (node is InventoryFolderBase)
2177 SendBulkUpdateInventoryFolder((InventoryFolderBase)node);
2178 else if (node != null)
2179 m_log.ErrorFormat("[CLIENT]: {0} sent unknown inventory node named {1}", Name, node.Name);
2180 else
2181 m_log.ErrorFormat("[CLIENT]: {0} sent null inventory node", Name);
2182 }
2183
2184 protected void SendBulkUpdateInventoryItem(InventoryItemBase item)
2185 {
2186 const uint FULL_MASK_PERMISSIONS = (uint)0x7ffffff;
2187
2188 BulkUpdateInventoryPacket bulkUpdate
2189 = (BulkUpdateInventoryPacket)PacketPool.Instance.GetPacket(PacketType.BulkUpdateInventory);
2190
2191 bulkUpdate.AgentData.AgentID = AgentId;
2192 bulkUpdate.AgentData.TransactionID = UUID.Random();
2193
2194 bulkUpdate.FolderData = new BulkUpdateInventoryPacket.FolderDataBlock[1];
2195 bulkUpdate.FolderData[0] = new BulkUpdateInventoryPacket.FolderDataBlock();
2196 bulkUpdate.FolderData[0].FolderID = UUID.Zero;
2197 bulkUpdate.FolderData[0].ParentID = UUID.Zero;
2198 bulkUpdate.FolderData[0].Type = -1;
2199 bulkUpdate.FolderData[0].Name = new byte[0];
2200
2201 bulkUpdate.ItemData = new BulkUpdateInventoryPacket.ItemDataBlock[1];
2202 bulkUpdate.ItemData[0] = new BulkUpdateInventoryPacket.ItemDataBlock();
2203 bulkUpdate.ItemData[0].ItemID = item.ID;
2204 bulkUpdate.ItemData[0].AssetID = item.AssetID;
2205 bulkUpdate.ItemData[0].CreatorID = item.CreatorIdAsUuid;
2206 bulkUpdate.ItemData[0].BaseMask = item.BasePermissions;
2207 bulkUpdate.ItemData[0].CreationDate = item.CreationDate;
2208 bulkUpdate.ItemData[0].Description = Util.StringToBytes256(item.Description);
2209 bulkUpdate.ItemData[0].EveryoneMask = item.EveryOnePermissions;
2210 bulkUpdate.ItemData[0].FolderID = item.Folder;
2211 bulkUpdate.ItemData[0].InvType = (sbyte)item.InvType;
2212 bulkUpdate.ItemData[0].Name = Util.StringToBytes256(item.Name);
2213 bulkUpdate.ItemData[0].NextOwnerMask = item.NextPermissions;
2214 bulkUpdate.ItemData[0].OwnerID = item.Owner;
2215 bulkUpdate.ItemData[0].OwnerMask = item.CurrentPermissions;
2216 bulkUpdate.ItemData[0].Type = (sbyte)item.AssetType;
2217
2218 bulkUpdate.ItemData[0].GroupID = item.GroupID;
2219 bulkUpdate.ItemData[0].GroupOwned = item.GroupOwned;
2220 bulkUpdate.ItemData[0].GroupMask = item.GroupPermissions;
2221 bulkUpdate.ItemData[0].Flags = item.Flags;
2222 bulkUpdate.ItemData[0].SalePrice = item.SalePrice;
2223 bulkUpdate.ItemData[0].SaleType = item.SaleType;
2224
2225 bulkUpdate.ItemData[0].CRC =
2226 Helpers.InventoryCRC(1000, 0, bulkUpdate.ItemData[0].InvType,
2227 bulkUpdate.ItemData[0].Type, bulkUpdate.ItemData[0].AssetID,
2228 bulkUpdate.ItemData[0].GroupID, 100,
2229 bulkUpdate.ItemData[0].OwnerID, bulkUpdate.ItemData[0].CreatorID,
2230 bulkUpdate.ItemData[0].ItemID, bulkUpdate.ItemData[0].FolderID,
2231 FULL_MASK_PERMISSIONS, 1, FULL_MASK_PERMISSIONS, FULL_MASK_PERMISSIONS,
2232 FULL_MASK_PERMISSIONS);
2233 bulkUpdate.Header.Zerocoded = true;
2234 OutPacket(bulkUpdate, ThrottleOutPacketType.Asset);
2235 }
2236
2237 /// <see>IClientAPI.SendInventoryItemCreateUpdate(InventoryItemBase)</see>
2238 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, uint callbackId)
2239 {
2240 const uint FULL_MASK_PERMISSIONS = (uint)0x7fffffff;
2241
2242 UpdateCreateInventoryItemPacket InventoryReply
2243 = (UpdateCreateInventoryItemPacket)PacketPool.Instance.GetPacket(
2244 PacketType.UpdateCreateInventoryItem);
2245
2246 // TODO: don't create new blocks if recycling an old packet
2247 InventoryReply.AgentData.AgentID = AgentId;
2248 InventoryReply.AgentData.SimApproved = true;
2249 InventoryReply.InventoryData = new UpdateCreateInventoryItemPacket.InventoryDataBlock[1];
2250 InventoryReply.InventoryData[0] = new UpdateCreateInventoryItemPacket.InventoryDataBlock();
2251 InventoryReply.InventoryData[0].ItemID = Item.ID;
2252 InventoryReply.InventoryData[0].AssetID = Item.AssetID;
2253 InventoryReply.InventoryData[0].CreatorID = Item.CreatorIdAsUuid;
2254 InventoryReply.InventoryData[0].BaseMask = Item.BasePermissions;
2255 InventoryReply.InventoryData[0].Description = Util.StringToBytes256(Item.Description);
2256 InventoryReply.InventoryData[0].EveryoneMask = Item.EveryOnePermissions;
2257 InventoryReply.InventoryData[0].FolderID = Item.Folder;
2258 InventoryReply.InventoryData[0].InvType = (sbyte)Item.InvType;
2259 InventoryReply.InventoryData[0].Name = Util.StringToBytes256(Item.Name);
2260 InventoryReply.InventoryData[0].NextOwnerMask = Item.NextPermissions;
2261 InventoryReply.InventoryData[0].OwnerID = Item.Owner;
2262 InventoryReply.InventoryData[0].OwnerMask = Item.CurrentPermissions;
2263 InventoryReply.InventoryData[0].Type = (sbyte)Item.AssetType;
2264 InventoryReply.InventoryData[0].CallbackID = callbackId;
2265
2266 InventoryReply.InventoryData[0].GroupID = Item.GroupID;
2267 InventoryReply.InventoryData[0].GroupOwned = Item.GroupOwned;
2268 InventoryReply.InventoryData[0].GroupMask = Item.GroupPermissions;
2269 InventoryReply.InventoryData[0].Flags = Item.Flags;
2270 InventoryReply.InventoryData[0].SalePrice = Item.SalePrice;
2271 InventoryReply.InventoryData[0].SaleType = Item.SaleType;
2272 InventoryReply.InventoryData[0].CreationDate = Item.CreationDate;
2273
2274 InventoryReply.InventoryData[0].CRC =
2275 Helpers.InventoryCRC(1000, 0, InventoryReply.InventoryData[0].InvType,
2276 InventoryReply.InventoryData[0].Type, InventoryReply.InventoryData[0].AssetID,
2277 InventoryReply.InventoryData[0].GroupID, 100,
2278 InventoryReply.InventoryData[0].OwnerID, InventoryReply.InventoryData[0].CreatorID,
2279 InventoryReply.InventoryData[0].ItemID, InventoryReply.InventoryData[0].FolderID,
2280 FULL_MASK_PERMISSIONS, 1, FULL_MASK_PERMISSIONS, FULL_MASK_PERMISSIONS,
2281 FULL_MASK_PERMISSIONS);
2282 InventoryReply.Header.Zerocoded = true;
2283 OutPacket(InventoryReply, ThrottleOutPacketType.Asset);
2284 }
2285
2286 public void SendRemoveInventoryItem(UUID itemID)
2287 {
2288 RemoveInventoryItemPacket remove = (RemoveInventoryItemPacket)PacketPool.Instance.GetPacket(PacketType.RemoveInventoryItem);
2289 // TODO: don't create new blocks if recycling an old packet
2290 remove.AgentData.AgentID = AgentId;
2291 remove.AgentData.SessionID = m_sessionId;
2292 remove.InventoryData = new RemoveInventoryItemPacket.InventoryDataBlock[1];
2293 remove.InventoryData[0] = new RemoveInventoryItemPacket.InventoryDataBlock();
2294 remove.InventoryData[0].ItemID = itemID;
2295 remove.Header.Zerocoded = true;
2296 OutPacket(remove, ThrottleOutPacketType.Asset);
2297 }
2298
2299 public void SendTakeControls(int controls, bool passToAgent, bool TakeControls)
2300 {
2301 ScriptControlChangePacket scriptcontrol = (ScriptControlChangePacket)PacketPool.Instance.GetPacket(PacketType.ScriptControlChange);
2302 ScriptControlChangePacket.DataBlock[] data = new ScriptControlChangePacket.DataBlock[1];
2303 ScriptControlChangePacket.DataBlock ddata = new ScriptControlChangePacket.DataBlock();
2304 ddata.Controls = (uint)controls;
2305 ddata.PassToAgent = passToAgent;
2306 ddata.TakeControls = TakeControls;
2307 data[0] = ddata;
2308 scriptcontrol.Data = data;
2309 OutPacket(scriptcontrol, ThrottleOutPacketType.Task);
2310 }
2311
2312 public void SendTaskInventory(UUID taskID, short serial, byte[] fileName)
2313 {
2314 ReplyTaskInventoryPacket replytask = (ReplyTaskInventoryPacket)PacketPool.Instance.GetPacket(PacketType.ReplyTaskInventory);
2315 replytask.InventoryData.TaskID = taskID;
2316 replytask.InventoryData.Serial = serial;
2317 replytask.InventoryData.Filename = fileName;
2318 OutPacket(replytask, ThrottleOutPacketType.Asset);
2319 }
2320
2321 public void SendXferPacket(ulong xferID, uint packet, byte[] data)
2322 {
2323 SendXferPacketPacket sendXfer = (SendXferPacketPacket)PacketPool.Instance.GetPacket(PacketType.SendXferPacket);
2324 sendXfer.XferID.ID = xferID;
2325 sendXfer.XferID.Packet = packet;
2326 sendXfer.DataPacket.Data = data;
2327 OutPacket(sendXfer, ThrottleOutPacketType.Asset);
2328 }
2329
2330 public void SendAbortXferPacket(ulong xferID)
2331 {
2332 AbortXferPacket xferItem = (AbortXferPacket)PacketPool.Instance.GetPacket(PacketType.AbortXfer);
2333 xferItem.XferID.ID = xferID;
2334 OutPacket(xferItem, ThrottleOutPacketType.Asset);
2335 }
2336
2337 public void SendEconomyData(float EnergyEfficiency, int ObjectCapacity, int ObjectCount, int PriceEnergyUnit,
2338 int PriceGroupCreate, int PriceObjectClaim, float PriceObjectRent, float PriceObjectScaleFactor,
2339 int PriceParcelClaim, float PriceParcelClaimFactor, int PriceParcelRent, int PricePublicObjectDecay,
2340 int PricePublicObjectDelete, int PriceRentLight, int PriceUpload, int TeleportMinPrice, float TeleportPriceExponent)
2341 {
2342 EconomyDataPacket economyData = (EconomyDataPacket)PacketPool.Instance.GetPacket(PacketType.EconomyData);
2343 economyData.Info.EnergyEfficiency = EnergyEfficiency;
2344 economyData.Info.ObjectCapacity = ObjectCapacity;
2345 economyData.Info.ObjectCount = ObjectCount;
2346 economyData.Info.PriceEnergyUnit = PriceEnergyUnit;
2347 economyData.Info.PriceGroupCreate = PriceGroupCreate;
2348 economyData.Info.PriceObjectClaim = PriceObjectClaim;
2349 economyData.Info.PriceObjectRent = PriceObjectRent;
2350 economyData.Info.PriceObjectScaleFactor = PriceObjectScaleFactor;
2351 economyData.Info.PriceParcelClaim = PriceParcelClaim;
2352 economyData.Info.PriceParcelClaimFactor = PriceParcelClaimFactor;
2353 economyData.Info.PriceParcelRent = PriceParcelRent;
2354 economyData.Info.PricePublicObjectDecay = PricePublicObjectDecay;
2355 economyData.Info.PricePublicObjectDelete = PricePublicObjectDelete;
2356 economyData.Info.PriceRentLight = PriceRentLight;
2357 economyData.Info.PriceUpload = PriceUpload;
2358 economyData.Info.TeleportMinPrice = TeleportMinPrice;
2359 economyData.Info.TeleportPriceExponent = TeleportPriceExponent;
2360 economyData.Header.Reliable = true;
2361 OutPacket(economyData, ThrottleOutPacketType.Task);
2362 }
2363
2364 public void SendAvatarPickerReply(AvatarPickerReplyAgentDataArgs AgentData, List<AvatarPickerReplyDataArgs> Data)
2365 {
2366 //construct the AvatarPickerReply packet.
2367 AvatarPickerReplyPacket replyPacket = new AvatarPickerReplyPacket();
2368 replyPacket.AgentData.AgentID = AgentData.AgentID;
2369 replyPacket.AgentData.QueryID = AgentData.QueryID;
2370 //int i = 0;
2371 List<AvatarPickerReplyPacket.DataBlock> data_block = new List<AvatarPickerReplyPacket.DataBlock>();
2372 foreach (AvatarPickerReplyDataArgs arg in Data)
2373 {
2374 AvatarPickerReplyPacket.DataBlock db = new AvatarPickerReplyPacket.DataBlock();
2375 db.AvatarID = arg.AvatarID;
2376 db.FirstName = arg.FirstName;
2377 db.LastName = arg.LastName;
2378 data_block.Add(db);
2379 }
2380 replyPacket.Data = data_block.ToArray();
2381 OutPacket(replyPacket, ThrottleOutPacketType.Task);
2382 }
2383
2384 public void SendAgentDataUpdate(UUID agentid, UUID activegroupid, string firstname, string lastname, ulong grouppowers, string groupname, string grouptitle)
2385 {
2386 if (agentid == AgentId)
2387 {
2388 ActiveGroupId = activegroupid;
2389 ActiveGroupName = groupname;
2390 ActiveGroupPowers = grouppowers;
2391 }
2392
2393 AgentDataUpdatePacket sendAgentDataUpdate = (AgentDataUpdatePacket)PacketPool.Instance.GetPacket(PacketType.AgentDataUpdate);
2394 sendAgentDataUpdate.AgentData.ActiveGroupID = activegroupid;
2395 sendAgentDataUpdate.AgentData.AgentID = agentid;
2396 sendAgentDataUpdate.AgentData.FirstName = Util.StringToBytes256(firstname);
2397 sendAgentDataUpdate.AgentData.GroupName = Util.StringToBytes256(groupname);
2398 sendAgentDataUpdate.AgentData.GroupPowers = grouppowers;
2399 sendAgentDataUpdate.AgentData.GroupTitle = Util.StringToBytes256(grouptitle);
2400 sendAgentDataUpdate.AgentData.LastName = Util.StringToBytes256(lastname);
2401 OutPacket(sendAgentDataUpdate, ThrottleOutPacketType.Task);
2402 }
2403
2404 /// <summary>
2405 /// Send an alert message to the client. On the Linden client (tested 1.19.1.4), this pops up a brief duration
2406 /// blue information box in the bottom right hand corner.
2407 /// </summary>
2408 /// <param name="message"></param>
2409 public void SendAlertMessage(string message)
2410 {
2411 AlertMessagePacket alertPack = (AlertMessagePacket)PacketPool.Instance.GetPacket(PacketType.AlertMessage);
2412 alertPack.AlertData = new AlertMessagePacket.AlertDataBlock();
2413 alertPack.AlertData.Message = Util.StringToBytes256(message);
2414 alertPack.AlertInfo = new AlertMessagePacket.AlertInfoBlock[0];
2415 OutPacket(alertPack, ThrottleOutPacketType.Task);
2416 }
2417
2418 /// <summary>
2419 /// Send an agent alert message to the client.
2420 /// </summary>
2421 /// <param name="message"></param>
2422 /// <param name="modal">On the linden client, if this true then it displays a one button text box placed in the
2423 /// middle of the window. If false, the message is displayed in a brief duration blue information box (as for
2424 /// the AlertMessage packet).</param>
2425 public void SendAgentAlertMessage(string message, bool modal)
2426 {
2427 OutPacket(BuildAgentAlertPacket(message, modal), ThrottleOutPacketType.Task);
2428 }
2429
2430 /// <summary>
2431 /// Construct an agent alert packet
2432 /// </summary>
2433 /// <param name="message"></param>
2434 /// <param name="modal"></param>
2435 /// <returns></returns>
2436 public AgentAlertMessagePacket BuildAgentAlertPacket(string message, bool modal)
2437 {
2438 // Prepend a slash to make the message come up in the top right
2439 // again.
2440 // Allow special formats to be sent from aware modules.
2441 if (!modal && !message.StartsWith("ALERT: ") && !message.StartsWith("NOTIFY: ") && message != "Home position set." && message != "You died and have been teleported to your home location")
2442 message = "/" + message;
2443 AgentAlertMessagePacket alertPack = (AgentAlertMessagePacket)PacketPool.Instance.GetPacket(PacketType.AgentAlertMessage);
2444 alertPack.AgentData.AgentID = AgentId;
2445 alertPack.AlertData.Message = Util.StringToBytes256(message);
2446 alertPack.AlertData.Modal = modal;
2447
2448 return alertPack;
2449 }
2450
2451 public void SendLoadURL(string objectname, UUID objectID, UUID ownerID, bool groupOwned, string message,
2452 string url)
2453 {
2454 LoadURLPacket loadURL = (LoadURLPacket)PacketPool.Instance.GetPacket(PacketType.LoadURL);
2455 loadURL.Data.ObjectName = Util.StringToBytes256(objectname);
2456 loadURL.Data.ObjectID = objectID;
2457 loadURL.Data.OwnerID = ownerID;
2458 loadURL.Data.OwnerIsGroup = groupOwned;
2459 loadURL.Data.Message = Util.StringToBytes256(message);
2460 loadURL.Data.URL = Util.StringToBytes256(url);
2461 OutPacket(loadURL, ThrottleOutPacketType.Task);
2462 }
2463
2464 public void SendDialog(
2465 string objectname, UUID objectID, UUID ownerID, string ownerFirstName, string ownerLastName, string msg,
2466 UUID textureID, int ch, string[] buttonlabels)
2467 {
2468 ScriptDialogPacket dialog = (ScriptDialogPacket)PacketPool.Instance.GetPacket(PacketType.ScriptDialog);
2469 dialog.Data.ObjectID = objectID;
2470 dialog.Data.ObjectName = Util.StringToBytes256(objectname);
2471 // this is the username of the *owner*
2472 dialog.Data.FirstName = Util.StringToBytes256(ownerFirstName);
2473 dialog.Data.LastName = Util.StringToBytes256(ownerLastName);
2474 dialog.Data.Message = Util.StringToBytes1024(msg);
2475 dialog.Data.ImageID = textureID;
2476 dialog.Data.ChatChannel = ch;
2477 ScriptDialogPacket.ButtonsBlock[] buttons = new ScriptDialogPacket.ButtonsBlock[buttonlabels.Length];
2478 for (int i = 0; i < buttonlabels.Length; i++)
2479 {
2480 buttons[i] = new ScriptDialogPacket.ButtonsBlock();
2481 buttons[i].ButtonLabel = Util.StringToBytes256(buttonlabels[i]);
2482 }
2483 dialog.Buttons = buttons;
2484
2485 dialog.OwnerData = new ScriptDialogPacket.OwnerDataBlock[1];
2486 dialog.OwnerData[0] = new ScriptDialogPacket.OwnerDataBlock();
2487 dialog.OwnerData[0].OwnerID = ownerID;
2488
2489 OutPacket(dialog, ThrottleOutPacketType.Task);
2490 }
2491
2492 public void SendPreLoadSound(UUID objectID, UUID ownerID, UUID soundID)
2493 {
2494 PreloadSoundPacket preSound = (PreloadSoundPacket)PacketPool.Instance.GetPacket(PacketType.PreloadSound);
2495 // TODO: don't create new blocks if recycling an old packet
2496 preSound.DataBlock = new PreloadSoundPacket.DataBlockBlock[1];
2497 preSound.DataBlock[0] = new PreloadSoundPacket.DataBlockBlock();
2498 preSound.DataBlock[0].ObjectID = objectID;
2499 preSound.DataBlock[0].OwnerID = ownerID;
2500 preSound.DataBlock[0].SoundID = soundID;
2501 preSound.Header.Zerocoded = true;
2502 OutPacket(preSound, ThrottleOutPacketType.Task);
2503 }
2504
2505 public void SendPlayAttachedSound(UUID soundID, UUID objectID, UUID ownerID, float gain, byte flags)
2506 {
2507 AttachedSoundPacket sound = (AttachedSoundPacket)PacketPool.Instance.GetPacket(PacketType.AttachedSound);
2508 sound.DataBlock.SoundID = soundID;
2509 sound.DataBlock.ObjectID = objectID;
2510 sound.DataBlock.OwnerID = ownerID;
2511 sound.DataBlock.Gain = gain;
2512 sound.DataBlock.Flags = flags;
2513
2514 OutPacket(sound, ThrottleOutPacketType.Task);
2515 }
2516
2517 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain)
2518 {
2519 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger);
2520 sound.SoundData.SoundID = soundID;
2521 sound.SoundData.OwnerID = ownerID;
2522 sound.SoundData.ObjectID = objectID;
2523 sound.SoundData.ParentID = parentID;
2524 sound.SoundData.Handle = handle;
2525 sound.SoundData.Position = position;
2526 sound.SoundData.Gain = gain;
2527
2528 OutPacket(sound, ThrottleOutPacketType.Task);
2529 }
2530
2531 public void SendAttachedSoundGainChange(UUID objectID, float gain)
2532 {
2533 AttachedSoundGainChangePacket sound = (AttachedSoundGainChangePacket)PacketPool.Instance.GetPacket(PacketType.AttachedSoundGainChange);
2534 sound.DataBlock.ObjectID = objectID;
2535 sound.DataBlock.Gain = gain;
2536
2537 OutPacket(sound, ThrottleOutPacketType.Task);
2538 }
2539
2540 public void SendSunPos(Vector3 Position, Vector3 Velocity, ulong CurrentTime, uint SecondsPerSunCycle, uint SecondsPerYear, float OrbitalPosition)
2541 {
2542 // Viewers based on the Linden viwer code, do wacky things for oribital positions from Midnight to Sunrise
2543 // So adjust for that
2544 // Contributed by: Godfrey
2545
2546 if (OrbitalPosition > m_sunPainDaHalfOrbitalCutoff) // things get weird from midnight to sunrise
2547 {
2548 OrbitalPosition = (OrbitalPosition - m_sunPainDaHalfOrbitalCutoff) * 0.6666666667f + m_sunPainDaHalfOrbitalCutoff;
2549 }
2550
2551 SimulatorViewerTimeMessagePacket viewertime = (SimulatorViewerTimeMessagePacket)PacketPool.Instance.GetPacket(PacketType.SimulatorViewerTimeMessage);
2552 viewertime.TimeInfo.SunDirection = Position;
2553 viewertime.TimeInfo.SunAngVelocity = Velocity;
2554
2555 // Sun module used to add 6 hours to adjust for linden sun hour, adding here
2556 // to prevent existing code from breaking if it assumed that 6 hours were included.
2557 // 21600 == 6 hours * 60 minutes * 60 Seconds
2558 viewertime.TimeInfo.UsecSinceStart = CurrentTime + 21600;
2559
2560 viewertime.TimeInfo.SecPerDay = SecondsPerSunCycle;
2561 viewertime.TimeInfo.SecPerYear = SecondsPerYear;
2562 viewertime.TimeInfo.SunPhase = OrbitalPosition;
2563 viewertime.Header.Reliable = false;
2564 viewertime.Header.Zerocoded = true;
2565 OutPacket(viewertime, ThrottleOutPacketType.Task);
2566 }
2567
2568 // Currently Deprecated
2569 public void SendViewerTime(int phase)
2570 {
2571 /*
2572 Console.WriteLine("SunPhase: {0}", phase);
2573 SimulatorViewerTimeMessagePacket viewertime = (SimulatorViewerTimeMessagePacket)PacketPool.Instance.GetPacket(PacketType.SimulatorViewerTimeMessage);
2574 //viewertime.TimeInfo.SecPerDay = 86400;
2575 //viewertime.TimeInfo.SecPerYear = 31536000;
2576 viewertime.TimeInfo.SecPerDay = 1000;
2577 viewertime.TimeInfo.SecPerYear = 365000;
2578 viewertime.TimeInfo.SunPhase = 1;
2579 int sunPhase = (phase + 2) / 2;
2580 if ((sunPhase < 6) || (sunPhase > 36))
2581 {
2582 viewertime.TimeInfo.SunDirection = new Vector3(0f, 0.8f, -0.8f);
2583 Console.WriteLine("sending night");
2584 }
2585 else
2586 {
2587 if (sunPhase < 12)
2588 {
2589 sunPhase = 12;
2590 }
2591 sunPhase = sunPhase - 12;
2592
2593 float yValue = 0.1f * (sunPhase);
2594 Console.WriteLine("Computed SunPhase: {0}, yValue: {1}", sunPhase, yValue);
2595 if (yValue > 1.2f)
2596 {
2597 yValue = yValue - 1.2f;
2598 }
2599
2600 yValue = Util.Clip(yValue, 0, 1);
2601
2602 if (sunPhase < 14)
2603 {
2604 yValue = 1 - yValue;
2605 }
2606 if (sunPhase < 12)
2607 {
2608 yValue *= -1;
2609 }
2610 viewertime.TimeInfo.SunDirection = new Vector3(0f, yValue, 0.3f);
2611 Console.WriteLine("sending sun update " + yValue);
2612 }
2613 viewertime.TimeInfo.SunAngVelocity = new Vector3(0, 0.0f, 10.0f);
2614 viewertime.TimeInfo.UsecSinceStart = (ulong)Util.UnixTimeSinceEpoch();
2615 viewertime.Header.Reliable = false;
2616 OutPacket(viewertime, ThrottleOutPacketType.Task);
2617 */
2618 }
2619
2620 public void SendViewerEffect(ViewerEffectPacket.EffectBlock[] effectBlocks)
2621 {
2622 ViewerEffectPacket packet = (ViewerEffectPacket)PacketPool.Instance.GetPacket(PacketType.ViewerEffect);
2623 packet.Header.Reliable = false;
2624 packet.Header.Zerocoded = true;
2625
2626 packet.AgentData.AgentID = AgentId;
2627 packet.AgentData.SessionID = SessionId;
2628
2629 packet.Effect = effectBlocks;
2630
2631 // OutPacket(packet, ThrottleOutPacketType.State);
2632 OutPacket(packet, ThrottleOutPacketType.Task);
2633 }
2634
2635 public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] charterMember,
2636 string flAbout, uint flags, UUID flImageID, UUID imageID, string profileURL,
2637 UUID partnerID)
2638 {
2639 AvatarPropertiesReplyPacket avatarReply = (AvatarPropertiesReplyPacket)PacketPool.Instance.GetPacket(PacketType.AvatarPropertiesReply);
2640 avatarReply.AgentData.AgentID = AgentId;
2641 avatarReply.AgentData.AvatarID = avatarID;
2642 if (aboutText != null)
2643 avatarReply.PropertiesData.AboutText = Util.StringToBytes1024(aboutText);
2644 else
2645 avatarReply.PropertiesData.AboutText = Utils.EmptyBytes;
2646 avatarReply.PropertiesData.BornOn = Util.StringToBytes256(bornOn);
2647 avatarReply.PropertiesData.CharterMember = charterMember;
2648 if (flAbout != null)
2649 avatarReply.PropertiesData.FLAboutText = Util.StringToBytes256(flAbout);
2650 else
2651 avatarReply.PropertiesData.FLAboutText = Utils.EmptyBytes;
2652 avatarReply.PropertiesData.Flags = flags;
2653 avatarReply.PropertiesData.FLImageID = flImageID;
2654 avatarReply.PropertiesData.ImageID = imageID;
2655 avatarReply.PropertiesData.ProfileURL = Util.StringToBytes256(profileURL);
2656 avatarReply.PropertiesData.PartnerID = partnerID;
2657 OutPacket(avatarReply, ThrottleOutPacketType.Task);
2658 }
2659
2660 /// <summary>
2661 /// Send the client an Estate message blue box pop-down with a single OK button
2662 /// </summary>
2663 /// <param name="FromAvatarID"></param>
2664 /// <param name="fromSessionID"></param>
2665 /// <param name="FromAvatarName"></param>
2666 /// <param name="Message"></param>
2667 public void SendBlueBoxMessage(UUID FromAvatarID, String FromAvatarName, String Message)
2668 {
2669 if (!SceneAgent.IsChildAgent)
2670 SendInstantMessage(new GridInstantMessage(null, FromAvatarID, FromAvatarName, AgentId, 1, Message, false, new Vector3()));
2671
2672 //SendInstantMessage(FromAvatarID, fromSessionID, Message, AgentId, SessionId, FromAvatarName, (byte)21,(uint) Util.UnixTimeSinceEpoch());
2673 }
2674
2675 public void SendLogoutPacket()
2676 {
2677 // I know this is a bit of a hack, however there are times when you don't
2678 // want to send this, but still need to do the rest of the shutdown process
2679 // this method gets called from the packet server.. which makes it practically
2680 // impossible to do any other way.
2681
2682 if (m_SendLogoutPacketWhenClosing)
2683 {
2684 LogoutReplyPacket logReply = (LogoutReplyPacket)PacketPool.Instance.GetPacket(PacketType.LogoutReply);
2685 // TODO: don't create new blocks if recycling an old packet
2686 logReply.AgentData.AgentID = AgentId;
2687 logReply.AgentData.SessionID = SessionId;
2688 logReply.InventoryData = new LogoutReplyPacket.InventoryDataBlock[1];
2689 logReply.InventoryData[0] = new LogoutReplyPacket.InventoryDataBlock();
2690 logReply.InventoryData[0].ItemID = UUID.Zero;
2691
2692 OutPacket(logReply, ThrottleOutPacketType.Task);
2693 }
2694 }
2695
2696 public void SendHealth(float health)
2697 {
2698 HealthMessagePacket healthpacket = (HealthMessagePacket)PacketPool.Instance.GetPacket(PacketType.HealthMessage);
2699 healthpacket.HealthData.Health = health;
2700 OutPacket(healthpacket, ThrottleOutPacketType.Task);
2701 }
2702
2703 public void SendAgentOnline(UUID[] agentIDs)
2704 {
2705 OnlineNotificationPacket onp = new OnlineNotificationPacket();
2706 OnlineNotificationPacket.AgentBlockBlock[] onpb = new OnlineNotificationPacket.AgentBlockBlock[agentIDs.Length];
2707 for (int i = 0; i < agentIDs.Length; i++)
2708 {
2709 OnlineNotificationPacket.AgentBlockBlock onpbl = new OnlineNotificationPacket.AgentBlockBlock();
2710 onpbl.AgentID = agentIDs[i];
2711 onpb[i] = onpbl;
2712 }
2713 onp.AgentBlock = onpb;
2714 onp.Header.Reliable = true;
2715 OutPacket(onp, ThrottleOutPacketType.Task);
2716 }
2717
2718 public void SendAgentOffline(UUID[] agentIDs)
2719 {
2720 OfflineNotificationPacket offp = new OfflineNotificationPacket();
2721 OfflineNotificationPacket.AgentBlockBlock[] offpb = new OfflineNotificationPacket.AgentBlockBlock[agentIDs.Length];
2722 for (int i = 0; i < agentIDs.Length; i++)
2723 {
2724 OfflineNotificationPacket.AgentBlockBlock onpbl = new OfflineNotificationPacket.AgentBlockBlock();
2725 onpbl.AgentID = agentIDs[i];
2726 offpb[i] = onpbl;
2727 }
2728 offp.AgentBlock = offpb;
2729 offp.Header.Reliable = true;
2730 OutPacket(offp, ThrottleOutPacketType.Task);
2731 }
2732
2733 public void SendSitResponse(UUID TargetID, Vector3 OffsetPos, Quaternion SitOrientation, bool autopilot,
2734 Vector3 CameraAtOffset, Vector3 CameraEyeOffset, bool ForceMouseLook)
2735 {
2736 AvatarSitResponsePacket avatarSitResponse = new AvatarSitResponsePacket();
2737 avatarSitResponse.SitObject.ID = TargetID;
2738 avatarSitResponse.SitTransform.CameraAtOffset = CameraAtOffset;
2739 avatarSitResponse.SitTransform.CameraEyeOffset = CameraEyeOffset;
2740 avatarSitResponse.SitTransform.ForceMouselook = ForceMouseLook;
2741 avatarSitResponse.SitTransform.AutoPilot = autopilot;
2742 avatarSitResponse.SitTransform.SitPosition = OffsetPos;
2743 avatarSitResponse.SitTransform.SitRotation = SitOrientation;
2744
2745 OutPacket(avatarSitResponse, ThrottleOutPacketType.Task);
2746 }
2747
2748 public void SendAdminResponse(UUID Token, uint AdminLevel)
2749 {
2750 GrantGodlikePowersPacket respondPacket = new GrantGodlikePowersPacket();
2751 GrantGodlikePowersPacket.GrantDataBlock gdb = new GrantGodlikePowersPacket.GrantDataBlock();
2752 GrantGodlikePowersPacket.AgentDataBlock adb = new GrantGodlikePowersPacket.AgentDataBlock();
2753
2754 adb.AgentID = AgentId;
2755 adb.SessionID = SessionId; // More security
2756 gdb.GodLevel = (byte)AdminLevel;
2757 gdb.Token = Token;
2758 //respondPacket.AgentData = (GrantGodlikePowersPacket.AgentDataBlock)ablock;
2759 respondPacket.GrantData = gdb;
2760 respondPacket.AgentData = adb;
2761 OutPacket(respondPacket, ThrottleOutPacketType.Task);
2762 }
2763
2764 public void SendGroupMembership(GroupMembershipData[] GroupMembership)
2765 {
2766 m_groupPowers.Clear();
2767
2768 AgentGroupDataUpdatePacket Groupupdate = new AgentGroupDataUpdatePacket();
2769 AgentGroupDataUpdatePacket.GroupDataBlock[] Groups = new AgentGroupDataUpdatePacket.GroupDataBlock[GroupMembership.Length];
2770 for (int i = 0; i < GroupMembership.Length; i++)
2771 {
2772 m_groupPowers[GroupMembership[i].GroupID] = GroupMembership[i].GroupPowers;
2773
2774 AgentGroupDataUpdatePacket.GroupDataBlock Group = new AgentGroupDataUpdatePacket.GroupDataBlock();
2775 Group.AcceptNotices = GroupMembership[i].AcceptNotices;
2776 Group.Contribution = GroupMembership[i].Contribution;
2777 Group.GroupID = GroupMembership[i].GroupID;
2778 Group.GroupInsigniaID = GroupMembership[i].GroupPicture;
2779 Group.GroupName = Util.StringToBytes256(GroupMembership[i].GroupName);
2780 Group.GroupPowers = GroupMembership[i].GroupPowers;
2781 Groups[i] = Group;
2782
2783
2784 }
2785 Groupupdate.GroupData = Groups;
2786 Groupupdate.AgentData = new AgentGroupDataUpdatePacket.AgentDataBlock();
2787 Groupupdate.AgentData.AgentID = AgentId;
2788 OutPacket(Groupupdate, ThrottleOutPacketType.Task);
2789
2790 try
2791 {
2792 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>();
2793 if (eq != null)
2794 {
2795 eq.GroupMembership(Groupupdate, this.AgentId);
2796 }
2797 }
2798 catch (Exception ex)
2799 {
2800 m_log.Error("Unable to send group membership data via eventqueue - exception: " + ex.ToString());
2801 m_log.Warn("sending group membership data via UDP");
2802 OutPacket(Groupupdate, ThrottleOutPacketType.Task);
2803 }
2804 }
2805
2806 public void SendPartPhysicsProprieties(ISceneEntity entity)
2807 {
2808 SceneObjectPart part = (SceneObjectPart)entity;
2809 if (part != null && AgentId != UUID.Zero)
2810 {
2811 try
2812 {
2813 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>();
2814 if (eq != null)
2815 {
2816 uint localid = part.LocalId;
2817 byte physshapetype = part.PhysicsShapeType;
2818 float density = part.Density;
2819 float friction = part.Friction;
2820 float bounce = part.Restitution;
2821 float gravmod = part.GravityModifier;
2822 eq.partPhysicsProperties(localid, physshapetype, density, friction, bounce, gravmod,AgentId);
2823 }
2824 }
2825 catch (Exception ex)
2826 {
2827 m_log.Error("Unable to send part Physics Proprieties - exception: " + ex.ToString());
2828 }
2829 part.UpdatePhysRequired = false;
2830 }
2831 }
2832
2833
2834
2835 public void SendGroupNameReply(UUID groupLLUID, string GroupName)
2836 {
2837 UUIDGroupNameReplyPacket pack = new UUIDGroupNameReplyPacket();
2838 UUIDGroupNameReplyPacket.UUIDNameBlockBlock[] uidnameblock = new UUIDGroupNameReplyPacket.UUIDNameBlockBlock[1];
2839 UUIDGroupNameReplyPacket.UUIDNameBlockBlock uidnamebloc = new UUIDGroupNameReplyPacket.UUIDNameBlockBlock();
2840 uidnamebloc.ID = groupLLUID;
2841 uidnamebloc.GroupName = Util.StringToBytes256(GroupName);
2842 uidnameblock[0] = uidnamebloc;
2843 pack.UUIDNameBlock = uidnameblock;
2844 OutPacket(pack, ThrottleOutPacketType.Task);
2845 }
2846
2847 public void SendLandStatReply(uint reportType, uint requestFlags, uint resultCount, LandStatReportItem[] lsrpia)
2848 {
2849 LandStatReplyPacket lsrp = new LandStatReplyPacket();
2850 // LandStatReplyPacket.RequestDataBlock lsreqdpb = new LandStatReplyPacket.RequestDataBlock();
2851 LandStatReplyPacket.ReportDataBlock[] lsrepdba = new LandStatReplyPacket.ReportDataBlock[lsrpia.Length];
2852 //LandStatReplyPacket.ReportDataBlock lsrepdb = new LandStatReplyPacket.ReportDataBlock();
2853 // lsrepdb.
2854 lsrp.RequestData.ReportType = reportType;
2855 lsrp.RequestData.RequestFlags = requestFlags;
2856 lsrp.RequestData.TotalObjectCount = resultCount;
2857 for (int i = 0; i < lsrpia.Length; i++)
2858 {
2859 LandStatReplyPacket.ReportDataBlock lsrepdb = new LandStatReplyPacket.ReportDataBlock();
2860 lsrepdb.LocationX = lsrpia[i].LocationX;
2861 lsrepdb.LocationY = lsrpia[i].LocationY;
2862 lsrepdb.LocationZ = lsrpia[i].LocationZ;
2863 lsrepdb.Score = lsrpia[i].Score;
2864 lsrepdb.TaskID = lsrpia[i].TaskID;
2865 lsrepdb.TaskLocalID = lsrpia[i].TaskLocalID;
2866 lsrepdb.TaskName = Util.StringToBytes256(lsrpia[i].TaskName);
2867 lsrepdb.OwnerName = Util.StringToBytes256(lsrpia[i].OwnerName);
2868 lsrepdba[i] = lsrepdb;
2869 }
2870 lsrp.ReportData = lsrepdba;
2871 OutPacket(lsrp, ThrottleOutPacketType.Task);
2872 }
2873
2874 public void SendScriptRunningReply(UUID objectID, UUID itemID, bool running)
2875 {
2876 ScriptRunningReplyPacket scriptRunningReply = new ScriptRunningReplyPacket();
2877 scriptRunningReply.Script.ObjectID = objectID;
2878 scriptRunningReply.Script.ItemID = itemID;
2879 scriptRunningReply.Script.Running = running;
2880
2881 OutPacket(scriptRunningReply, ThrottleOutPacketType.Task);
2882 }
2883
2884 public void SendAsset(AssetRequestToClient req)
2885 {
2886 if (req.AssetInf.Data == null)
2887 {
2888 m_log.ErrorFormat("{0} Cannot send asset {1} ({2}), asset data is null",
2889 LogHeader, req.AssetInf.ID, req.AssetInf.Metadata.ContentType);
2890 return;
2891 }
2892
2893 //m_log.Debug("sending asset " + req.RequestAssetID);
2894 TransferInfoPacket Transfer = new TransferInfoPacket();
2895 Transfer.TransferInfo.ChannelType = 2;
2896 Transfer.TransferInfo.Status = 0;
2897 Transfer.TransferInfo.TargetType = 0;
2898 if (req.AssetRequestSource == 2)
2899 {
2900 Transfer.TransferInfo.Params = new byte[20];
2901 Array.Copy(req.RequestAssetID.GetBytes(), 0, Transfer.TransferInfo.Params, 0, 16);
2902 int assType = req.AssetInf.Type;
2903 Array.Copy(Utils.IntToBytes(assType), 0, Transfer.TransferInfo.Params, 16, 4);
2904 }
2905 else if (req.AssetRequestSource == 3)
2906 {
2907 Transfer.TransferInfo.Params = req.Params;
2908 // Transfer.TransferInfo.Params = new byte[100];
2909 //Array.Copy(req.RequestUser.AgentId.GetBytes(), 0, Transfer.TransferInfo.Params, 0, 16);
2910 //Array.Copy(req.RequestUser.SessionId.GetBytes(), 0, Transfer.TransferInfo.Params, 16, 16);
2911 }
2912 Transfer.TransferInfo.Size = req.AssetInf.Data.Length;
2913 Transfer.TransferInfo.TransferID = req.TransferRequestID;
2914 Transfer.Header.Zerocoded = true;
2915 OutPacket(Transfer, ThrottleOutPacketType.Asset);
2916
2917 if (req.NumPackets == 1)
2918 {
2919 TransferPacketPacket TransferPacket = new TransferPacketPacket();
2920 TransferPacket.TransferData.Packet = 0;
2921 TransferPacket.TransferData.ChannelType = 2;
2922 TransferPacket.TransferData.TransferID = req.TransferRequestID;
2923 TransferPacket.TransferData.Data = req.AssetInf.Data;
2924 TransferPacket.TransferData.Status = 1;
2925 TransferPacket.Header.Zerocoded = true;
2926 OutPacket(TransferPacket, ThrottleOutPacketType.Asset);
2927 }
2928 else
2929 {
2930 int processedLength = 0;
2931 int maxChunkSize = Settings.MAX_PACKET_SIZE - 100;
2932 int packetNumber = 0;
2933
2934 while (processedLength < req.AssetInf.Data.Length)
2935 {
2936 TransferPacketPacket TransferPacket = new TransferPacketPacket();
2937 TransferPacket.TransferData.Packet = packetNumber;
2938 TransferPacket.TransferData.ChannelType = 2;
2939 TransferPacket.TransferData.TransferID = req.TransferRequestID;
2940
2941 int chunkSize = Math.Min(req.AssetInf.Data.Length - processedLength, maxChunkSize);
2942 byte[] chunk = new byte[chunkSize];
2943 Array.Copy(req.AssetInf.Data, processedLength, chunk, 0, chunk.Length);
2944
2945 TransferPacket.TransferData.Data = chunk;
2946
2947 // 0 indicates more packets to come, 1 indicates last packet
2948 if (req.AssetInf.Data.Length - processedLength > maxChunkSize)
2949 {
2950 TransferPacket.TransferData.Status = 0;
2951 }
2952 else
2953 {
2954 TransferPacket.TransferData.Status = 1;
2955 }
2956 TransferPacket.Header.Zerocoded = true;
2957 OutPacket(TransferPacket, ThrottleOutPacketType.Asset);
2958
2959 processedLength += chunkSize;
2960 packetNumber++;
2961 }
2962 }
2963 }
2964
2965 public void SendAssetNotFound(AssetRequestToClient req)
2966 {
2967 TransferInfoPacket Transfer = new TransferInfoPacket();
2968 Transfer.TransferInfo.ChannelType = 2;
2969 Transfer.TransferInfo.Status = -2;
2970 Transfer.TransferInfo.TargetType = 0;
2971 Transfer.TransferInfo.Params = req.Params;
2972 Transfer.TransferInfo.Size = 0;
2973 Transfer.TransferInfo.TransferID = req.TransferRequestID;
2974 Transfer.Header.Zerocoded = true;
2975 OutPacket(Transfer, ThrottleOutPacketType.Asset);
2976 }
2977
2978 public void SendTexture(AssetBase TextureAsset)
2979 {
2980
2981 }
2982
2983 public void SendRegionHandle(UUID regionID, ulong handle)
2984 {
2985 RegionIDAndHandleReplyPacket reply = (RegionIDAndHandleReplyPacket)PacketPool.Instance.GetPacket(PacketType.RegionIDAndHandleReply);
2986 reply.ReplyBlock.RegionID = regionID;
2987 reply.ReplyBlock.RegionHandle = handle;
2988 OutPacket(reply, ThrottleOutPacketType.Land);
2989 }
2990
2991 public void SendParcelInfo(RegionInfo info, LandData land, UUID parcelID, uint x, uint y)
2992 {
2993 float dwell = 0.0f;
2994 IDwellModule dwellModule = m_scene.RequestModuleInterface<IDwellModule>();
2995 if (dwellModule != null)
2996 dwell = dwellModule.GetDwell(land.GlobalID);
2997 ParcelInfoReplyPacket reply = (ParcelInfoReplyPacket)PacketPool.Instance.GetPacket(PacketType.ParcelInfoReply);
2998 reply.AgentData.AgentID = m_agentId;
2999 reply.Data.ParcelID = parcelID;
3000 reply.Data.OwnerID = land.OwnerID;
3001 reply.Data.Name = Utils.StringToBytes(land.Name);
3002 reply.Data.Desc = Utils.StringToBytes(land.Description);
3003 reply.Data.ActualArea = land.Area;
3004 reply.Data.BillableArea = land.Area; // TODO: what is this?
3005
3006 // Bit 0: Mature, bit 7: on sale, other bits: no idea
3007 reply.Data.Flags = (byte)(
3008 (info.AccessLevel > 13 ? (1 << 0) : 0) +
3009 ((land.Flags & (uint)ParcelFlags.ForSale) != 0 ? (1 << 7) : 0));
3010
3011 Vector3 pos = land.UserLocation;
3012 if (pos.Equals(Vector3.Zero))
3013 {
3014 pos = (land.AABBMax + land.AABBMin) * 0.5f;
3015 }
3016 reply.Data.GlobalX = info.RegionLocX + x;
3017 reply.Data.GlobalY = info.RegionLocY + y;
3018 reply.Data.GlobalZ = pos.Z;
3019 reply.Data.SimName = Utils.StringToBytes(info.RegionName);
3020 reply.Data.SnapshotID = land.SnapshotID;
3021 reply.Data.Dwell = dwell;
3022 reply.Data.SalePrice = land.SalePrice;
3023 reply.Data.AuctionID = (int)land.AuctionID;
3024
3025 OutPacket(reply, ThrottleOutPacketType.Land);
3026 }
3027
3028 public void SendScriptTeleportRequest(string objName, string simName, Vector3 pos, Vector3 lookAt)
3029 {
3030 ScriptTeleportRequestPacket packet = (ScriptTeleportRequestPacket)PacketPool.Instance.GetPacket(PacketType.ScriptTeleportRequest);
3031
3032 packet.Data.ObjectName = Utils.StringToBytes(objName);
3033 packet.Data.SimName = Utils.StringToBytes(simName);
3034 packet.Data.SimPosition = pos;
3035 packet.Data.LookAt = lookAt;
3036
3037 OutPacket(packet, ThrottleOutPacketType.Task);
3038 }
3039
3040 public void SendDirPlacesReply(UUID queryID, DirPlacesReplyData[] data)
3041 {
3042 DirPlacesReplyPacket packet = (DirPlacesReplyPacket)PacketPool.Instance.GetPacket(PacketType.DirPlacesReply);
3043
3044 packet.AgentData = new DirPlacesReplyPacket.AgentDataBlock();
3045
3046 packet.QueryData = new DirPlacesReplyPacket.QueryDataBlock[1];
3047 packet.QueryData[0] = new DirPlacesReplyPacket.QueryDataBlock();
3048
3049 packet.AgentData.AgentID = AgentId;
3050
3051 packet.QueryData[0].QueryID = queryID;
3052
3053 DirPlacesReplyPacket.QueryRepliesBlock[] replies =
3054 new DirPlacesReplyPacket.QueryRepliesBlock[0];
3055 DirPlacesReplyPacket.StatusDataBlock[] status =
3056 new DirPlacesReplyPacket.StatusDataBlock[0];
3057
3058 packet.QueryReplies = replies;
3059 packet.StatusData = status;
3060
3061 foreach (DirPlacesReplyData d in data)
3062 {
3063 int idx = replies.Length;
3064 Array.Resize(ref replies, idx + 1);
3065 Array.Resize(ref status, idx + 1);
3066
3067 replies[idx] = new DirPlacesReplyPacket.QueryRepliesBlock();
3068 status[idx] = new DirPlacesReplyPacket.StatusDataBlock();
3069 replies[idx].ParcelID = d.parcelID;
3070 replies[idx].Name = Utils.StringToBytes(d.name);
3071 replies[idx].ForSale = d.forSale;
3072 replies[idx].Auction = d.auction;
3073 replies[idx].Dwell = d.dwell;
3074 status[idx].Status = d.Status;
3075
3076 packet.QueryReplies = replies;
3077 packet.StatusData = status;
3078
3079 if (packet.Length >= 1000)
3080 {
3081 OutPacket(packet, ThrottleOutPacketType.Task);
3082
3083 packet = (DirPlacesReplyPacket)PacketPool.Instance.GetPacket(PacketType.DirPlacesReply);
3084
3085 packet.AgentData = new DirPlacesReplyPacket.AgentDataBlock();
3086
3087 packet.QueryData = new DirPlacesReplyPacket.QueryDataBlock[1];
3088 packet.QueryData[0] = new DirPlacesReplyPacket.QueryDataBlock();
3089
3090 packet.AgentData.AgentID = AgentId;
3091
3092 packet.QueryData[0].QueryID = queryID;
3093
3094 replies = new DirPlacesReplyPacket.QueryRepliesBlock[0];
3095 status = new DirPlacesReplyPacket.StatusDataBlock[0];
3096 }
3097 }
3098
3099 if (replies.Length > 0 || data.Length == 0)
3100 OutPacket(packet, ThrottleOutPacketType.Task);
3101 }
3102
3103 public void SendDirPeopleReply(UUID queryID, DirPeopleReplyData[] data)
3104 {
3105 DirPeopleReplyPacket packet = (DirPeopleReplyPacket)PacketPool.Instance.GetPacket(PacketType.DirPeopleReply);
3106
3107 packet.AgentData = new DirPeopleReplyPacket.AgentDataBlock();
3108 packet.AgentData.AgentID = AgentId;
3109
3110 packet.QueryData = new DirPeopleReplyPacket.QueryDataBlock();
3111 packet.QueryData.QueryID = queryID;
3112
3113 packet.QueryReplies = new DirPeopleReplyPacket.QueryRepliesBlock[
3114 data.Length];
3115
3116 int i = 0;
3117 foreach (DirPeopleReplyData d in data)
3118 {
3119 packet.QueryReplies[i] = new DirPeopleReplyPacket.QueryRepliesBlock();
3120 packet.QueryReplies[i].AgentID = d.agentID;
3121 packet.QueryReplies[i].FirstName =
3122 Utils.StringToBytes(d.firstName);
3123 packet.QueryReplies[i].LastName =
3124 Utils.StringToBytes(d.lastName);
3125 packet.QueryReplies[i].Group =
3126 Utils.StringToBytes(d.group);
3127 packet.QueryReplies[i].Online = d.online;
3128 packet.QueryReplies[i].Reputation = d.reputation;
3129 i++;
3130 }
3131
3132 OutPacket(packet, ThrottleOutPacketType.Task);
3133 }
3134
3135 public void SendDirEventsReply(UUID queryID, DirEventsReplyData[] data)
3136 {
3137 DirEventsReplyPacket packet = (DirEventsReplyPacket)PacketPool.Instance.GetPacket(PacketType.DirEventsReply);
3138
3139 packet.AgentData = new DirEventsReplyPacket.AgentDataBlock();
3140 packet.AgentData.AgentID = AgentId;
3141
3142 packet.QueryData = new DirEventsReplyPacket.QueryDataBlock();
3143 packet.QueryData.QueryID = queryID;
3144
3145 packet.QueryReplies = new DirEventsReplyPacket.QueryRepliesBlock[
3146 data.Length];
3147
3148 packet.StatusData = new DirEventsReplyPacket.StatusDataBlock[
3149 data.Length];
3150
3151 int i = 0;
3152 foreach (DirEventsReplyData d in data)
3153 {
3154 packet.QueryReplies[i] = new DirEventsReplyPacket.QueryRepliesBlock();
3155 packet.StatusData[i] = new DirEventsReplyPacket.StatusDataBlock();
3156 packet.QueryReplies[i].OwnerID = d.ownerID;
3157 packet.QueryReplies[i].Name =
3158 Utils.StringToBytes(d.name);
3159 packet.QueryReplies[i].EventID = d.eventID;
3160 packet.QueryReplies[i].Date =
3161 Utils.StringToBytes(d.date);
3162 packet.QueryReplies[i].UnixTime = d.unixTime;
3163 packet.QueryReplies[i].EventFlags = d.eventFlags;
3164 packet.StatusData[i].Status = d.Status;
3165 i++;
3166 }
3167
3168 OutPacket(packet, ThrottleOutPacketType.Task);
3169 }
3170
3171 public void SendDirGroupsReply(UUID queryID, DirGroupsReplyData[] data)
3172 {
3173 DirGroupsReplyPacket packet = (DirGroupsReplyPacket)PacketPool.Instance.GetPacket(PacketType.DirGroupsReply);
3174
3175 packet.AgentData = new DirGroupsReplyPacket.AgentDataBlock();
3176 packet.AgentData.AgentID = AgentId;
3177
3178 packet.QueryData = new DirGroupsReplyPacket.QueryDataBlock();
3179 packet.QueryData.QueryID = queryID;
3180
3181 packet.QueryReplies = new DirGroupsReplyPacket.QueryRepliesBlock[
3182 data.Length];
3183
3184 int i = 0;
3185 foreach (DirGroupsReplyData d in data)
3186 {
3187 packet.QueryReplies[i] = new DirGroupsReplyPacket.QueryRepliesBlock();
3188 packet.QueryReplies[i].GroupID = d.groupID;
3189 packet.QueryReplies[i].GroupName =
3190 Utils.StringToBytes(d.groupName);
3191 packet.QueryReplies[i].Members = d.members;
3192 packet.QueryReplies[i].SearchOrder = d.searchOrder;
3193 i++;
3194 }
3195
3196 OutPacket(packet, ThrottleOutPacketType.Task);
3197 }
3198
3199 public void SendDirClassifiedReply(UUID queryID, DirClassifiedReplyData[] data)
3200 {
3201 DirClassifiedReplyPacket packet = (DirClassifiedReplyPacket)PacketPool.Instance.GetPacket(PacketType.DirClassifiedReply);
3202
3203 packet.AgentData = new DirClassifiedReplyPacket.AgentDataBlock();
3204 packet.AgentData.AgentID = AgentId;
3205
3206 packet.QueryData = new DirClassifiedReplyPacket.QueryDataBlock();
3207 packet.QueryData.QueryID = queryID;
3208
3209 packet.QueryReplies = new DirClassifiedReplyPacket.QueryRepliesBlock[
3210 data.Length];
3211 packet.StatusData = new DirClassifiedReplyPacket.StatusDataBlock[
3212 data.Length];
3213
3214 int i = 0;
3215 foreach (DirClassifiedReplyData d in data)
3216 {
3217 packet.QueryReplies[i] = new DirClassifiedReplyPacket.QueryRepliesBlock();
3218 packet.StatusData[i] = new DirClassifiedReplyPacket.StatusDataBlock();
3219 packet.QueryReplies[i].ClassifiedID = d.classifiedID;
3220 packet.QueryReplies[i].Name =
3221 Utils.StringToBytes(d.name);
3222 packet.QueryReplies[i].ClassifiedFlags = d.classifiedFlags;
3223 packet.QueryReplies[i].CreationDate = d.creationDate;
3224 packet.QueryReplies[i].ExpirationDate = d.expirationDate;
3225 packet.QueryReplies[i].PriceForListing = d.price;
3226 packet.StatusData[i].Status = d.Status;
3227 i++;
3228 }
3229
3230 OutPacket(packet, ThrottleOutPacketType.Task);
3231 }
3232
3233 public void SendDirLandReply(UUID queryID, DirLandReplyData[] data)
3234 {
3235 DirLandReplyPacket packet = (DirLandReplyPacket)PacketPool.Instance.GetPacket(PacketType.DirLandReply);
3236
3237 packet.AgentData = new DirLandReplyPacket.AgentDataBlock();
3238 packet.AgentData.AgentID = AgentId;
3239
3240 packet.QueryData = new DirLandReplyPacket.QueryDataBlock();
3241 packet.QueryData.QueryID = queryID;
3242
3243 packet.QueryReplies = new DirLandReplyPacket.QueryRepliesBlock[
3244 data.Length];
3245
3246 int i = 0;
3247 foreach (DirLandReplyData d in data)
3248 {
3249 packet.QueryReplies[i] = new DirLandReplyPacket.QueryRepliesBlock();
3250 packet.QueryReplies[i].ParcelID = d.parcelID;
3251 packet.QueryReplies[i].Name =
3252 Utils.StringToBytes(d.name);
3253 packet.QueryReplies[i].Auction = d.auction;
3254 packet.QueryReplies[i].ForSale = d.forSale;
3255 packet.QueryReplies[i].SalePrice = d.salePrice;
3256 packet.QueryReplies[i].ActualArea = d.actualArea;
3257 i++;
3258 }
3259
3260 OutPacket(packet, ThrottleOutPacketType.Task);
3261 }
3262
3263 public void SendDirPopularReply(UUID queryID, DirPopularReplyData[] data)
3264 {
3265 DirPopularReplyPacket packet = (DirPopularReplyPacket)PacketPool.Instance.GetPacket(PacketType.DirPopularReply);
3266
3267 packet.AgentData = new DirPopularReplyPacket.AgentDataBlock();
3268 packet.AgentData.AgentID = AgentId;
3269
3270 packet.QueryData = new DirPopularReplyPacket.QueryDataBlock();
3271 packet.QueryData.QueryID = queryID;
3272
3273 packet.QueryReplies = new DirPopularReplyPacket.QueryRepliesBlock[
3274 data.Length];
3275
3276 int i = 0;
3277 foreach (DirPopularReplyData d in data)
3278 {
3279 packet.QueryReplies[i] = new DirPopularReplyPacket.QueryRepliesBlock();
3280 packet.QueryReplies[i].ParcelID = d.parcelID;
3281 packet.QueryReplies[i].Name =
3282 Utils.StringToBytes(d.name);
3283 packet.QueryReplies[i].Dwell = d.dwell;
3284 i++;
3285 }
3286
3287 OutPacket(packet, ThrottleOutPacketType.Task);
3288 }
3289
3290 public void SendEventInfoReply(EventData data)
3291 {
3292 EventInfoReplyPacket packet = (EventInfoReplyPacket)PacketPool.Instance.GetPacket(PacketType.EventInfoReply);
3293
3294 packet.AgentData = new EventInfoReplyPacket.AgentDataBlock();
3295 packet.AgentData.AgentID = AgentId;
3296
3297 packet.EventData = new EventInfoReplyPacket.EventDataBlock();
3298 packet.EventData.EventID = data.eventID;
3299 packet.EventData.Creator = Utils.StringToBytes(data.creator);
3300 packet.EventData.Name = Utils.StringToBytes(data.name);
3301 packet.EventData.Category = Utils.StringToBytes(data.category);
3302 packet.EventData.Desc = Utils.StringToBytes(data.description);
3303 packet.EventData.Date = Utils.StringToBytes(data.date);
3304 packet.EventData.DateUTC = data.dateUTC;
3305 packet.EventData.Duration = data.duration;
3306 packet.EventData.Cover = data.cover;
3307 packet.EventData.Amount = data.amount;
3308 packet.EventData.SimName = Utils.StringToBytes(data.simName);
3309 packet.EventData.GlobalPos = new Vector3d(data.globalPos);
3310 packet.EventData.EventFlags = data.eventFlags;
3311
3312 OutPacket(packet, ThrottleOutPacketType.Task);
3313 }
3314
3315 public void SendMapItemReply(mapItemReply[] replies, uint mapitemtype, uint flags)
3316 {
3317 MapItemReplyPacket mirplk = new MapItemReplyPacket();
3318 mirplk.AgentData.AgentID = AgentId;
3319 mirplk.RequestData.ItemType = mapitemtype;
3320 mirplk.Data = new MapItemReplyPacket.DataBlock[replies.Length];
3321 for (int i = 0; i < replies.Length; i++)
3322 {
3323 MapItemReplyPacket.DataBlock mrdata = new MapItemReplyPacket.DataBlock();
3324 mrdata.X = replies[i].x;
3325 mrdata.Y = replies[i].y;
3326 mrdata.ID = replies[i].id;
3327 mrdata.Extra = replies[i].Extra;
3328 mrdata.Extra2 = replies[i].Extra2;
3329 mrdata.Name = Utils.StringToBytes(replies[i].name);
3330 mirplk.Data[i] = mrdata;
3331 }
3332 //m_log.Debug(mirplk.ToString());
3333 OutPacket(mirplk, ThrottleOutPacketType.Task);
3334
3335 }
3336
3337 public void SendOfferCallingCard(UUID srcID, UUID transactionID)
3338 {
3339 // a bit special, as this uses AgentID to store the source instead
3340 // of the destination. The destination (the receiver) goes into destID
3341 OfferCallingCardPacket p = (OfferCallingCardPacket)PacketPool.Instance.GetPacket(PacketType.OfferCallingCard);
3342 p.AgentData.AgentID = srcID;
3343 p.AgentData.SessionID = UUID.Zero;
3344 p.AgentBlock.DestID = AgentId;
3345 p.AgentBlock.TransactionID = transactionID;
3346 OutPacket(p, ThrottleOutPacketType.Task);
3347 }
3348
3349 public void SendAcceptCallingCard(UUID transactionID)
3350 {
3351 AcceptCallingCardPacket p = (AcceptCallingCardPacket)PacketPool.Instance.GetPacket(PacketType.AcceptCallingCard);
3352 p.AgentData.AgentID = AgentId;
3353 p.AgentData.SessionID = UUID.Zero;
3354 p.FolderData = new AcceptCallingCardPacket.FolderDataBlock[1];
3355 p.FolderData[0] = new AcceptCallingCardPacket.FolderDataBlock();
3356 p.FolderData[0].FolderID = UUID.Zero;
3357 OutPacket(p, ThrottleOutPacketType.Task);
3358 }
3359
3360 public void SendDeclineCallingCard(UUID transactionID)
3361 {
3362 DeclineCallingCardPacket p = (DeclineCallingCardPacket)PacketPool.Instance.GetPacket(PacketType.DeclineCallingCard);
3363 p.AgentData.AgentID = AgentId;
3364 p.AgentData.SessionID = UUID.Zero;
3365 p.TransactionBlock.TransactionID = transactionID;
3366 OutPacket(p, ThrottleOutPacketType.Task);
3367 }
3368
3369 public void SendTerminateFriend(UUID exFriendID)
3370 {
3371 TerminateFriendshipPacket p = (TerminateFriendshipPacket)PacketPool.Instance.GetPacket(PacketType.TerminateFriendship);
3372 p.AgentData.AgentID = AgentId;
3373 p.AgentData.SessionID = SessionId;
3374 p.ExBlock.OtherID = exFriendID;
3375 OutPacket(p, ThrottleOutPacketType.Task);
3376 }
3377
3378 public void SendAvatarGroupsReply(UUID avatarID, GroupMembershipData[] data)
3379 {
3380 OSDMap llsd = new OSDMap(3);
3381 OSDArray AgentData = new OSDArray(1);
3382 OSDMap AgentDataMap = new OSDMap(1);
3383 AgentDataMap.Add("AgentID", OSD.FromUUID(this.AgentId));
3384 AgentDataMap.Add("AvatarID", OSD.FromUUID(avatarID));
3385 AgentData.Add(AgentDataMap);
3386 llsd.Add("AgentData", AgentData);
3387 OSDArray GroupData = new OSDArray(data.Length);
3388 OSDArray NewGroupData = new OSDArray(data.Length);
3389 foreach (GroupMembershipData m in data)
3390 {
3391 OSDMap GroupDataMap = new OSDMap(6);
3392 OSDMap NewGroupDataMap = new OSDMap(1);
3393 GroupDataMap.Add("GroupPowers", OSD.FromULong(m.GroupPowers));
3394 GroupDataMap.Add("AcceptNotices", OSD.FromBoolean(m.AcceptNotices));
3395 GroupDataMap.Add("GroupTitle", OSD.FromString(m.GroupTitle));
3396 GroupDataMap.Add("GroupID", OSD.FromUUID(m.GroupID));
3397 GroupDataMap.Add("GroupName", OSD.FromString(m.GroupName));
3398 GroupDataMap.Add("GroupInsigniaID", OSD.FromUUID(m.GroupPicture));
3399 NewGroupDataMap.Add("ListInProfile", OSD.FromBoolean(m.ListInProfile));
3400 GroupData.Add(GroupDataMap);
3401 NewGroupData.Add(NewGroupDataMap);
3402 }
3403 llsd.Add("GroupData", GroupData);
3404 llsd.Add("NewGroupData", NewGroupData);
3405
3406 IEventQueue eq = this.Scene.RequestModuleInterface<IEventQueue>();
3407 if (eq != null)
3408 {
3409 eq.Enqueue(BuildEvent("AvatarGroupsReply", llsd), this.AgentId);
3410 }
3411 }
3412
3413 public void SendJoinGroupReply(UUID groupID, bool success)
3414 {
3415 JoinGroupReplyPacket p = (JoinGroupReplyPacket)PacketPool.Instance.GetPacket(PacketType.JoinGroupReply);
3416
3417 p.AgentData = new JoinGroupReplyPacket.AgentDataBlock();
3418 p.AgentData.AgentID = AgentId;
3419
3420 p.GroupData = new JoinGroupReplyPacket.GroupDataBlock();
3421 p.GroupData.GroupID = groupID;
3422 p.GroupData.Success = success;
3423
3424 OutPacket(p, ThrottleOutPacketType.Task);
3425 }
3426
3427 public void SendEjectGroupMemberReply(UUID agentID, UUID groupID, bool success)
3428 {
3429 EjectGroupMemberReplyPacket p = (EjectGroupMemberReplyPacket)PacketPool.Instance.GetPacket(PacketType.EjectGroupMemberReply);
3430
3431 p.AgentData = new EjectGroupMemberReplyPacket.AgentDataBlock();
3432 p.AgentData.AgentID = agentID;
3433
3434 p.GroupData = new EjectGroupMemberReplyPacket.GroupDataBlock();
3435 p.GroupData.GroupID = groupID;
3436
3437 p.EjectData = new EjectGroupMemberReplyPacket.EjectDataBlock();
3438 p.EjectData.Success = success;
3439
3440 OutPacket(p, ThrottleOutPacketType.Task);
3441 }
3442
3443 public void SendLeaveGroupReply(UUID groupID, bool success)
3444 {
3445 LeaveGroupReplyPacket p = (LeaveGroupReplyPacket)PacketPool.Instance.GetPacket(PacketType.LeaveGroupReply);
3446
3447 p.AgentData = new LeaveGroupReplyPacket.AgentDataBlock();
3448 p.AgentData.AgentID = AgentId;
3449
3450 p.GroupData = new LeaveGroupReplyPacket.GroupDataBlock();
3451 p.GroupData.GroupID = groupID;
3452 p.GroupData.Success = success;
3453
3454 OutPacket(p, ThrottleOutPacketType.Task);
3455 }
3456
3457 public void SendAvatarClassifiedReply(UUID targetID, UUID[] classifiedID, string[] name)
3458 {
3459 if (classifiedID.Length != name.Length)
3460 return;
3461
3462 AvatarClassifiedReplyPacket ac =
3463 (AvatarClassifiedReplyPacket)PacketPool.Instance.GetPacket(
3464 PacketType.AvatarClassifiedReply);
3465
3466 ac.AgentData = new AvatarClassifiedReplyPacket.AgentDataBlock();
3467 ac.AgentData.AgentID = AgentId;
3468 ac.AgentData.TargetID = targetID;
3469
3470 ac.Data = new AvatarClassifiedReplyPacket.DataBlock[classifiedID.Length];
3471 int i;
3472 for (i = 0; i < classifiedID.Length; i++)
3473 {
3474 ac.Data[i].ClassifiedID = classifiedID[i];
3475 ac.Data[i].Name = Utils.StringToBytes(name[i]);
3476 }
3477
3478 OutPacket(ac, ThrottleOutPacketType.Task);
3479 }
3480
3481 public void SendClassifiedInfoReply(UUID classifiedID, UUID creatorID, uint creationDate, uint expirationDate, uint category, string name, string description, UUID parcelID, uint parentEstate, UUID snapshotID, string simName, Vector3 globalPos, string parcelName, byte classifiedFlags, int price)
3482 {
3483 ClassifiedInfoReplyPacket cr =
3484 (ClassifiedInfoReplyPacket)PacketPool.Instance.GetPacket(
3485 PacketType.ClassifiedInfoReply);
3486
3487 cr.AgentData = new ClassifiedInfoReplyPacket.AgentDataBlock();
3488 cr.AgentData.AgentID = AgentId;
3489
3490 cr.Data = new ClassifiedInfoReplyPacket.DataBlock();
3491 cr.Data.ClassifiedID = classifiedID;
3492 cr.Data.CreatorID = creatorID;
3493 cr.Data.CreationDate = creationDate;
3494 cr.Data.ExpirationDate = expirationDate;
3495 cr.Data.Category = category;
3496 cr.Data.Name = Utils.StringToBytes(name);
3497 cr.Data.Desc = Utils.StringToBytes(description);
3498 cr.Data.ParcelID = parcelID;
3499 cr.Data.ParentEstate = parentEstate;
3500 cr.Data.SnapshotID = snapshotID;
3501 cr.Data.SimName = Utils.StringToBytes(simName);
3502 cr.Data.PosGlobal = new Vector3d(globalPos);
3503 cr.Data.ParcelName = Utils.StringToBytes(parcelName);
3504 cr.Data.ClassifiedFlags = classifiedFlags;
3505 cr.Data.PriceForListing = price;
3506
3507 OutPacket(cr, ThrottleOutPacketType.Task);
3508 }
3509
3510 public void SendAgentDropGroup(UUID groupID)
3511 {
3512 AgentDropGroupPacket dg =
3513 (AgentDropGroupPacket)PacketPool.Instance.GetPacket(
3514 PacketType.AgentDropGroup);
3515
3516 dg.AgentData = new AgentDropGroupPacket.AgentDataBlock();
3517 dg.AgentData.AgentID = AgentId;
3518 dg.AgentData.GroupID = groupID;
3519
3520 OutPacket(dg, ThrottleOutPacketType.Task);
3521 }
3522
3523 public void SendAvatarNotesReply(UUID targetID, string text)
3524 {
3525 AvatarNotesReplyPacket an =
3526 (AvatarNotesReplyPacket)PacketPool.Instance.GetPacket(
3527 PacketType.AvatarNotesReply);
3528
3529 an.AgentData = new AvatarNotesReplyPacket.AgentDataBlock();
3530 an.AgentData.AgentID = AgentId;
3531
3532 an.Data = new AvatarNotesReplyPacket.DataBlock();
3533 an.Data.TargetID = targetID;
3534 an.Data.Notes = Utils.StringToBytes(text);
3535
3536 OutPacket(an, ThrottleOutPacketType.Task);
3537 }
3538
3539 public void SendAvatarPicksReply(UUID targetID, Dictionary<UUID, string> picks)
3540 {
3541 AvatarPicksReplyPacket ap =
3542 (AvatarPicksReplyPacket)PacketPool.Instance.GetPacket(
3543 PacketType.AvatarPicksReply);
3544
3545 ap.AgentData = new AvatarPicksReplyPacket.AgentDataBlock();
3546 ap.AgentData.AgentID = AgentId;
3547 ap.AgentData.TargetID = targetID;
3548
3549 ap.Data = new AvatarPicksReplyPacket.DataBlock[picks.Count];
3550
3551 int i = 0;
3552 foreach (KeyValuePair<UUID, string> pick in picks)
3553 {
3554 ap.Data[i] = new AvatarPicksReplyPacket.DataBlock();
3555 ap.Data[i].PickID = pick.Key;
3556 ap.Data[i].PickName = Utils.StringToBytes(pick.Value);
3557 i++;
3558 }
3559
3560 OutPacket(ap, ThrottleOutPacketType.Task);
3561 }
3562
3563 public void SendAvatarClassifiedReply(UUID targetID, Dictionary<UUID, string> classifieds)
3564 {
3565 AvatarClassifiedReplyPacket ac =
3566 (AvatarClassifiedReplyPacket)PacketPool.Instance.GetPacket(
3567 PacketType.AvatarClassifiedReply);
3568
3569 ac.AgentData = new AvatarClassifiedReplyPacket.AgentDataBlock();
3570 ac.AgentData.AgentID = AgentId;
3571 ac.AgentData.TargetID = targetID;
3572
3573 ac.Data = new AvatarClassifiedReplyPacket.DataBlock[classifieds.Count];
3574
3575 int i = 0;
3576 foreach (KeyValuePair<UUID, string> classified in classifieds)
3577 {
3578 ac.Data[i] = new AvatarClassifiedReplyPacket.DataBlock();
3579 ac.Data[i].ClassifiedID = classified.Key;
3580 ac.Data[i].Name = Utils.StringToBytes(classified.Value);
3581 i++;
3582 }
3583
3584 OutPacket(ac, ThrottleOutPacketType.Task);
3585 }
3586
3587 public void SendParcelDwellReply(int localID, UUID parcelID, float dwell)
3588 {
3589 ParcelDwellReplyPacket pd =
3590 (ParcelDwellReplyPacket)PacketPool.Instance.GetPacket(
3591 PacketType.ParcelDwellReply);
3592
3593 pd.AgentData = new ParcelDwellReplyPacket.AgentDataBlock();
3594 pd.AgentData.AgentID = AgentId;
3595
3596 pd.Data = new ParcelDwellReplyPacket.DataBlock();
3597 pd.Data.LocalID = localID;
3598 pd.Data.ParcelID = parcelID;
3599 pd.Data.Dwell = dwell;
3600
3601 OutPacket(pd, ThrottleOutPacketType.Land);
3602 }
3603
3604 public void SendUserInfoReply(bool imViaEmail, bool visible, string email)
3605 {
3606 UserInfoReplyPacket ur =
3607 (UserInfoReplyPacket)PacketPool.Instance.GetPacket(
3608 PacketType.UserInfoReply);
3609
3610 string Visible = "hidden";
3611 if (visible)
3612 Visible = "default";
3613
3614 ur.AgentData = new UserInfoReplyPacket.AgentDataBlock();
3615 ur.AgentData.AgentID = AgentId;
3616
3617 ur.UserData = new UserInfoReplyPacket.UserDataBlock();
3618 ur.UserData.IMViaEMail = imViaEmail;
3619 ur.UserData.DirectoryVisibility = Utils.StringToBytes(Visible);
3620 ur.UserData.EMail = Utils.StringToBytes(email);
3621
3622 OutPacket(ur, ThrottleOutPacketType.Task);
3623 }
3624
3625 public void SendCreateGroupReply(UUID groupID, bool success, string message)
3626 {
3627 CreateGroupReplyPacket createGroupReply = (CreateGroupReplyPacket)PacketPool.Instance.GetPacket(PacketType.CreateGroupReply);
3628
3629 createGroupReply.AgentData =
3630 new CreateGroupReplyPacket.AgentDataBlock();
3631 createGroupReply.ReplyData =
3632 new CreateGroupReplyPacket.ReplyDataBlock();
3633
3634 createGroupReply.AgentData.AgentID = AgentId;
3635 createGroupReply.ReplyData.GroupID = groupID;
3636
3637 createGroupReply.ReplyData.Success = success;
3638 createGroupReply.ReplyData.Message = Utils.StringToBytes(message);
3639 OutPacket(createGroupReply, ThrottleOutPacketType.Task);
3640 }
3641
3642 public void SendUseCachedMuteList()
3643 {
3644 UseCachedMuteListPacket useCachedMuteList = (UseCachedMuteListPacket)PacketPool.Instance.GetPacket(PacketType.UseCachedMuteList);
3645
3646 useCachedMuteList.AgentData = new UseCachedMuteListPacket.AgentDataBlock();
3647 useCachedMuteList.AgentData.AgentID = AgentId;
3648
3649 OutPacket(useCachedMuteList, ThrottleOutPacketType.Task);
3650 }
3651
3652 public void SendMuteListUpdate(string filename)
3653 {
3654 MuteListUpdatePacket muteListUpdate = (MuteListUpdatePacket)PacketPool.Instance.GetPacket(PacketType.MuteListUpdate);
3655
3656 muteListUpdate.MuteData = new MuteListUpdatePacket.MuteDataBlock();
3657 muteListUpdate.MuteData.AgentID = AgentId;
3658 muteListUpdate.MuteData.Filename = Utils.StringToBytes(filename);
3659
3660 OutPacket(muteListUpdate, ThrottleOutPacketType.Task);
3661 }
3662
3663 public void SendPickInfoReply(UUID pickID, UUID creatorID, bool topPick, UUID parcelID, string name, string desc, UUID snapshotID, string user, string originalName, string simName, Vector3 posGlobal, int sortOrder, bool enabled)
3664 {
3665 PickInfoReplyPacket pickInfoReply = (PickInfoReplyPacket)PacketPool.Instance.GetPacket(PacketType.PickInfoReply);
3666
3667 pickInfoReply.AgentData = new PickInfoReplyPacket.AgentDataBlock();
3668 pickInfoReply.AgentData.AgentID = AgentId;
3669
3670 pickInfoReply.Data = new PickInfoReplyPacket.DataBlock();
3671 pickInfoReply.Data.PickID = pickID;
3672 pickInfoReply.Data.CreatorID = creatorID;
3673 pickInfoReply.Data.TopPick = topPick;
3674 pickInfoReply.Data.ParcelID = parcelID;
3675 pickInfoReply.Data.Name = Utils.StringToBytes(name);
3676 pickInfoReply.Data.Desc = Utils.StringToBytes(desc);
3677 pickInfoReply.Data.SnapshotID = snapshotID;
3678 pickInfoReply.Data.User = Utils.StringToBytes(user);
3679 pickInfoReply.Data.OriginalName = Utils.StringToBytes(originalName);
3680 pickInfoReply.Data.SimName = Utils.StringToBytes(simName);
3681 pickInfoReply.Data.PosGlobal = new Vector3d(posGlobal);
3682 pickInfoReply.Data.SortOrder = sortOrder;
3683 pickInfoReply.Data.Enabled = enabled;
3684
3685 OutPacket(pickInfoReply, ThrottleOutPacketType.Task);
3686 }
3687
3688 #endregion Scene/Avatar to Client
3689
3690 // Gesture
3691
3692 #region Appearance/ Wearables Methods
3693
3694 public void SendWearables(AvatarWearable[] wearables, int serial)
3695 {
3696 AgentWearablesUpdatePacket aw = (AgentWearablesUpdatePacket)PacketPool.Instance.GetPacket(PacketType.AgentWearablesUpdate);
3697 aw.AgentData.AgentID = AgentId;
3698 aw.AgentData.SerialNum = (uint)serial;
3699 aw.AgentData.SessionID = m_sessionId;
3700
3701 int count = 0;
3702 for (int i = 0; i < wearables.Length; i++)
3703 count += wearables[i].Count;
3704
3705 // TODO: don't create new blocks if recycling an old packet
3706 aw.WearableData = new AgentWearablesUpdatePacket.WearableDataBlock[count];
3707 AgentWearablesUpdatePacket.WearableDataBlock awb;
3708 int idx = 0;
3709 for (int i = 0; i < wearables.Length; i++)
3710 {
3711 for (int j = 0; j < wearables[i].Count; j++)
3712 {
3713 awb = new AgentWearablesUpdatePacket.WearableDataBlock();
3714 awb.WearableType = (byte)i;
3715 awb.AssetID = wearables[i][j].AssetID;
3716 awb.ItemID = wearables[i][j].ItemID;
3717 aw.WearableData[idx] = awb;
3718 idx++;
3719
3720// m_log.DebugFormat(
3721// "[APPEARANCE]: Sending wearable item/asset {0} {1} (index {2}) for {3}",
3722// awb.ItemID, awb.AssetID, i, Name);
3723 }
3724 }
3725
3726 OutPacket(aw, ThrottleOutPacketType.Task);
3727 }
3728
3729 public void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry)
3730 {
3731// m_log.DebugFormat(
3732// "[LLCLIENTVIEW]: Sending avatar appearance for {0} with {1} bytes to {2} {3}",
3733// agentID, textureEntry.Length, Name, AgentId);
3734
3735 AvatarAppearancePacket avp = (AvatarAppearancePacket)PacketPool.Instance.GetPacket(PacketType.AvatarAppearance);
3736 // TODO: don't create new blocks if recycling an old packet
3737 avp.VisualParam = new AvatarAppearancePacket.VisualParamBlock[visualParams.Length];
3738 avp.ObjectData.TextureEntry = textureEntry;
3739
3740 AvatarAppearancePacket.VisualParamBlock avblock = null;
3741 for (int i = 0; i < visualParams.Length; i++)
3742 {
3743 avblock = new AvatarAppearancePacket.VisualParamBlock();
3744 avblock.ParamValue = visualParams[i];
3745 avp.VisualParam[i] = avblock;
3746 }
3747
3748 avp.Sender.IsTrial = false;
3749 avp.Sender.ID = agentID;
3750 avp.AppearanceData = new AvatarAppearancePacket.AppearanceDataBlock[0];
3751 avp.AppearanceHover = new AvatarAppearancePacket.AppearanceHoverBlock[0];
3752 //m_log.DebugFormat("[CLIENT]: Sending appearance for {0} to {1}", agentID.ToString(), AgentId.ToString());
3753 OutPacket(avp, ThrottleOutPacketType.Task);
3754 }
3755
3756 public void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs)
3757 {
3758// m_log.DebugFormat("[LLCLIENTVIEW]: Sending animations for {0} to {1}", sourceAgentId, Name);
3759
3760 AvatarAnimationPacket ani = (AvatarAnimationPacket)PacketPool.Instance.GetPacket(PacketType.AvatarAnimation);
3761 // TODO: don't create new blocks if recycling an old packet
3762 ani.AnimationSourceList = new AvatarAnimationPacket.AnimationSourceListBlock[animations.Length];
3763 ani.Sender = new AvatarAnimationPacket.SenderBlock();
3764 ani.Sender.ID = sourceAgentId;
3765 ani.AnimationList = new AvatarAnimationPacket.AnimationListBlock[animations.Length];
3766 ani.PhysicalAvatarEventList = new AvatarAnimationPacket.PhysicalAvatarEventListBlock[0];
3767
3768 for (int i = 0; i < animations.Length; ++i)
3769 {
3770 ani.AnimationList[i] = new AvatarAnimationPacket.AnimationListBlock();
3771 ani.AnimationList[i].AnimID = animations[i];
3772 ani.AnimationList[i].AnimSequenceID = seqs[i];
3773
3774 ani.AnimationSourceList[i] = new AvatarAnimationPacket.AnimationSourceListBlock();
3775 if (objectIDs[i].Equals(sourceAgentId))
3776 ani.AnimationSourceList[i].ObjectID = UUID.Zero;
3777 else
3778 ani.AnimationSourceList[i].ObjectID = objectIDs[i];
3779 }
3780 ani.Header.Reliable = false;
3781 OutPacket(ani, ThrottleOutPacketType.Task);
3782 }
3783
3784 #endregion
3785
3786 #region Avatar Packet/Data Sending Methods
3787
3788 /// <summary>
3789 /// Send an ObjectUpdate packet with information about an avatar
3790 /// </summary>
3791 public void SendAvatarDataImmediate(ISceneEntity avatar)
3792 {
3793// m_log.DebugFormat(
3794// "[LLCLIENTVIEW]: Sending immediate object update for avatar {0} {1} to {2} {3}",
3795// avatar.Name, avatar.UUID, Name, AgentId);
3796
3797 ScenePresence presence = avatar as ScenePresence;
3798 if (presence == null)
3799 return;
3800
3801 ObjectUpdatePacket objupdate = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
3802 objupdate.Header.Zerocoded = true;
3803
3804 objupdate.RegionData.RegionHandle = presence.RegionHandle;
3805 objupdate.RegionData.TimeDilation = ushort.MaxValue;
3806
3807 objupdate.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1];
3808 objupdate.ObjectData[0] = CreateAvatarUpdateBlock(presence);
3809
3810 OutPacket(objupdate, ThrottleOutPacketType.Task);
3811
3812 // We need to record the avatar local id since the root prim of an attachment points to this.
3813// m_attachmentsSent.Add(avatar.LocalId);
3814 }
3815
3816 public void SendCoarseLocationUpdate(List<UUID> users, List<Vector3> CoarseLocations)
3817 {
3818 // We don't need to update inactive clients.
3819 if (!IsActive)
3820 return;
3821
3822 CoarseLocationUpdatePacket loc = (CoarseLocationUpdatePacket)PacketPool.Instance.GetPacket(PacketType.CoarseLocationUpdate);
3823 loc.Header.Reliable = false;
3824
3825 // Each packet can only hold around 60 avatar positions and the client clears the mini-map each time
3826 // a CoarseLocationUpdate packet is received. Oh well.
3827 int total = Math.Min(CoarseLocations.Count, 60);
3828
3829 CoarseLocationUpdatePacket.IndexBlock ib = new CoarseLocationUpdatePacket.IndexBlock();
3830
3831 loc.Location = new CoarseLocationUpdatePacket.LocationBlock[total];
3832 loc.AgentData = new CoarseLocationUpdatePacket.AgentDataBlock[total];
3833
3834 int selfindex = -1;
3835 for (int i = 0; i < total; i++)
3836 {
3837 CoarseLocationUpdatePacket.LocationBlock lb =
3838 new CoarseLocationUpdatePacket.LocationBlock();
3839
3840 lb.X = (byte)CoarseLocations[i].X;
3841 lb.Y = (byte)CoarseLocations[i].Y;
3842
3843 lb.Z = CoarseLocations[i].Z > 1024 ? (byte)0 : (byte)(CoarseLocations[i].Z * 0.25f);
3844 loc.Location[i] = lb;
3845 loc.AgentData[i] = new CoarseLocationUpdatePacket.AgentDataBlock();
3846 loc.AgentData[i].AgentID = users[i];
3847 if (users[i] == AgentId)
3848 selfindex = i;
3849 }
3850
3851 ib.You = (short)selfindex;
3852 ib.Prey = -1;
3853 loc.Index = ib;
3854
3855 OutPacket(loc, ThrottleOutPacketType.Task);
3856 }
3857
3858 #endregion Avatar Packet/Data Sending Methods
3859
3860 #region Primitive Packet/Data Sending Methods
3861
3862
3863 /// <summary>
3864 /// Generate one of the object update packets based on PrimUpdateFlags
3865 /// and broadcast the packet to clients
3866 /// </summary>
3867 public void SendEntityUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags)
3868 {
3869 if (entity.UUID == m_agentId && !updateFlags.HasFlag(PrimUpdateFlags.FullUpdate))
3870 {
3871 ImprovedTerseObjectUpdatePacket packet
3872 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate);
3873
3874 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3875 packet.RegionData.TimeDilation = Utils.FloatToUInt16(1, 0.0f, 1.0f);
3876 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1];
3877 packet.ObjectData[0] = CreateImprovedTerseBlock(entity, false);
3878 OutPacket(packet, ThrottleOutPacketType.Unknown, true);
3879 }
3880 else
3881 {
3882 //double priority = m_prioritizer.GetUpdatePriority(this, entity);
3883 uint priority = m_prioritizer.GetUpdatePriority(this, entity);
3884
3885 lock (m_entityUpdates.SyncRoot)
3886 m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation));
3887 }
3888 }
3889
3890 /// <summary>
3891 /// Requeue an EntityUpdate when it was not acknowledged by the client.
3892 /// We will update the priority and put it in the correct queue, merging update flags
3893 /// with any other updates that may be queued for the same entity.
3894 /// The original update time is used for the merged update.
3895 /// </summary>
3896 private void ResendPrimUpdate(EntityUpdate update)
3897 {
3898 // If the update exists in priority queue, it will be updated.
3899 // If it does not exist then it will be added with the current (rather than its original) priority
3900 uint priority = m_prioritizer.GetUpdatePriority(this, update.Entity);
3901
3902 lock (m_entityUpdates.SyncRoot)
3903 m_entityUpdates.Enqueue(priority, update);
3904 }
3905
3906 /// <summary>
3907 /// Requeue a list of EntityUpdates when they were not acknowledged by the client.
3908 /// We will update the priority and put it in the correct queue, merging update flags
3909 /// with any other updates that may be queued for the same entity.
3910 /// The original update time is used for the merged update.
3911 /// </summary>
3912 private void ResendPrimUpdates(List<EntityUpdate> updates, OutgoingPacket oPacket)
3913 {
3914 // m_log.WarnFormat("[CLIENT] resending prim updates {0}, packet sequence number {1}", updates[0].UpdateTime, oPacket.SequenceNumber);
3915
3916 // Remove the update packet from the list of packets waiting for acknowledgement
3917 // because we are requeuing the list of updates. They will be resent in new packets
3918 // with the most recent state and priority.
3919 m_udpClient.NeedAcks.Remove(oPacket.SequenceNumber);
3920
3921 // Count this as a resent packet since we are going to requeue all of the updates contained in it
3922 Interlocked.Increment(ref m_udpClient.PacketsResent);
3923
3924 // We're not going to worry about interlock yet since its not currently critical that this total count
3925 // is 100% correct
3926 m_udpServer.PacketsResentCount++;
3927
3928 foreach (EntityUpdate update in updates)
3929 ResendPrimUpdate(update);
3930 }
3931
3932// OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>();
3933// OpenSim.Framework.Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>> compressedUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>>();
3934// OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();
3935// OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();
3936//
3937// OpenSim.Framework.Lazy<List<EntityUpdate>> objectUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3938// OpenSim.Framework.Lazy<List<EntityUpdate>> compressedUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3939// OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3940// OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3941
3942
3943 private void ProcessEntityUpdates(int maxUpdates)
3944 {
3945 OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>();
3946 OpenSim.Framework.Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>> compressedUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>>();
3947 OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();
3948 OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();
3949
3950 OpenSim.Framework.Lazy<List<EntityUpdate>> objectUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3951 OpenSim.Framework.Lazy<List<EntityUpdate>> compressedUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3952 OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3953 OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3954
3955// objectUpdateBlocks.Value.Clear();
3956// compressedUpdateBlocks.Value.Clear();
3957// terseUpdateBlocks.Value.Clear();
3958// terseAgentUpdateBlocks.Value.Clear();
3959// objectUpdates.Value.Clear();
3960// compressedUpdates.Value.Clear();
3961// terseUpdates.Value.Clear();
3962// terseAgentUpdates.Value.Clear();
3963
3964 // Check to see if this is a flush
3965 if (maxUpdates <= 0)
3966 {
3967 maxUpdates = Int32.MaxValue;
3968 }
3969
3970 int updatesThisCall = 0;
3971
3972 // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race
3973 // condition where a kill can be processed before an out-of-date update for the same object.
3974 lock (m_killRecord)
3975 {
3976 float avgTimeDilation = 1.0f;
3977 IEntityUpdate iupdate;
3978 Int32 timeinqueue; // this is just debugging code & can be dropped later
3979
3980 while (updatesThisCall < maxUpdates)
3981 {
3982 lock (m_entityUpdates.SyncRoot)
3983 if (!m_entityUpdates.TryDequeue(out iupdate, out timeinqueue))
3984 break;
3985
3986 EntityUpdate update = (EntityUpdate)iupdate;
3987
3988 avgTimeDilation += update.TimeDilation;
3989 avgTimeDilation *= 0.5f;
3990
3991 if (update.Entity is SceneObjectPart)
3992 {
3993 SceneObjectPart part = (SceneObjectPart)update.Entity;
3994
3995 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client
3996 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good
3997 // safety measure.
3998 //
3999 // If a Linden Lab 1.23.5 client (and possibly later and earlier) receives an object update
4000 // after a kill, it will keep displaying the deleted object until relog. OpenSim currently performs
4001 // updates and kills on different threads with different scheduling strategies, hence this protection.
4002 //
4003 // This doesn't appear to apply to child prims - a client will happily ignore these updates
4004 // after the root prim has been deleted.
4005 if (m_killRecord.Contains(part.LocalId))
4006 {
4007 // m_log.WarnFormat(
4008 // "[CLIENT]: Preventing update for prim with local id {0} after client for user {1} told it was deleted",
4009 // part.LocalId, Name);
4010 continue;
4011 }
4012
4013 if (part.ParentGroup.IsAttachment && m_disableFacelights)
4014 {
4015 if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand &&
4016 part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand)
4017 {
4018 part.Shape.LightEntry = false;
4019 }
4020 }
4021
4022 if (part.Shape != null && (part.Shape.SculptType == (byte)SculptType.Mesh))
4023 {
4024 // Ensure that mesh has at least 8 valid faces
4025 part.Shape.ProfileBegin = 12500;
4026 part.Shape.ProfileEnd = 0;
4027 part.Shape.ProfileHollow = 27500;
4028 }
4029 }
4030
4031 #region UpdateFlags to packet type conversion
4032
4033 PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags;
4034
4035 bool canUseCompressed = true;
4036 bool canUseImproved = true;
4037
4038 // Compressed object updates only make sense for LL primitives
4039 if (!(update.Entity is SceneObjectPart))
4040 {
4041 canUseCompressed = false;
4042 }
4043
4044 if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate))
4045 {
4046 canUseCompressed = false;
4047 canUseImproved = false;
4048 }
4049 else
4050 {
4051 if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) ||
4052 updateFlags.HasFlag(PrimUpdateFlags.Acceleration) ||
4053 updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) ||
4054 updateFlags.HasFlag(PrimUpdateFlags.Joint))
4055 {
4056 canUseCompressed = false;
4057 }
4058
4059 if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) ||
4060 updateFlags.HasFlag(PrimUpdateFlags.ParentID) ||
4061 updateFlags.HasFlag(PrimUpdateFlags.Scale) ||
4062 updateFlags.HasFlag(PrimUpdateFlags.PrimData) ||
4063 updateFlags.HasFlag(PrimUpdateFlags.Text) ||
4064 updateFlags.HasFlag(PrimUpdateFlags.NameValue) ||
4065 updateFlags.HasFlag(PrimUpdateFlags.ExtraData) ||
4066 updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) ||
4067 updateFlags.HasFlag(PrimUpdateFlags.Sound) ||
4068 updateFlags.HasFlag(PrimUpdateFlags.Particles) ||
4069 updateFlags.HasFlag(PrimUpdateFlags.Material) ||
4070 updateFlags.HasFlag(PrimUpdateFlags.ClickAction) ||
4071 updateFlags.HasFlag(PrimUpdateFlags.MediaURL) ||
4072 updateFlags.HasFlag(PrimUpdateFlags.Joint))
4073 {
4074 canUseImproved = false;
4075 }
4076 }
4077
4078 #endregion UpdateFlags to packet type conversion
4079
4080 #region Block Construction
4081
4082 // TODO: Remove this once we can build compressed updates
4083 canUseCompressed = false;
4084
4085 if (!canUseImproved && !canUseCompressed)
4086 {
4087 ObjectUpdatePacket.ObjectDataBlock updateBlock;
4088
4089 if (update.Entity is ScenePresence)
4090 {
4091 updateBlock = CreateAvatarUpdateBlock((ScenePresence)update.Entity);
4092 }
4093 else
4094 {
4095 SceneObjectPart part = (SceneObjectPart)update.Entity;
4096 updateBlock = CreatePrimUpdateBlock(part, AgentId);
4097
4098 // If the part has become a private hud since the update was scheduled then we do not
4099 // want to send it to other avatars.
4100 if (part.ParentGroup.IsAttachment
4101 && part.ParentGroup.HasPrivateAttachmentPoint
4102 && part.ParentGroup.AttachedAvatar != AgentId)
4103 continue;
4104
4105 // If the part has since been deleted, then drop the update. In the case of attachments,
4106 // this is to avoid spurious updates to other viewers since post-processing of attachments
4107 // has to change the IsAttachment flag for various reasons (which will end up in a pass
4108 // of the test above).
4109 //
4110 // Actual deletions (kills) happen in another method.
4111 if (part.ParentGroup.IsDeleted)
4112 continue;
4113 }
4114
4115 objectUpdateBlocks.Value.Add(updateBlock);
4116 objectUpdates.Value.Add(update);
4117 }
4118 else if (!canUseImproved)
4119 {
4120 SceneObjectPart part = (SceneObjectPart)update.Entity;
4121 ObjectUpdateCompressedPacket.ObjectDataBlock compressedBlock
4122 = CreateCompressedUpdateBlock(part, updateFlags);
4123
4124 // If the part has since been deleted, then drop the update. In the case of attachments,
4125 // this is to avoid spurious updates to other viewers since post-processing of attachments
4126 // has to change the IsAttachment flag for various reasons (which will end up in a pass
4127 // of the test above).
4128 //
4129 // Actual deletions (kills) happen in another method.
4130 if (part.ParentGroup.IsDeleted)
4131 continue;
4132
4133 compressedUpdateBlocks.Value.Add(compressedBlock);
4134 compressedUpdates.Value.Add(update);
4135 }
4136 else
4137 {
4138 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId)
4139 {
4140 // Self updates go into a special list
4141 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
4142 terseAgentUpdates.Value.Add(update);
4143 }
4144 else
4145 {
4146 ImprovedTerseObjectUpdatePacket.ObjectDataBlock terseUpdateBlock
4147 = CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures));
4148
4149 // Everything else goes here
4150 if (update.Entity is SceneObjectPart)
4151 {
4152 SceneObjectPart part = (SceneObjectPart)update.Entity;
4153
4154 // If the part has become a private hud since the update was scheduled then we do not
4155 // want to send it to other avatars.
4156 if (part.ParentGroup.IsAttachment
4157 && part.ParentGroup.HasPrivateAttachmentPoint
4158 && part.ParentGroup.AttachedAvatar != AgentId)
4159 continue;
4160
4161 // If the part has since been deleted, then drop the update. In the case of attachments,
4162 // this is to avoid spurious updates to other viewers since post-processing of attachments
4163 // has to change the IsAttachment flag for various reasons (which will end up in a pass
4164 // of the test above).
4165 //
4166 // Actual deletions (kills) happen in another method.
4167 if (part.ParentGroup.IsDeleted)
4168 continue;
4169 }
4170
4171 terseUpdateBlocks.Value.Add(terseUpdateBlock);
4172 terseUpdates.Value.Add(update);
4173 }
4174 }
4175
4176 ++updatesThisCall;
4177
4178 #endregion Block Construction
4179 }
4180
4181 #region Packet Sending
4182 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f);
4183
4184 if (terseAgentUpdateBlocks.IsValueCreated)
4185 {
4186 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value;
4187
4188 ImprovedTerseObjectUpdatePacket packet
4189 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate);
4190
4191 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4192 packet.RegionData.TimeDilation = timeDilation;
4193 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
4194
4195 for (int i = 0; i < blocks.Count; i++)
4196 packet.ObjectData[i] = blocks[i];
4197 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
4198 OutPacket(packet, ThrottleOutPacketType.Unknown, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseAgentUpdates.Value, oPacket); });
4199 }
4200
4201 if (objectUpdateBlocks.IsValueCreated)
4202 {
4203 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value;
4204
4205 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
4206 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4207 packet.RegionData.TimeDilation = timeDilation;
4208 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count];
4209
4210 for (int i = 0; i < blocks.Count; i++)
4211 packet.ObjectData[i] = blocks[i];
4212 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
4213 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(objectUpdates.Value, oPacket); });
4214 }
4215
4216 if (compressedUpdateBlocks.IsValueCreated)
4217 {
4218 List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value;
4219
4220 ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
4221 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4222 packet.RegionData.TimeDilation = timeDilation;
4223 packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];
4224
4225 for (int i = 0; i < blocks.Count; i++)
4226 packet.ObjectData[i] = blocks[i];
4227 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
4228 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(compressedUpdates.Value, oPacket); });
4229 }
4230
4231 if (terseUpdateBlocks.IsValueCreated)
4232 {
4233 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
4234
4235 ImprovedTerseObjectUpdatePacket packet
4236 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
4237 PacketType.ImprovedTerseObjectUpdate);
4238
4239 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4240 packet.RegionData.TimeDilation = timeDilation;
4241 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
4242
4243 for (int i = 0; i < blocks.Count; i++)
4244 packet.ObjectData[i] = blocks[i];
4245 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
4246 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); });
4247 }
4248 }
4249
4250// m_log.DebugFormat(
4251// "[LLCLIENTVIEW]: Sent {0} updates in ProcessEntityUpdates() for {1} {2} in {3}",
4252// updatesThisCall, Name, SceneAgent.IsChildAgent ? "child" : "root", Scene.Name);
4253//
4254 #endregion Packet Sending
4255 }
4256
4257 public void ReprioritizeUpdates()
4258 {
4259 lock (m_entityUpdates.SyncRoot)
4260 m_entityUpdates.Reprioritize(UpdatePriorityHandler);
4261 }
4262
4263 private bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity)
4264 {
4265 if (entity != null)
4266 {
4267 priority = m_prioritizer.GetUpdatePriority(this, entity);
4268 return true;
4269 }
4270
4271 return false;
4272 }
4273
4274 public void FlushPrimUpdates()
4275 {
4276 m_log.WarnFormat("[CLIENT]: Flushing prim updates to " + m_firstName + " " + m_lastName);
4277
4278 while (m_entityUpdates.Count > 0)
4279 ProcessEntityUpdates(-1);
4280 }
4281
4282 #endregion Primitive Packet/Data Sending Methods
4283
4284 // These are used to implement an adaptive backoff in the number
4285 // of updates converted to packets. Since we don't want packets
4286 // to sit in the queue with old data, only convert enough updates
4287 // to packets that can be sent in 200ms.
4288 private Int32 m_LastQueueFill = 0;
4289 private Int32 m_maxUpdates = 0;
4290
4291 void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories)
4292 {
4293// if (!m_udpServer.IsRunningOutbound)
4294// return;
4295
4296 if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
4297 {
4298// if (!m_udpServer.IsRunningOutbound)
4299// return;
4300
4301 if (m_maxUpdates == 0 || m_LastQueueFill == 0)
4302 {
4303 m_maxUpdates = m_udpServer.PrimUpdatesPerCallback;
4304 }
4305 else
4306 {
4307 if (Util.EnvironmentTickCountSubtract(m_LastQueueFill) < 200)
4308 m_maxUpdates += 5;
4309 else
4310 m_maxUpdates = m_maxUpdates >> 1;
4311 }
4312 m_maxUpdates = Util.Clamp<Int32>(m_maxUpdates,10,500);
4313 m_LastQueueFill = Util.EnvironmentTickCount();
4314
4315 if (m_entityUpdates.Count > 0)
4316 ProcessEntityUpdates(m_maxUpdates);
4317
4318 if (m_entityProps.Count > 0)
4319 ProcessEntityPropertyRequests(m_maxUpdates);
4320 }
4321
4322 if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0)
4323 ImageManager.ProcessImageQueue(m_udpServer.TextureSendLimit);
4324 }
4325
4326 internal bool HandleHasUpdates(ThrottleOutPacketTypeFlags categories)
4327 {
4328 bool hasUpdates = false;
4329
4330 if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
4331 {
4332 if (m_entityUpdates.Count > 0)
4333 hasUpdates = true;
4334 else if (m_entityProps.Count > 0)
4335 hasUpdates = true;
4336 }
4337
4338 if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0)
4339 {
4340 if (ImageManager.HasUpdates())
4341 hasUpdates = true;
4342 }
4343
4344 return hasUpdates;
4345 }
4346
4347 public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID)
4348 {
4349 AssetUploadCompletePacket newPack = new AssetUploadCompletePacket();
4350 newPack.AssetBlock.Type = AssetType;
4351 newPack.AssetBlock.Success = Success;
4352 newPack.AssetBlock.UUID = AssetFullID;
4353 newPack.Header.Zerocoded = true;
4354 OutPacket(newPack, ThrottleOutPacketType.Asset);
4355 }
4356
4357 public void SendXferRequest(ulong XferID, short AssetType, UUID vFileID, byte FilePath, byte[] FileName)
4358 {
4359 RequestXferPacket newPack = new RequestXferPacket();
4360 newPack.XferID.ID = XferID;
4361 newPack.XferID.VFileType = AssetType;
4362 newPack.XferID.VFileID = vFileID;
4363 newPack.XferID.FilePath = FilePath;
4364 newPack.XferID.Filename = FileName;
4365 newPack.Header.Zerocoded = true;
4366 OutPacket(newPack, ThrottleOutPacketType.Asset);
4367 }
4368
4369 public void SendConfirmXfer(ulong xferID, uint PacketID)
4370 {
4371 ConfirmXferPacketPacket newPack = new ConfirmXferPacketPacket();
4372 newPack.XferID.ID = xferID;
4373 newPack.XferID.Packet = PacketID;
4374 newPack.Header.Zerocoded = true;
4375 OutPacket(newPack, ThrottleOutPacketType.Asset);
4376 }
4377
4378 public void SendInitiateDownload(string simFileName, string clientFileName)
4379 {
4380 InitiateDownloadPacket newPack = new InitiateDownloadPacket();
4381 newPack.AgentData.AgentID = AgentId;
4382 newPack.FileData.SimFilename = Utils.StringToBytes(simFileName);
4383 newPack.FileData.ViewerFilename = Utils.StringToBytes(clientFileName);
4384 OutPacket(newPack, ThrottleOutPacketType.Asset);
4385 }
4386
4387 public void SendImageFirstPart(
4388 ushort numParts, UUID ImageUUID, uint ImageSize, byte[] ImageData, byte imageCodec)
4389 {
4390 ImageDataPacket im = new ImageDataPacket();
4391 im.Header.Reliable = false;
4392 im.ImageID.Packets = numParts;
4393 im.ImageID.ID = ImageUUID;
4394
4395 if (ImageSize > 0)
4396 im.ImageID.Size = ImageSize;
4397
4398 im.ImageData.Data = ImageData;
4399 im.ImageID.Codec = imageCodec;
4400 im.Header.Zerocoded = true;
4401 OutPacket(im, ThrottleOutPacketType.Texture);
4402 }
4403
4404 public void SendImageNextPart(ushort partNumber, UUID imageUuid, byte[] imageData)
4405 {
4406 ImagePacketPacket im = new ImagePacketPacket();
4407 im.Header.Reliable = false;
4408 im.ImageID.Packet = partNumber;
4409 im.ImageID.ID = imageUuid;
4410 im.ImageData.Data = imageData;
4411
4412 OutPacket(im, ThrottleOutPacketType.Texture);
4413 }
4414
4415 public void SendImageNotFound(UUID imageid)
4416 {
4417 ImageNotInDatabasePacket notFoundPacket
4418 = (ImageNotInDatabasePacket)PacketPool.Instance.GetPacket(PacketType.ImageNotInDatabase);
4419
4420 notFoundPacket.ImageID.ID = imageid;
4421
4422 OutPacket(notFoundPacket, ThrottleOutPacketType.Texture);
4423 }
4424
4425 public void SendShutdownConnectionNotice()
4426 {
4427 OutPacket(PacketPool.Instance.GetPacket(PacketType.DisableSimulator), ThrottleOutPacketType.Unknown);
4428 }
4429
4430 public void SendSimStats(SimStats stats)
4431 {
4432 SimStatsPacket pack = new SimStatsPacket();
4433 pack.Region = new SimStatsPacket.RegionBlock();
4434 pack.Region.RegionX = stats.RegionX;
4435 pack.Region.RegionY = stats.RegionY;
4436 pack.Region.RegionFlags = stats.RegionFlags;
4437 pack.Region.ObjectCapacity = stats.ObjectCapacity;
4438 //pack.Region = //stats.RegionBlock;
4439 pack.Stat = stats.StatsBlock;
4440
4441 pack.Header.Reliable = false;
4442 pack.RegionInfo = new SimStatsPacket.RegionInfoBlock[0];
4443 OutPacket(pack, ThrottleOutPacketType.Task);
4444 }
4445
4446 private class ObjectPropertyUpdate : IEntityUpdate
4447 {
4448 internal bool SendFamilyProps;
4449 internal bool SendObjectProps;
4450
4451 public ObjectPropertyUpdate(ISceneEntity entity, uint flags, bool sendfam, bool sendobj)
4452 : base(entity,flags)
4453 {
4454 SendFamilyProps = sendfam;
4455 SendObjectProps = sendobj;
4456 }
4457 public void Update(ObjectPropertyUpdate update)
4458 {
4459 SendFamilyProps = SendFamilyProps || update.SendFamilyProps;
4460 SendObjectProps = SendObjectProps || update.SendObjectProps;
4461 // other properties may need to be updated by base class
4462 base.Update(update);
4463 }
4464 }
4465
4466 public void SendObjectPropertiesFamilyData(ISceneEntity entity, uint requestFlags)
4467 {
4468 uint priority = 0; // time based ordering only
4469 lock (m_entityProps.SyncRoot)
4470 m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,requestFlags,true,false));
4471 }
4472
4473 private void ResendPropertyUpdate(ObjectPropertyUpdate update)
4474 {
4475 uint priority = 0;
4476 lock (m_entityProps.SyncRoot)
4477 m_entityProps.Enqueue(priority, update);
4478 }
4479
4480 private void ResendPropertyUpdates(List<ObjectPropertyUpdate> updates, OutgoingPacket oPacket)
4481 {
4482 // m_log.WarnFormat("[CLIENT] resending object property {0}",updates[0].UpdateTime);
4483
4484 // Remove the update packet from the list of packets waiting for acknowledgement
4485 // because we are requeuing the list of updates. They will be resent in new packets
4486 // with the most recent state.
4487 m_udpClient.NeedAcks.Remove(oPacket.SequenceNumber);
4488
4489 // Count this as a resent packet since we are going to requeue all of the updates contained in it
4490 Interlocked.Increment(ref m_udpClient.PacketsResent);
4491
4492 // We're not going to worry about interlock yet since its not currently critical that this total count
4493 // is 100% correct
4494 m_udpServer.PacketsResentCount++;
4495
4496 foreach (ObjectPropertyUpdate update in updates)
4497 ResendPropertyUpdate(update);
4498 }
4499
4500 public void SendObjectPropertiesReply(ISceneEntity entity)
4501 {
4502 uint priority = 0; // time based ordering only
4503 lock (m_entityProps.SyncRoot)
4504 m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,0,false,true));
4505 }
4506
4507 private void ProcessEntityPropertyRequests(int maxUpdates)
4508 {
4509 OpenSim.Framework.Lazy<List<ObjectPropertiesFamilyPacket.ObjectDataBlock>> objectFamilyBlocks =
4510 new OpenSim.Framework.Lazy<List<ObjectPropertiesFamilyPacket.ObjectDataBlock>>();
4511
4512 OpenSim.Framework.Lazy<List<ObjectPropertiesPacket.ObjectDataBlock>> objectPropertiesBlocks =
4513 new OpenSim.Framework.Lazy<List<ObjectPropertiesPacket.ObjectDataBlock>>();
4514
4515 OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>> familyUpdates =
4516 new OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>>();
4517
4518 OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>> propertyUpdates =
4519 new OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>>();
4520
4521 IEntityUpdate iupdate;
4522 Int32 timeinqueue; // this is just debugging code & can be dropped later
4523
4524 int updatesThisCall = 0;
4525 while (updatesThisCall < m_maxUpdates)
4526 {
4527 lock (m_entityProps.SyncRoot)
4528 if (!m_entityProps.TryDequeue(out iupdate, out timeinqueue))
4529 break;
4530
4531 ObjectPropertyUpdate update = (ObjectPropertyUpdate)iupdate;
4532 if (update.SendFamilyProps)
4533 {
4534 if (update.Entity is SceneObjectPart)
4535 {
4536 SceneObjectPart sop = (SceneObjectPart)update.Entity;
4537 ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesFamilyBlock(sop,update.Flags);
4538 objectFamilyBlocks.Value.Add(objPropDB);
4539 familyUpdates.Value.Add(update);
4540 }
4541 }
4542
4543 if (update.SendObjectProps)
4544 {
4545 if (update.Entity is SceneObjectPart)
4546 {
4547 SceneObjectPart sop = (SceneObjectPart)update.Entity;
4548 ObjectPropertiesPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesBlock(sop);
4549 objectPropertiesBlocks.Value.Add(objPropDB);
4550 propertyUpdates.Value.Add(update);
4551 }
4552 }
4553
4554 updatesThisCall++;
4555 }
4556
4557
4558 // Int32 ppcnt = 0;
4559 // Int32 pbcnt = 0;
4560
4561 if (objectPropertiesBlocks.IsValueCreated)
4562 {
4563 List<ObjectPropertiesPacket.ObjectDataBlock> blocks = objectPropertiesBlocks.Value;
4564 List<ObjectPropertyUpdate> updates = propertyUpdates.Value;
4565
4566 ObjectPropertiesPacket packet = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties);
4567 packet.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[blocks.Count];
4568 for (int i = 0; i < blocks.Count; i++)
4569 packet.ObjectData[i] = blocks[i];
4570
4571 packet.Header.Zerocoded = true;
4572
4573 // Pass in the delegate so that if this packet needs to be resent, we send the current properties
4574 // of the object rather than the properties when the packet was created
4575 OutPacket(packet, ThrottleOutPacketType.Task, true,
4576 delegate(OutgoingPacket oPacket)
4577 {
4578 ResendPropertyUpdates(updates, oPacket);
4579 });
4580
4581 // pbcnt += blocks.Count;
4582 // ppcnt++;
4583 }
4584
4585 // Int32 fpcnt = 0;
4586 // Int32 fbcnt = 0;
4587
4588 if (objectFamilyBlocks.IsValueCreated)
4589 {
4590 List<ObjectPropertiesFamilyPacket.ObjectDataBlock> blocks = objectFamilyBlocks.Value;
4591
4592 // one packet per object block... uggh...
4593 for (int i = 0; i < blocks.Count; i++)
4594 {
4595 ObjectPropertiesFamilyPacket packet =
4596 (ObjectPropertiesFamilyPacket)PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily);
4597
4598 packet.ObjectData = blocks[i];
4599 packet.Header.Zerocoded = true;
4600
4601 // Pass in the delegate so that if this packet needs to be resent, we send the current properties
4602 // of the object rather than the properties when the packet was created
4603 List<ObjectPropertyUpdate> updates = new List<ObjectPropertyUpdate>();
4604 updates.Add(familyUpdates.Value[i]);
4605 OutPacket(packet, ThrottleOutPacketType.Task, true,
4606 delegate(OutgoingPacket oPacket)
4607 {
4608 ResendPropertyUpdates(updates, oPacket);
4609 });
4610
4611 // fpcnt++;
4612 // fbcnt++;
4613 }
4614
4615 }
4616
4617 // m_log.WarnFormat("[PACKETCOUNTS] queued {0} property packets with {1} blocks",ppcnt,pbcnt);
4618 // m_log.WarnFormat("[PACKETCOUNTS] queued {0} family property packets with {1} blocks",fpcnt,fbcnt);
4619 }
4620
4621 private ObjectPropertiesFamilyPacket.ObjectDataBlock CreateObjectPropertiesFamilyBlock(SceneObjectPart sop, uint requestFlags)
4622 {
4623 ObjectPropertiesFamilyPacket.ObjectDataBlock block = new ObjectPropertiesFamilyPacket.ObjectDataBlock();
4624
4625 block.RequestFlags = requestFlags;
4626 block.ObjectID = sop.UUID;
4627 if (sop.OwnerID == sop.GroupID)
4628 block.OwnerID = UUID.Zero;
4629 else
4630 block.OwnerID = sop.OwnerID;
4631 block.GroupID = sop.GroupID;
4632 block.BaseMask = sop.BaseMask;
4633 block.OwnerMask = sop.OwnerMask;
4634 block.GroupMask = sop.GroupMask;
4635 block.EveryoneMask = sop.EveryoneMask;
4636 block.NextOwnerMask = sop.NextOwnerMask;
4637
4638 // TODO: More properties are needed in SceneObjectPart!
4639 block.OwnershipCost = sop.OwnershipCost;
4640 block.SaleType = sop.ObjectSaleType;
4641 block.SalePrice = sop.SalePrice;
4642 block.Category = sop.Category;
4643 block.LastOwnerID = sop.CreatorID; // copied from old SOG call... is this right?
4644 block.Name = Util.StringToBytes256(sop.Name);
4645 block.Description = Util.StringToBytes256(sop.Description);
4646
4647 return block;
4648 }
4649
4650 private ObjectPropertiesPacket.ObjectDataBlock CreateObjectPropertiesBlock(SceneObjectPart sop)
4651 {
4652 //ObjectPropertiesPacket proper = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties);
4653 // TODO: don't create new blocks if recycling an old packet
4654
4655 ObjectPropertiesPacket.ObjectDataBlock block =
4656 new ObjectPropertiesPacket.ObjectDataBlock();
4657
4658 block.ObjectID = sop.UUID;
4659 block.Name = Util.StringToBytes256(sop.Name);
4660 block.Description = Util.StringToBytes256(sop.Description);
4661
4662 block.CreationDate = (ulong)sop.CreationDate * 1000000; // viewer wants date in microseconds
4663 block.CreatorID = sop.CreatorID;
4664 block.GroupID = sop.GroupID;
4665 block.LastOwnerID = sop.LastOwnerID;
4666 if (sop.OwnerID == sop.GroupID)
4667 block.OwnerID = UUID.Zero;
4668 else
4669 block.OwnerID = sop.OwnerID;
4670
4671 block.ItemID = sop.FromUserInventoryItemID;
4672 block.FolderID = UUID.Zero; // sog.FromFolderID ??
4673 block.FromTaskID = UUID.Zero; // ???
4674 block.InventorySerial = (short)sop.InventorySerial;
4675
4676 SceneObjectPart root = sop.ParentGroup.RootPart;
4677
4678 block.TouchName = Util.StringToBytes256(root.TouchName);
4679
4680 // SL 3.3.4, at least, appears to read this information as a concatenated byte[] stream of UUIDs but
4681 // it's not yet clear whether this is actually used. If this is done in the future then a pre-cached
4682 // copy is really needed since it's less efficient to be constantly recreating this byte array.
4683// using (MemoryStream memStream = new MemoryStream())
4684// {
4685// using (BinaryWriter binWriter = new BinaryWriter(memStream))
4686// {
4687// for (int i = 0; i < sop.GetNumberOfSides(); i++)
4688// {
4689// Primitive.TextureEntryFace teFace = sop.Shape.Textures.FaceTextures[i];
4690//
4691// UUID textureID;
4692//
4693// if (teFace != null)
4694// textureID = teFace.TextureID;
4695// else
4696// textureID = sop.Shape.Textures.DefaultTexture.TextureID;
4697//
4698// binWriter.Write(textureID.GetBytes());
4699// }
4700//
4701// block.TextureID = memStream.ToArray();
4702// }
4703// }
4704
4705 block.TextureID = new byte[0]; // TextureID ???
4706 block.SitName = Util.StringToBytes256(root.SitName);
4707 block.OwnerMask = root.OwnerMask;
4708 block.NextOwnerMask = root.NextOwnerMask;
4709 block.GroupMask = root.GroupMask;
4710 block.EveryoneMask = root.EveryoneMask;
4711 block.BaseMask = root.BaseMask;
4712 block.SaleType = root.ObjectSaleType;
4713 block.SalePrice = root.SalePrice;
4714
4715 return block;
4716 }
4717
4718 #region Estate Data Sending Methods
4719
4720 private static bool convertParamStringToBool(byte[] field)
4721 {
4722 string s = Utils.BytesToString(field);
4723 if (s == "1" || s.ToLower() == "y" || s.ToLower() == "yes" || s.ToLower() == "t" || s.ToLower() == "true")
4724 {
4725 return true;
4726 }
4727 return false;
4728 }
4729
4730 public void SendEstateList(UUID invoice, int code, UUID[] Data, uint estateID)
4731
4732 {
4733 EstateOwnerMessagePacket packet = new EstateOwnerMessagePacket();
4734 packet.AgentData.TransactionID = UUID.Random();
4735 packet.AgentData.AgentID = AgentId;
4736 packet.AgentData.SessionID = SessionId;
4737 packet.MethodData.Invoice = invoice;
4738 packet.MethodData.Method = Utils.StringToBytes("setaccess");
4739
4740 EstateOwnerMessagePacket.ParamListBlock[] returnblock = new EstateOwnerMessagePacket.ParamListBlock[6 + Data.Length];
4741
4742 for (int i = 0; i < (6 + Data.Length); i++)
4743 {
4744 returnblock[i] = new EstateOwnerMessagePacket.ParamListBlock();
4745 }
4746 int j = 0;
4747
4748 returnblock[j].Parameter = Utils.StringToBytes(estateID.ToString()); j++;
4749 returnblock[j].Parameter = Utils.StringToBytes(code.ToString()); j++;
4750 returnblock[j].Parameter = Utils.StringToBytes("0"); j++;
4751 returnblock[j].Parameter = Utils.StringToBytes("0"); j++;
4752 returnblock[j].Parameter = Utils.StringToBytes("0"); j++;
4753 returnblock[j].Parameter = Utils.StringToBytes("0"); j++;
4754
4755 j = 2; // Agents
4756 if ((code & 2) != 0)
4757 j = 3; // Groups
4758 if ((code & 8) != 0)
4759 j = 5; // Managers
4760
4761 returnblock[j].Parameter = Utils.StringToBytes(Data.Length.ToString());
4762 j = 6;
4763
4764 for (int i = 0; i < Data.Length; i++)
4765 {
4766 returnblock[j].Parameter = Data[i].GetBytes(); j++;
4767 }
4768 packet.ParamList = returnblock;
4769 packet.Header.Reliable = true;
4770 OutPacket(packet, ThrottleOutPacketType.Task);
4771 }
4772
4773 public void SendBannedUserList(UUID invoice, EstateBan[] bl, uint estateID)
4774 {
4775 List<UUID> BannedUsers = new List<UUID>();
4776
4777 for (int i = 0; i < bl.Length; i++)
4778 {
4779 if (bl[i] == null)
4780 continue;
4781 if (bl[i].BannedUserID == UUID.Zero)
4782 continue;
4783 BannedUsers.Add(bl[i].BannedUserID);
4784
4785 if (BannedUsers.Count >= 50 || (i == (bl.Length - 1) && BannedUsers.Count > 0))
4786 {
4787 EstateOwnerMessagePacket packet = new EstateOwnerMessagePacket();
4788 packet.AgentData.TransactionID = UUID.Random();
4789 packet.AgentData.AgentID = AgentId;
4790 packet.AgentData.SessionID = SessionId;
4791 packet.MethodData.Invoice = invoice;
4792 packet.MethodData.Method = Utils.StringToBytes("setaccess");
4793
4794 EstateOwnerMessagePacket.ParamListBlock[] returnblock = new EstateOwnerMessagePacket.ParamListBlock[6 + BannedUsers.Count];
4795
4796 int j;
4797 for (j = 0; j < (6 + BannedUsers.Count); j++)
4798 {
4799 returnblock[j] = new EstateOwnerMessagePacket.ParamListBlock();
4800 }
4801 j = 0;
4802
4803 returnblock[j].Parameter = Utils.StringToBytes(estateID.ToString()); j++;
4804 returnblock[j].Parameter = Utils.StringToBytes(((int)Constants.EstateAccessCodex.EstateBans).ToString()); j++;
4805 returnblock[j].Parameter = Utils.StringToBytes("0"); j++;
4806 returnblock[j].Parameter = Utils.StringToBytes("0"); j++;
4807 returnblock[j].Parameter = Utils.StringToBytes(BannedUsers.Count.ToString()); j++;
4808 returnblock[j].Parameter = Utils.StringToBytes("0"); j++;
4809
4810 foreach (UUID banned in BannedUsers)
4811 {
4812 returnblock[j].Parameter = banned.GetBytes(); j++;
4813 }
4814 packet.ParamList = returnblock;
4815 packet.Header.Reliable = true;
4816 OutPacket(packet, ThrottleOutPacketType.Task);
4817
4818 BannedUsers.Clear();
4819 }
4820 }
4821
4822 }
4823
4824 public void SendRegionInfoToEstateMenu(RegionInfoForEstateMenuArgs args)
4825 {
4826 RegionInfoPacket rinfopack = new RegionInfoPacket();
4827 RegionInfoPacket.RegionInfoBlock rinfoblk = new RegionInfoPacket.RegionInfoBlock();
4828 rinfopack.AgentData.AgentID = AgentId;
4829 rinfopack.AgentData.SessionID = SessionId;
4830 rinfoblk.BillableFactor = args.billableFactor;
4831 rinfoblk.EstateID = args.estateID;
4832 rinfoblk.MaxAgents = args.maxAgents;
4833 rinfoblk.ObjectBonusFactor = args.objectBonusFactor;
4834 rinfoblk.ParentEstateID = args.parentEstateID;
4835 rinfoblk.PricePerMeter = args.pricePerMeter;
4836 rinfoblk.RedirectGridX = args.redirectGridX;
4837 rinfoblk.RedirectGridY = args.redirectGridY;
4838 rinfoblk.RegionFlags = args.regionFlags;
4839 rinfoblk.SimAccess = args.simAccess;
4840 rinfoblk.SunHour = args.sunHour;
4841 rinfoblk.TerrainLowerLimit = args.terrainLowerLimit;
4842 rinfoblk.TerrainRaiseLimit = args.terrainRaiseLimit;
4843 rinfoblk.UseEstateSun = args.useEstateSun;
4844 rinfoblk.WaterHeight = args.waterHeight;
4845 rinfoblk.SimName = Utils.StringToBytes(args.simName);
4846
4847 rinfopack.RegionInfo2 = new RegionInfoPacket.RegionInfo2Block();
4848 rinfopack.RegionInfo2.HardMaxAgents = uint.MaxValue;
4849 rinfopack.RegionInfo2.HardMaxObjects = uint.MaxValue;
4850 rinfopack.RegionInfo2.MaxAgents32 = uint.MaxValue;
4851 rinfopack.RegionInfo2.ProductName = Util.StringToBytes256(args.regionType);
4852 rinfopack.RegionInfo2.ProductSKU = Utils.EmptyBytes;
4853
4854 rinfopack.HasVariableBlocks = true;
4855 rinfopack.RegionInfo = rinfoblk;
4856 rinfopack.AgentData = new RegionInfoPacket.AgentDataBlock();
4857 rinfopack.AgentData.AgentID = AgentId;
4858 rinfopack.AgentData.SessionID = SessionId;
4859 rinfopack.RegionInfo3 = new RegionInfoPacket.RegionInfo3Block[0];
4860
4861 OutPacket(rinfopack, ThrottleOutPacketType.Task);
4862 }
4863
4864 public void SendEstateCovenantInformation(UUID covenant)
4865 {
4866// m_log.DebugFormat("[LLCLIENTVIEW]: Sending estate covenant asset id of {0} to {1}", covenant, Name);
4867
4868 EstateCovenantReplyPacket einfopack = new EstateCovenantReplyPacket();
4869 EstateCovenantReplyPacket.DataBlock edata = new EstateCovenantReplyPacket.DataBlock();
4870 edata.CovenantID = covenant;
4871 edata.CovenantTimestamp = (uint) m_scene.RegionInfo.RegionSettings.CovenantChangedDateTime;
4872 edata.EstateOwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
4873 edata.EstateName = Utils.StringToBytes(m_scene.RegionInfo.EstateSettings.EstateName);
4874 einfopack.Data = edata;
4875 OutPacket(einfopack, ThrottleOutPacketType.Task);
4876 }
4877
4878 public void SendDetailedEstateData(
4879 UUID invoice, string estateName, uint estateID, uint parentEstate, uint estateFlags, uint sunPosition,
4880 UUID covenant, uint covenantChanged, string abuseEmail, UUID estateOwner)
4881 {
4882// m_log.DebugFormat(
4883// "[LLCLIENTVIEW]: Sending detailed estate data to {0} with covenant asset id {1}", Name, covenant);
4884
4885 EstateOwnerMessagePacket packet = new EstateOwnerMessagePacket();
4886 packet.MethodData.Invoice = invoice;
4887 packet.AgentData.TransactionID = UUID.Random();
4888 packet.MethodData.Method = Utils.StringToBytes("estateupdateinfo");
4889 EstateOwnerMessagePacket.ParamListBlock[] returnblock = new EstateOwnerMessagePacket.ParamListBlock[10];
4890
4891 for (int i = 0; i < 10; i++)
4892 {
4893 returnblock[i] = new EstateOwnerMessagePacket.ParamListBlock();
4894 }
4895
4896 //Sending Estate Settings
4897 returnblock[0].Parameter = Utils.StringToBytes(estateName);
4898 returnblock[1].Parameter = Utils.StringToBytes(estateOwner.ToString());
4899 returnblock[2].Parameter = Utils.StringToBytes(estateID.ToString());
4900
4901 returnblock[3].Parameter = Utils.StringToBytes(estateFlags.ToString());
4902 returnblock[4].Parameter = Utils.StringToBytes(sunPosition.ToString());
4903 returnblock[5].Parameter = Utils.StringToBytes(parentEstate.ToString());
4904 returnblock[6].Parameter = Utils.StringToBytes(covenant.ToString());
4905 returnblock[7].Parameter = Utils.StringToBytes(covenantChanged.ToString());
4906 returnblock[8].Parameter = Utils.StringToBytes("1"); // what is this?
4907 returnblock[9].Parameter = Utils.StringToBytes(abuseEmail);
4908
4909 packet.ParamList = returnblock;
4910 packet.Header.Reliable = false;
4911 //m_log.Debug("[ESTATE]: SIM--->" + packet.ToString());
4912 OutPacket(packet, ThrottleOutPacketType.Task);
4913 }
4914
4915 public void SendTelehubInfo(UUID ObjectID, string ObjectName, Vector3 ObjectPos, Quaternion ObjectRot, List<Vector3> SpawnPoint)
4916 {
4917 TelehubInfoPacket packet = (TelehubInfoPacket)PacketPool.Instance.GetPacket(PacketType.TelehubInfo);
4918 packet.TelehubBlock.ObjectID = ObjectID;
4919 packet.TelehubBlock.ObjectName = Utils.StringToBytes(ObjectName);
4920 packet.TelehubBlock.TelehubPos = ObjectPos;
4921 packet.TelehubBlock.TelehubRot = ObjectRot;
4922
4923 packet.SpawnPointBlock = new TelehubInfoPacket.SpawnPointBlockBlock[SpawnPoint.Count];
4924 for (int n = 0; n < SpawnPoint.Count; n++)
4925 {
4926 packet.SpawnPointBlock[n] = new TelehubInfoPacket.SpawnPointBlockBlock{SpawnPointPos = SpawnPoint[n]};
4927 }
4928
4929 OutPacket(packet, ThrottleOutPacketType.Task);
4930 }
4931
4932 #endregion
4933
4934 #region Land Data Sending Methods
4935
4936 public void SendLandParcelOverlay(byte[] data, int sequence_id)
4937 {
4938 ParcelOverlayPacket packet = (ParcelOverlayPacket)PacketPool.Instance.GetPacket(PacketType.ParcelOverlay);
4939 packet.ParcelData.Data = data;
4940 packet.ParcelData.SequenceID = sequence_id;
4941 packet.Header.Zerocoded = true;
4942 OutPacket(packet, ThrottleOutPacketType.Task);
4943 }
4944
4945 public void SendLandProperties(
4946 int sequence_id, bool snap_selection, int request_result, ILandObject lo,
4947 float simObjectBonusFactor, int parcelObjectCapacity, int simObjectCapacity, uint regionFlags)
4948 {
4949// m_log.DebugFormat("[LLCLIENTVIEW]: Sending land properties for {0} to {1}", lo.LandData.GlobalID, Name);
4950
4951 LandData landData = lo.LandData;
4952
4953 ParcelPropertiesMessage updateMessage = new ParcelPropertiesMessage();
4954
4955 updateMessage.AABBMax = landData.AABBMax;
4956 updateMessage.AABBMin = landData.AABBMin;
4957 updateMessage.Area = landData.Area;
4958 updateMessage.AuctionID = landData.AuctionID;
4959 updateMessage.AuthBuyerID = landData.AuthBuyerID;
4960 updateMessage.Bitmap = landData.Bitmap;
4961 updateMessage.Desc = landData.Description;
4962 updateMessage.Category = landData.Category;
4963 updateMessage.ClaimDate = Util.ToDateTime(landData.ClaimDate);
4964 updateMessage.ClaimPrice = landData.ClaimPrice;
4965 updateMessage.GroupID = landData.GroupID;
4966 updateMessage.IsGroupOwned = landData.IsGroupOwned;
4967 updateMessage.LandingType = (LandingType) landData.LandingType;
4968 updateMessage.LocalID = landData.LocalID;
4969
4970 if (landData.Area > 0)
4971 {
4972 updateMessage.MaxPrims = parcelObjectCapacity;
4973 }
4974 else
4975 {
4976 updateMessage.MaxPrims = 0;
4977 }
4978
4979 updateMessage.MediaAutoScale = Convert.ToBoolean(landData.MediaAutoScale);
4980 updateMessage.MediaID = landData.MediaID;
4981 updateMessage.MediaURL = landData.MediaURL;
4982 updateMessage.MusicURL = landData.MusicURL;
4983 updateMessage.Name = landData.Name;
4984 updateMessage.OtherCleanTime = landData.OtherCleanTime;
4985 updateMessage.OtherCount = 0; //TODO: Unimplemented
4986 updateMessage.OwnerID = landData.OwnerID;
4987 updateMessage.ParcelFlags = (ParcelFlags) landData.Flags;
4988 updateMessage.ParcelPrimBonus = simObjectBonusFactor;
4989 updateMessage.PassHours = landData.PassHours;
4990 updateMessage.PassPrice = landData.PassPrice;
4991 updateMessage.PublicCount = 0; //TODO: Unimplemented
4992
4993 updateMessage.RegionPushOverride = (regionFlags & (uint)RegionFlags.RestrictPushObject) > 0;
4994 updateMessage.RegionDenyAnonymous = (regionFlags & (uint)RegionFlags.DenyAnonymous) > 0;
4995
4996 //updateMessage.RegionDenyIdentified = (regionFlags & (uint)RegionFlags.DenyIdentified) > 0;
4997 //updateMessage.RegionDenyTransacted = (regionFlags & (uint)RegionFlags.DenyTransacted) > 0;
4998
4999 updateMessage.RentPrice = 0;
5000 updateMessage.RequestResult = (ParcelResult) request_result;
5001 updateMessage.SalePrice = landData.SalePrice;
5002 updateMessage.SelfCount = 0; //TODO: Unimplemented
5003 updateMessage.SequenceID = sequence_id;
5004
5005 if (landData.SimwideArea > 0)
5006 {
5007 int simulatorCapacity = (int)(((float)landData.SimwideArea / 65536.0f) * (float)m_scene.RegionInfo.ObjectCapacity * (float)m_scene.RegionInfo.RegionSettings.ObjectBonus);
5008 updateMessage.SimWideMaxPrims = simulatorCapacity;
5009 }
5010 else
5011 {
5012 updateMessage.SimWideMaxPrims = 0;
5013 }
5014
5015 updateMessage.SnapSelection = snap_selection;
5016 updateMessage.SnapshotID = landData.SnapshotID;
5017 updateMessage.Status = (ParcelStatus) landData.Status;
5018 updateMessage.UserLocation = landData.UserLocation;
5019 updateMessage.UserLookAt = landData.UserLookAt;
5020
5021 updateMessage.MediaType = landData.MediaType;
5022 updateMessage.MediaDesc = landData.MediaDescription;
5023 updateMessage.MediaWidth = landData.MediaWidth;
5024 updateMessage.MediaHeight = landData.MediaHeight;
5025 updateMessage.MediaLoop = landData.MediaLoop;
5026 updateMessage.ObscureMusic = landData.ObscureMusic;
5027 updateMessage.ObscureMedia = landData.ObscureMedia;
5028
5029 IPrimCounts pc = lo.PrimCounts;
5030 updateMessage.OwnerPrims = pc.Owner;
5031 updateMessage.GroupPrims = pc.Group;
5032 updateMessage.OtherPrims = pc.Others;
5033 updateMessage.SelectedPrims = pc.Selected;
5034 updateMessage.TotalPrims = pc.Total;
5035 updateMessage.SimWideTotalPrims = pc.Simulator;
5036
5037 try
5038 {
5039 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>();
5040 if (eq != null)
5041 {
5042 eq.ParcelProperties(updateMessage, this.AgentId);
5043 }
5044 else
5045 {
5046 m_log.Warn("[LLCLIENTVIEW]: No EQ Interface when sending parcel data.");
5047 }
5048 }
5049 catch (Exception ex)
5050 {
5051 m_log.Error("[LLCLIENTVIEW]: Unable to send parcel data via eventqueue - exception: " + ex.ToString());
5052 }
5053 }
5054
5055 public void SendLandAccessListData(List<LandAccessEntry> accessList, uint accessFlag, int localLandID)
5056 {
5057 ParcelAccessListReplyPacket replyPacket = (ParcelAccessListReplyPacket)PacketPool.Instance.GetPacket(PacketType.ParcelAccessListReply);
5058 replyPacket.Data.AgentID = AgentId;
5059 replyPacket.Data.Flags = accessFlag;
5060 replyPacket.Data.LocalID = localLandID;
5061 replyPacket.Data.SequenceID = 0;
5062
5063 List<ParcelAccessListReplyPacket.ListBlock> list = new List<ParcelAccessListReplyPacket.ListBlock>();
5064 foreach (LandAccessEntry entry in accessList)
5065 {
5066 ParcelAccessListReplyPacket.ListBlock block = new ParcelAccessListReplyPacket.ListBlock();
5067 block.Flags = accessFlag;
5068 block.ID = entry.AgentID;
5069 block.Time = entry.Expires;
5070 list.Add(block);
5071 }
5072
5073 replyPacket.List = list.ToArray();
5074 replyPacket.Header.Zerocoded = true;
5075 OutPacket(replyPacket, ThrottleOutPacketType.Task);
5076 }
5077
5078 public void SendForceClientSelectObjects(List<uint> ObjectIDs)
5079 {
5080// m_log.DebugFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count);
5081
5082 bool firstCall = true;
5083 const int MAX_OBJECTS_PER_PACKET = 251;
5084 ForceObjectSelectPacket pack = (ForceObjectSelectPacket)PacketPool.Instance.GetPacket(PacketType.ForceObjectSelect);
5085 ForceObjectSelectPacket.DataBlock[] data;
5086 while (ObjectIDs.Count > 0)
5087 {
5088 if (firstCall)
5089 {
5090 pack._Header.ResetList = true;
5091 firstCall = false;
5092 }
5093 else
5094 {
5095 pack._Header.ResetList = false;
5096 }
5097
5098 if (ObjectIDs.Count > MAX_OBJECTS_PER_PACKET)
5099 {
5100 data = new ForceObjectSelectPacket.DataBlock[MAX_OBJECTS_PER_PACKET];
5101 }
5102 else
5103 {
5104 data = new ForceObjectSelectPacket.DataBlock[ObjectIDs.Count];
5105 }
5106
5107 int i;
5108 for (i = 0; i < MAX_OBJECTS_PER_PACKET && ObjectIDs.Count > 0; i++)
5109 {
5110 data[i] = new ForceObjectSelectPacket.DataBlock();
5111 data[i].LocalID = Convert.ToUInt32(ObjectIDs[0]);
5112 ObjectIDs.RemoveAt(0);
5113 }
5114 pack.Data = data;
5115 pack.Header.Zerocoded = true;
5116 OutPacket(pack, ThrottleOutPacketType.Task);
5117 }
5118 }
5119
5120 public void SendCameraConstraint(Vector4 ConstraintPlane)
5121 {
5122 CameraConstraintPacket cpack = (CameraConstraintPacket)PacketPool.Instance.GetPacket(PacketType.CameraConstraint);
5123 cpack.CameraCollidePlane = new CameraConstraintPacket.CameraCollidePlaneBlock();
5124 cpack.CameraCollidePlane.Plane = ConstraintPlane;
5125 //m_log.DebugFormat("[CLIENTVIEW]: Constraint {0}", ConstraintPlane);
5126 OutPacket(cpack, ThrottleOutPacketType.Task);
5127 }
5128
5129 public void SendLandObjectOwners(LandData land, List<UUID> groups, Dictionary<UUID, int> ownersAndCount)
5130 {
5131 int notifyCount = ownersAndCount.Count;
5132 ParcelObjectOwnersReplyPacket pack = (ParcelObjectOwnersReplyPacket)PacketPool.Instance.GetPacket(PacketType.ParcelObjectOwnersReply);
5133
5134 if (notifyCount > 0)
5135 {
5136 if (notifyCount > 32)
5137 {
5138 m_log.InfoFormat(
5139 "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}"
5140 + " - a developer might want to investigate whether this is a hard limit", 32);
5141
5142 notifyCount = 32;
5143 }
5144
5145 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock
5146 = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount];
5147
5148 int num = 0;
5149 foreach (UUID owner in ownersAndCount.Keys)
5150 {
5151 dataBlock[num] = new ParcelObjectOwnersReplyPacket.DataBlock();
5152 dataBlock[num].Count = ownersAndCount[owner];
5153
5154 if (land.GroupID == owner || groups.Contains(owner))
5155 dataBlock[num].IsGroupOwned = true;
5156
5157 dataBlock[num].OnlineStatus = true; //TODO: fix me later
5158 dataBlock[num].OwnerID = owner;
5159
5160 num++;
5161
5162 if (num >= notifyCount)
5163 {
5164 break;
5165 }
5166 }
5167
5168 pack.Data = dataBlock;
5169 }
5170 else
5171 {
5172 pack.Data = new ParcelObjectOwnersReplyPacket.DataBlock[0];
5173 }
5174 pack.Header.Zerocoded = true;
5175 this.OutPacket(pack, ThrottleOutPacketType.Task);
5176 }
5177
5178 #endregion
5179
5180 #region Helper Methods
5181
5182 protected ImprovedTerseObjectUpdatePacket.ObjectDataBlock CreateImprovedTerseBlock(ISceneEntity entity, bool sendTexture)
5183 {
5184 #region ScenePresence/SOP Handling
5185
5186 bool avatar = (entity is ScenePresence);
5187 uint localID = entity.LocalId;
5188 uint attachPoint;
5189 Vector4 collisionPlane;
5190 Vector3 position, velocity, acceleration, angularVelocity;
5191 Quaternion rotation;
5192 byte[] textureEntry;
5193
5194 if (entity is ScenePresence)
5195 {
5196 ScenePresence presence = (ScenePresence)entity;
5197
5198// m_log.DebugFormat(
5199// "[LLCLIENTVIEW]: Sending terse update to {0} with pos {1}, vel {2} in {3}",
5200// Name, presence.OffsetPosition, presence.Velocity, m_scene.Name);
5201
5202 attachPoint = presence.State;
5203 collisionPlane = presence.CollisionPlane;
5204 position = presence.OffsetPosition;
5205 velocity = presence.Velocity;
5206 acceleration = Vector3.Zero;
5207
5208 // Interestingly, sending this to non-zero will cause the client's avatar to start moving & accelerating
5209 // in that direction, even though we don't model this on the server. Implementing this in the future
5210 // may improve movement smoothness.
5211// acceleration = new Vector3(1, 0, 0);
5212
5213 angularVelocity = presence.AngularVelocity;
5214
5215 // Whilst not in mouselook, an avatar will transmit only the Z rotation as this is the only axis
5216 // it rotates around.
5217 // In mouselook, X and Y co-ordinate will also be sent but when used in Rotation, these cause unwanted
5218 // excessive up and down movements of the camera when looking up and down.
5219 // See http://opensimulator.org/mantis/view.php?id=3274
5220 // This does not affect head movement, since this is controlled entirely by camera movement rather than
5221 // body rotation. We still need to transmit X and Y for sitting avatars but mouselook does not change
5222 // the rotation in this case.
5223 rotation = presence.Rotation;
5224
5225 if (!presence.IsSatOnObject)
5226 {
5227 rotation.X = 0;
5228 rotation.Y = 0;
5229 }
5230
5231 if (sendTexture)
5232 textureEntry = presence.Appearance.Texture.GetBytes();
5233 else
5234 textureEntry = null;
5235 }
5236 else
5237 {
5238 SceneObjectPart part = (SceneObjectPart)entity;
5239
5240 attachPoint = part.ParentGroup.AttachmentPoint;
5241 attachPoint = ((attachPoint % 16) * 16 + (attachPoint / 16));
5242// m_log.DebugFormat(
5243// "[LLCLIENTVIEW]: Sending attachPoint {0} for {1} {2} to {3}",
5244// attachPoint, part.Name, part.LocalId, Name);
5245
5246 collisionPlane = Vector4.Zero;
5247 position = part.RelativePosition;
5248 velocity = part.Velocity;
5249 acceleration = part.Acceleration;
5250 angularVelocity = part.AngularVelocity;
5251 rotation = part.RotationOffset;
5252
5253 if (sendTexture)
5254 textureEntry = part.Shape.TextureEntry;
5255 else
5256 textureEntry = null;
5257 }
5258
5259 #endregion ScenePresence/SOP Handling
5260
5261 int pos = 0;
5262 byte[] data = new byte[(avatar ? 60 : 44)];
5263
5264 // LocalID
5265 Utils.UIntToBytes(localID, data, pos);
5266 pos += 4;
5267
5268 // Avatar/CollisionPlane
5269 data[pos++] = (byte) attachPoint;
5270 if (avatar)
5271 {
5272 data[pos++] = 1;
5273
5274 if (collisionPlane == Vector4.Zero)
5275 collisionPlane = Vector4.UnitW;
5276 //m_log.DebugFormat("CollisionPlane: {0}",collisionPlane);
5277 collisionPlane.ToBytes(data, pos);
5278 pos += 16;
5279 }
5280 else
5281 {
5282 ++pos;
5283 }
5284
5285 // Position
5286 position.ToBytes(data, pos);
5287 pos += 12;
5288
5289 // Velocity
5290 Utils.UInt16ToBytes(Utils.FloatToUInt16(velocity.X, -128.0f, 128.0f), data, pos); pos += 2;
5291 Utils.UInt16ToBytes(Utils.FloatToUInt16(velocity.Y, -128.0f, 128.0f), data, pos); pos += 2;
5292 Utils.UInt16ToBytes(Utils.FloatToUInt16(velocity.Z, -128.0f, 128.0f), data, pos); pos += 2;
5293
5294 // Acceleration
5295 Utils.UInt16ToBytes(Utils.FloatToUInt16(acceleration.X, -64.0f, 64.0f), data, pos); pos += 2;
5296 Utils.UInt16ToBytes(Utils.FloatToUInt16(acceleration.Y, -64.0f, 64.0f), data, pos); pos += 2;
5297 Utils.UInt16ToBytes(Utils.FloatToUInt16(acceleration.Z, -64.0f, 64.0f), data, pos); pos += 2;
5298
5299 // Rotation
5300 Utils.UInt16ToBytes(Utils.FloatToUInt16(rotation.X, -1.0f, 1.0f), data, pos); pos += 2;
5301 Utils.UInt16ToBytes(Utils.FloatToUInt16(rotation.Y, -1.0f, 1.0f), data, pos); pos += 2;
5302 Utils.UInt16ToBytes(Utils.FloatToUInt16(rotation.Z, -1.0f, 1.0f), data, pos); pos += 2;
5303 Utils.UInt16ToBytes(Utils.FloatToUInt16(rotation.W, -1.0f, 1.0f), data, pos); pos += 2;
5304
5305 // Angular Velocity
5306 Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.X, -64.0f, 64.0f), data, pos); pos += 2;
5307 Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Y, -64.0f, 64.0f), data, pos); pos += 2;
5308 Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Z, -64.0f, 64.0f), data, pos); pos += 2;
5309
5310 ImprovedTerseObjectUpdatePacket.ObjectDataBlock block
5311 = PacketPool.Instance.GetDataBlock<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>();
5312
5313 block.Data = data;
5314
5315 if (textureEntry != null && textureEntry.Length > 0)
5316 {
5317 byte[] teBytesFinal = new byte[textureEntry.Length + 4];
5318
5319 // Texture Length
5320 Utils.IntToBytes(textureEntry.Length, textureEntry, 0);
5321 // Texture
5322 Buffer.BlockCopy(textureEntry, 0, teBytesFinal, 4, textureEntry.Length);
5323
5324 block.TextureEntry = teBytesFinal;
5325 }
5326 else
5327 {
5328 block.TextureEntry = Utils.EmptyBytes;
5329 }
5330
5331 return block;
5332 }
5333
5334 protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(ScenePresence data)
5335 {
5336// m_log.DebugFormat(
5337// "[LLCLIENTVIEW]: Sending full update to {0} with pos {1}, vel {2} in {3}", Name, data.OffsetPosition, data.Velocity, m_scene.Name);
5338
5339 byte[] objectData = new byte[76];
5340
5341 data.CollisionPlane.ToBytes(objectData, 0);
5342 data.OffsetPosition.ToBytes(objectData, 16);
5343 data.Velocity.ToBytes(objectData, 28);
5344// data.Acceleration.ToBytes(objectData, 40);
5345
5346 // Whilst not in mouselook, an avatar will transmit only the Z rotation as this is the only axis
5347 // it rotates around.
5348 // In mouselook, X and Y co-ordinate will also be sent but when used in Rotation, these cause unwanted
5349 // excessive up and down movements of the camera when looking up and down.
5350 // See http://opensimulator.org/mantis/view.php?id=3274
5351 // This does not affect head movement, since this is controlled entirely by camera movement rather than
5352 // body rotation. We still need to transmit X and Y for sitting avatars but mouselook does not change
5353 // the rotation in this case.
5354 Quaternion rot = data.Rotation;
5355
5356 if (!data.IsSatOnObject)
5357 {
5358 rot.X = 0;
5359 rot.Y = 0;
5360 }
5361
5362 rot.ToBytes(objectData, 52);
5363 //data.AngularVelocity.ToBytes(objectData, 64);
5364
5365 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock();
5366
5367 update.Data = Utils.EmptyBytes;
5368 update.ExtraParams = new byte[1];
5369 update.FullID = data.UUID;
5370 update.ID = data.LocalId;
5371 update.Material = (byte)Material.Flesh;
5372 update.MediaURL = Utils.EmptyBytes;
5373 update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " +
5374 data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle);
5375 update.ObjectData = objectData;
5376
5377 SceneObjectPart parentPart = data.ParentPart;
5378 if (parentPart != null)
5379 update.ParentID = parentPart.ParentGroup.LocalId;
5380 else
5381 update.ParentID = 0;
5382
5383 update.PathCurve = 16;
5384 update.PathScaleX = 100;
5385 update.PathScaleY = 100;
5386 update.PCode = (byte)PCode.Avatar;
5387 update.ProfileCurve = 1;
5388 update.PSBlock = Utils.EmptyBytes;
5389 update.Scale = new Vector3(0.45f, 0.6f, 1.9f);
5390 update.Text = Utils.EmptyBytes;
5391 update.TextColor = new byte[4];
5392
5393 // Don't send texture anim for avatars - this has no meaning for them.
5394 update.TextureAnim = Utils.EmptyBytes;
5395
5396 // Don't send texture entry for avatars here - this is accomplished via the AvatarAppearance packet
5397 update.TextureEntry = Utils.EmptyBytes;
5398// update.TextureEntry = (data.Appearance.Texture != null) ? data.Appearance.Texture.GetBytes() : Utils.EmptyBytes;
5399
5400 update.UpdateFlags = (uint)(
5401 PrimFlags.Physics | PrimFlags.ObjectModify | PrimFlags.ObjectCopy | PrimFlags.ObjectAnyOwner |
5402 PrimFlags.ObjectYouOwner | PrimFlags.ObjectMove | PrimFlags.InventoryEmpty | PrimFlags.ObjectTransfer |
5403 PrimFlags.ObjectOwnerModify);
5404
5405 return update;
5406 }
5407
5408 protected ObjectUpdatePacket.ObjectDataBlock CreatePrimUpdateBlock(SceneObjectPart data, UUID recipientID)
5409 {
5410 byte[] objectData = new byte[60];
5411 data.RelativePosition.ToBytes(objectData, 0);
5412 data.Velocity.ToBytes(objectData, 12);
5413 data.Acceleration.ToBytes(objectData, 24);
5414 try
5415 {
5416 data.RotationOffset.ToBytes(objectData, 36);
5417 }
5418 catch (Exception e)
5419 {
5420 m_log.Warn("[LLClientView]: exception converting quaternion to bytes, using Quaternion.Identity. Exception: " + e.ToString());
5421 OpenMetaverse.Quaternion.Identity.ToBytes(objectData, 36);
5422 }
5423 data.AngularVelocity.ToBytes(objectData, 48);
5424
5425 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock();
5426 update.ClickAction = (byte)data.ClickAction;
5427 update.CRC = 0;
5428 update.ExtraParams = data.Shape.ExtraParams ?? Utils.EmptyBytes;
5429 update.FullID = data.UUID;
5430 update.ID = data.LocalId;
5431 //update.JointAxisOrAnchor = Vector3.Zero; // These are deprecated
5432 //update.JointPivot = Vector3.Zero;
5433 //update.JointType = 0;
5434 update.Material = data.Material;
5435 update.MediaURL = Utils.EmptyBytes; // FIXME: Support this in OpenSim
5436
5437 if (data.ParentGroup.IsAttachment)
5438 {
5439 update.NameValue
5440 = Util.StringToBytes256(
5441 string.Format("AttachItemID STRING RW SV {0}", data.ParentGroup.FromItemID));
5442
5443 update.State = (byte)((data.ParentGroup.AttachmentPoint % 16) * 16 + (data.ParentGroup.AttachmentPoint / 16));
5444
5445// m_log.DebugFormat(
5446// "[LLCLIENTVIEW]: Sending NameValue {0} for {1} {2} to {3}",
5447// Util.UTF8.GetString(update.NameValue), data.Name, data.LocalId, Name);
5448//
5449// m_log.DebugFormat(
5450// "[LLCLIENTVIEW]: Sending state {0} for {1} {2} to {3}",
5451// update.State, data.Name, data.LocalId, Name);
5452 }
5453 else
5454 {
5455 update.NameValue = Utils.EmptyBytes;
5456
5457 // The root part state is the canonical state for all parts of the object. The other part states in the
5458 // case for attachments may contain conflicting values that can end up crashing the viewer.
5459 update.State = data.ParentGroup.RootPart.Shape.State;
5460 }
5461
5462 update.ObjectData = objectData;
5463 update.ParentID = data.ParentID;
5464 update.PathBegin = data.Shape.PathBegin;
5465 update.PathCurve = data.Shape.PathCurve;
5466 update.PathEnd = data.Shape.PathEnd;
5467 update.PathRadiusOffset = data.Shape.PathRadiusOffset;
5468 update.PathRevolutions = data.Shape.PathRevolutions;
5469 update.PathScaleX = data.Shape.PathScaleX;
5470 update.PathScaleY = data.Shape.PathScaleY;
5471 update.PathShearX = data.Shape.PathShearX;
5472 update.PathShearY = data.Shape.PathShearY;
5473 update.PathSkew = data.Shape.PathSkew;
5474 update.PathTaperX = data.Shape.PathTaperX;
5475 update.PathTaperY = data.Shape.PathTaperY;
5476 update.PathTwist = data.Shape.PathTwist;
5477 update.PathTwistBegin = data.Shape.PathTwistBegin;
5478 update.PCode = data.Shape.PCode;
5479 update.ProfileBegin = data.Shape.ProfileBegin;
5480 update.ProfileCurve = data.Shape.ProfileCurve;
5481 update.ProfileEnd = data.Shape.ProfileEnd;
5482 update.ProfileHollow = data.Shape.ProfileHollow;
5483 update.PSBlock = data.ParticleSystem ?? Utils.EmptyBytes;
5484 update.TextColor = data.GetTextColor().GetBytes(false);
5485 update.TextureAnim = data.TextureAnimation ?? Utils.EmptyBytes;
5486 update.TextureEntry = data.Shape.TextureEntry ?? Utils.EmptyBytes;
5487 update.Scale = data.Shape.Scale;
5488 update.Text = Util.StringToBytes256(data.Text);
5489 update.MediaURL = Util.StringToBytes256(data.MediaUrl);
5490
5491 #region PrimFlags
5492
5493 PrimFlags flags = (PrimFlags)m_scene.Permissions.GenerateClientFlags(recipientID, data.UUID);
5494
5495 // Don't send the CreateSelected flag to everyone
5496 flags &= ~PrimFlags.CreateSelected;
5497
5498 if (recipientID == data.OwnerID)
5499 {
5500 if (data.CreateSelected)
5501 {
5502 // Only send this flag once, then unset it
5503 flags |= PrimFlags.CreateSelected;
5504 data.CreateSelected = false;
5505 }
5506 }
5507
5508// m_log.DebugFormat(
5509// "[LLCLIENTVIEW]: Constructing client update for part {0} {1} with flags {2}, localId {3}",
5510// data.Name, update.FullID, flags, update.ID);
5511
5512 update.UpdateFlags = (uint)flags;
5513
5514 #endregion PrimFlags
5515
5516 if (data.Sound != UUID.Zero)
5517 {
5518 update.Sound = data.Sound;
5519 update.OwnerID = data.OwnerID;
5520 update.Gain = (float)data.SoundGain;
5521 update.Radius = (float)data.SoundRadius;
5522 update.Flags = data.SoundFlags;
5523 }
5524
5525 switch ((PCode)data.Shape.PCode)
5526 {
5527 case PCode.Grass:
5528 case PCode.Tree:
5529 case PCode.NewTree:
5530 update.Data = new byte[] { data.Shape.State };
5531 break;
5532 default:
5533 update.Data = Utils.EmptyBytes;
5534 break;
5535 }
5536
5537 return update;
5538 }
5539
5540 protected ObjectUpdateCompressedPacket.ObjectDataBlock CreateCompressedUpdateBlock(SceneObjectPart part, PrimUpdateFlags updateFlags)
5541 {
5542 // TODO: Implement this
5543 return null;
5544 }
5545
5546 public void SendNameReply(UUID profileId, string firstname, string lastname)
5547 {
5548 UUIDNameReplyPacket packet = (UUIDNameReplyPacket)PacketPool.Instance.GetPacket(PacketType.UUIDNameReply);
5549 // TODO: don't create new blocks if recycling an old packet
5550 packet.UUIDNameBlock = new UUIDNameReplyPacket.UUIDNameBlockBlock[1];
5551 packet.UUIDNameBlock[0] = new UUIDNameReplyPacket.UUIDNameBlockBlock();
5552 packet.UUIDNameBlock[0].ID = profileId;
5553 packet.UUIDNameBlock[0].FirstName = Util.StringToBytes256(firstname);
5554 packet.UUIDNameBlock[0].LastName = Util.StringToBytes256(lastname);
5555
5556 OutPacket(packet, ThrottleOutPacketType.Task);
5557 }
5558
5559 public ulong GetGroupPowers(UUID groupID)
5560 {
5561 if (groupID == ActiveGroupId)
5562 return ActiveGroupPowers;
5563
5564 if (m_groupPowers.ContainsKey(groupID))
5565 return m_groupPowers[groupID];
5566
5567 return 0;
5568 }
5569
5570 #endregion
5571
5572 /// <summary>
5573 /// This is a different way of processing packets then ProcessInPacket
5574 /// </summary>
5575 protected virtual void RegisterLocalPacketHandlers()
5576 {
5577 AddLocalPacketHandler(PacketType.LogoutRequest, HandleLogout);
5578
5579 // If AgentUpdate is ever handled asynchronously, then we will also need to construct a new AgentUpdateArgs
5580 // for each AgentUpdate packet.
5581 AddLocalPacketHandler(PacketType.AgentUpdate, HandleAgentUpdate, false);
5582
5583 AddLocalPacketHandler(PacketType.ViewerEffect, HandleViewerEffect, false);
5584 AddLocalPacketHandler(PacketType.AgentCachedTexture, HandleAgentTextureCached, false);
5585 AddLocalPacketHandler(PacketType.MultipleObjectUpdate, HandleMultipleObjUpdate, false);
5586 AddLocalPacketHandler(PacketType.MoneyTransferRequest, HandleMoneyTransferRequest, false);
5587 AddLocalPacketHandler(PacketType.ParcelBuy, HandleParcelBuyRequest, false);
5588 AddLocalPacketHandler(PacketType.UUIDGroupNameRequest, HandleUUIDGroupNameRequest);
5589 AddLocalPacketHandler(PacketType.ObjectGroup, HandleObjectGroupRequest);
5590 AddLocalPacketHandler(PacketType.GenericMessage, HandleGenericMessage, true, true);
5591 AddLocalPacketHandler(PacketType.AvatarPropertiesRequest, HandleAvatarPropertiesRequest, true, true);
5592 AddLocalPacketHandler(PacketType.ChatFromViewer, HandleChatFromViewer);
5593 AddLocalPacketHandler(PacketType.AvatarPropertiesUpdate, HandlerAvatarPropertiesUpdate, true, true);
5594 AddLocalPacketHandler(PacketType.ScriptDialogReply, HandlerScriptDialogReply);
5595 AddLocalPacketHandler(PacketType.ImprovedInstantMessage, HandlerImprovedInstantMessage);
5596 AddLocalPacketHandler(PacketType.AcceptFriendship, HandlerAcceptFriendship);
5597 AddLocalPacketHandler(PacketType.DeclineFriendship, HandlerDeclineFriendship);
5598 AddLocalPacketHandler(PacketType.TerminateFriendship, HandlerTerminateFriendship);
5599 AddLocalPacketHandler(PacketType.RezObject, HandlerRezObject);
5600 AddLocalPacketHandler(PacketType.DeRezObject, HandlerDeRezObject);
5601 AddLocalPacketHandler(PacketType.ModifyLand, HandlerModifyLand);
5602 AddLocalPacketHandler(PacketType.RegionHandshakeReply, HandlerRegionHandshakeReply, false);
5603 AddLocalPacketHandler(PacketType.AgentWearablesRequest, HandlerAgentWearablesRequest);
5604 AddLocalPacketHandler(PacketType.AgentSetAppearance, HandlerAgentSetAppearance);
5605 AddLocalPacketHandler(PacketType.AgentIsNowWearing, HandlerAgentIsNowWearing);
5606 AddLocalPacketHandler(PacketType.RezSingleAttachmentFromInv, HandlerRezSingleAttachmentFromInv);
5607 AddLocalPacketHandler(PacketType.RezMultipleAttachmentsFromInv, HandleRezMultipleAttachmentsFromInv);
5608 AddLocalPacketHandler(PacketType.DetachAttachmentIntoInv, HandleDetachAttachmentIntoInv);
5609 AddLocalPacketHandler(PacketType.ObjectAttach, HandleObjectAttach);
5610 AddLocalPacketHandler(PacketType.ObjectDetach, HandleObjectDetach);
5611 AddLocalPacketHandler(PacketType.ObjectDrop, HandleObjectDrop);
5612 AddLocalPacketHandler(PacketType.SetAlwaysRun, HandleSetAlwaysRun, false);
5613 AddLocalPacketHandler(PacketType.CompleteAgentMovement, HandleCompleteAgentMovement);
5614 AddLocalPacketHandler(PacketType.AgentAnimation, HandleAgentAnimation, false);
5615 AddLocalPacketHandler(PacketType.AgentRequestSit, HandleAgentRequestSit);
5616 AddLocalPacketHandler(PacketType.AgentSit, HandleAgentSit);
5617 AddLocalPacketHandler(PacketType.SoundTrigger, HandleSoundTrigger);
5618 AddLocalPacketHandler(PacketType.AvatarPickerRequest, HandleAvatarPickerRequest);
5619 AddLocalPacketHandler(PacketType.AgentDataUpdateRequest, HandleAgentDataUpdateRequest);
5620 AddLocalPacketHandler(PacketType.UserInfoRequest, HandleUserInfoRequest);
5621 AddLocalPacketHandler(PacketType.UpdateUserInfo, HandleUpdateUserInfo);
5622 AddLocalPacketHandler(PacketType.SetStartLocationRequest, HandleSetStartLocationRequest);
5623 AddLocalPacketHandler(PacketType.AgentThrottle, HandleAgentThrottle, false);
5624 AddLocalPacketHandler(PacketType.AgentPause, HandleAgentPause, false);
5625 AddLocalPacketHandler(PacketType.AgentResume, HandleAgentResume, false);
5626 AddLocalPacketHandler(PacketType.ForceScriptControlRelease, HandleForceScriptControlRelease);
5627 AddLocalPacketHandler(PacketType.ObjectLink, HandleObjectLink);
5628 AddLocalPacketHandler(PacketType.ObjectDelink, HandleObjectDelink);
5629 AddLocalPacketHandler(PacketType.ObjectAdd, HandleObjectAdd);
5630 AddLocalPacketHandler(PacketType.ObjectShape, HandleObjectShape);
5631 AddLocalPacketHandler(PacketType.ObjectExtraParams, HandleObjectExtraParams);
5632 AddLocalPacketHandler(PacketType.ObjectDuplicate, HandleObjectDuplicate);
5633 AddLocalPacketHandler(PacketType.RequestMultipleObjects, HandleRequestMultipleObjects);
5634 AddLocalPacketHandler(PacketType.ObjectSelect, HandleObjectSelect);
5635 AddLocalPacketHandler(PacketType.ObjectDeselect, HandleObjectDeselect);
5636 AddLocalPacketHandler(PacketType.ObjectPosition, HandleObjectPosition);
5637 AddLocalPacketHandler(PacketType.ObjectScale, HandleObjectScale);
5638 AddLocalPacketHandler(PacketType.ObjectRotation, HandleObjectRotation);
5639 AddLocalPacketHandler(PacketType.ObjectFlagUpdate, HandleObjectFlagUpdate);
5640
5641 // Handle ObjectImage (TextureEntry) updates synchronously, since when updating multiple prim faces at once,
5642 // some clients will send out a separate ObjectImage packet for each face
5643 AddLocalPacketHandler(PacketType.ObjectImage, HandleObjectImage, false);
5644
5645 AddLocalPacketHandler(PacketType.ObjectGrab, HandleObjectGrab, false);
5646 AddLocalPacketHandler(PacketType.ObjectGrabUpdate, HandleObjectGrabUpdate, false);
5647 AddLocalPacketHandler(PacketType.ObjectDeGrab, HandleObjectDeGrab);
5648 AddLocalPacketHandler(PacketType.ObjectSpinStart, HandleObjectSpinStart, false);
5649 AddLocalPacketHandler(PacketType.ObjectSpinUpdate, HandleObjectSpinUpdate, false);
5650 AddLocalPacketHandler(PacketType.ObjectSpinStop, HandleObjectSpinStop, false);
5651 AddLocalPacketHandler(PacketType.ObjectDescription, HandleObjectDescription, false);
5652 AddLocalPacketHandler(PacketType.ObjectName, HandleObjectName, false);
5653 AddLocalPacketHandler(PacketType.ObjectPermissions, HandleObjectPermissions, false);
5654 AddLocalPacketHandler(PacketType.Undo, HandleUndo, false);
5655 AddLocalPacketHandler(PacketType.UndoLand, HandleLandUndo, false);
5656 AddLocalPacketHandler(PacketType.Redo, HandleRedo, false);
5657 AddLocalPacketHandler(PacketType.ObjectDuplicateOnRay, HandleObjectDuplicateOnRay);
5658 AddLocalPacketHandler(PacketType.RequestObjectPropertiesFamily, HandleRequestObjectPropertiesFamily, false);
5659 AddLocalPacketHandler(PacketType.ObjectIncludeInSearch, HandleObjectIncludeInSearch);
5660 AddLocalPacketHandler(PacketType.ScriptAnswerYes, HandleScriptAnswerYes, false);
5661 AddLocalPacketHandler(PacketType.ObjectClickAction, HandleObjectClickAction, false);
5662 AddLocalPacketHandler(PacketType.ObjectMaterial, HandleObjectMaterial, false);
5663 AddLocalPacketHandler(PacketType.RequestImage, HandleRequestImage, false);
5664 AddLocalPacketHandler(PacketType.TransferRequest, HandleTransferRequest, false);
5665 AddLocalPacketHandler(PacketType.AssetUploadRequest, HandleAssetUploadRequest);
5666 AddLocalPacketHandler(PacketType.RequestXfer, HandleRequestXfer);
5667 AddLocalPacketHandler(PacketType.SendXferPacket, HandleSendXferPacket);
5668 AddLocalPacketHandler(PacketType.ConfirmXferPacket, HandleConfirmXferPacket);
5669 AddLocalPacketHandler(PacketType.AbortXfer, HandleAbortXfer);
5670 AddLocalPacketHandler(PacketType.CreateInventoryFolder, HandleCreateInventoryFolder);
5671 AddLocalPacketHandler(PacketType.UpdateInventoryFolder, HandleUpdateInventoryFolder);
5672 AddLocalPacketHandler(PacketType.MoveInventoryFolder, HandleMoveInventoryFolder);
5673 AddLocalPacketHandler(PacketType.CreateInventoryItem, HandleCreateInventoryItem);
5674 AddLocalPacketHandler(PacketType.LinkInventoryItem, HandleLinkInventoryItem);
5675 AddLocalPacketHandler(PacketType.FetchInventory, HandleFetchInventory);
5676 AddLocalPacketHandler(PacketType.FetchInventoryDescendents, HandleFetchInventoryDescendents);
5677 AddLocalPacketHandler(PacketType.PurgeInventoryDescendents, HandlePurgeInventoryDescendents);
5678 AddLocalPacketHandler(PacketType.UpdateInventoryItem, HandleUpdateInventoryItem);
5679 AddLocalPacketHandler(PacketType.CopyInventoryItem, HandleCopyInventoryItem);
5680 AddLocalPacketHandler(PacketType.MoveInventoryItem, HandleMoveInventoryItem);
5681 AddLocalPacketHandler(PacketType.RemoveInventoryItem, HandleRemoveInventoryItem);
5682 AddLocalPacketHandler(PacketType.RemoveInventoryFolder, HandleRemoveInventoryFolder);
5683 AddLocalPacketHandler(PacketType.RemoveInventoryObjects, HandleRemoveInventoryObjects);
5684 AddLocalPacketHandler(PacketType.RequestTaskInventory, HandleRequestTaskInventory);
5685 AddLocalPacketHandler(PacketType.UpdateTaskInventory, HandleUpdateTaskInventory);
5686 AddLocalPacketHandler(PacketType.RemoveTaskInventory, HandleRemoveTaskInventory);
5687 AddLocalPacketHandler(PacketType.MoveTaskInventory, HandleMoveTaskInventory);
5688 AddLocalPacketHandler(PacketType.RezScript, HandleRezScript);
5689 AddLocalPacketHandler(PacketType.MapLayerRequest, HandleMapLayerRequest);
5690 AddLocalPacketHandler(PacketType.MapBlockRequest, HandleMapBlockRequest);
5691 AddLocalPacketHandler(PacketType.MapNameRequest, HandleMapNameRequest);
5692 AddLocalPacketHandler(PacketType.TeleportLandmarkRequest, HandleTeleportLandmarkRequest);
5693 AddLocalPacketHandler(PacketType.TeleportCancel, HandleTeleportCancel);
5694 AddLocalPacketHandler(PacketType.TeleportLocationRequest, HandleTeleportLocationRequest);
5695 AddLocalPacketHandler(PacketType.UUIDNameRequest, HandleUUIDNameRequest, false);
5696 AddLocalPacketHandler(PacketType.RegionHandleRequest, HandleRegionHandleRequest, false);
5697 AddLocalPacketHandler(PacketType.ParcelInfoRequest, HandleParcelInfoRequest);
5698 AddLocalPacketHandler(PacketType.ParcelAccessListRequest, HandleParcelAccessListRequest, false);
5699 AddLocalPacketHandler(PacketType.ParcelAccessListUpdate, HandleParcelAccessListUpdate, false);
5700 AddLocalPacketHandler(PacketType.ParcelPropertiesRequest, HandleParcelPropertiesRequest, false);
5701 AddLocalPacketHandler(PacketType.ParcelDivide, HandleParcelDivide);
5702 AddLocalPacketHandler(PacketType.ParcelJoin, HandleParcelJoin);
5703 AddLocalPacketHandler(PacketType.ParcelPropertiesUpdate, HandleParcelPropertiesUpdate);
5704 AddLocalPacketHandler(PacketType.ParcelSelectObjects, HandleParcelSelectObjects);
5705 AddLocalPacketHandler(PacketType.ParcelObjectOwnersRequest, HandleParcelObjectOwnersRequest);
5706 AddLocalPacketHandler(PacketType.ParcelGodForceOwner, HandleParcelGodForceOwner);
5707 AddLocalPacketHandler(PacketType.ParcelRelease, HandleParcelRelease);
5708 AddLocalPacketHandler(PacketType.ParcelReclaim, HandleParcelReclaim);
5709 AddLocalPacketHandler(PacketType.ParcelReturnObjects, HandleParcelReturnObjects);
5710 AddLocalPacketHandler(PacketType.ParcelSetOtherCleanTime, HandleParcelSetOtherCleanTime);
5711 AddLocalPacketHandler(PacketType.LandStatRequest, HandleLandStatRequest);
5712 AddLocalPacketHandler(PacketType.ParcelDwellRequest, HandleParcelDwellRequest);
5713 AddLocalPacketHandler(PacketType.EstateOwnerMessage, HandleEstateOwnerMessage);
5714 AddLocalPacketHandler(PacketType.RequestRegionInfo, HandleRequestRegionInfo, false);
5715 AddLocalPacketHandler(PacketType.EstateCovenantRequest, HandleEstateCovenantRequest);
5716 AddLocalPacketHandler(PacketType.RequestGodlikePowers, HandleRequestGodlikePowers);
5717 AddLocalPacketHandler(PacketType.GodKickUser, HandleGodKickUser);
5718 AddLocalPacketHandler(PacketType.MoneyBalanceRequest, HandleMoneyBalanceRequest);
5719 AddLocalPacketHandler(PacketType.EconomyDataRequest, HandleEconomyDataRequest);
5720 AddLocalPacketHandler(PacketType.RequestPayPrice, HandleRequestPayPrice);
5721 AddLocalPacketHandler(PacketType.ObjectSaleInfo, HandleObjectSaleInfo);
5722 AddLocalPacketHandler(PacketType.ObjectBuy, HandleObjectBuy);
5723 AddLocalPacketHandler(PacketType.GetScriptRunning, HandleGetScriptRunning);
5724 AddLocalPacketHandler(PacketType.SetScriptRunning, HandleSetScriptRunning);
5725 AddLocalPacketHandler(PacketType.ScriptReset, HandleScriptReset);
5726 AddLocalPacketHandler(PacketType.ActivateGestures, HandleActivateGestures);
5727 AddLocalPacketHandler(PacketType.DeactivateGestures, HandleDeactivateGestures);
5728 AddLocalPacketHandler(PacketType.ObjectOwner, HandleObjectOwner);
5729 AddLocalPacketHandler(PacketType.AgentFOV, HandleAgentFOV, false);
5730 AddLocalPacketHandler(PacketType.ViewerStats, HandleViewerStats);
5731 AddLocalPacketHandler(PacketType.MapItemRequest, HandleMapItemRequest, false);
5732 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false);
5733 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false);
5734 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode);
5735 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false);
5736 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents);
5737 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery);
5738 AddLocalPacketHandler(PacketType.DirFindQuery, HandleDirFindQuery);
5739 AddLocalPacketHandler(PacketType.DirLandQuery, HandleDirLandQuery);
5740 AddLocalPacketHandler(PacketType.DirPopularQuery, HandleDirPopularQuery);
5741 AddLocalPacketHandler(PacketType.DirClassifiedQuery, HandleDirClassifiedQuery);
5742 AddLocalPacketHandler(PacketType.EventInfoRequest, HandleEventInfoRequest);
5743 AddLocalPacketHandler(PacketType.OfferCallingCard, HandleOfferCallingCard);
5744 AddLocalPacketHandler(PacketType.AcceptCallingCard, HandleAcceptCallingCard);
5745 AddLocalPacketHandler(PacketType.DeclineCallingCard, HandleDeclineCallingCard);
5746 AddLocalPacketHandler(PacketType.ActivateGroup, HandleActivateGroup);
5747 AddLocalPacketHandler(PacketType.GroupTitlesRequest, HandleGroupTitlesRequest);
5748 AddLocalPacketHandler(PacketType.GroupProfileRequest, HandleGroupProfileRequest);
5749 AddLocalPacketHandler(PacketType.GroupMembersRequest, HandleGroupMembersRequest);
5750 AddLocalPacketHandler(PacketType.GroupRoleDataRequest, HandleGroupRoleDataRequest);
5751 AddLocalPacketHandler(PacketType.GroupRoleMembersRequest, HandleGroupRoleMembersRequest);
5752 AddLocalPacketHandler(PacketType.CreateGroupRequest, HandleCreateGroupRequest);
5753 AddLocalPacketHandler(PacketType.UpdateGroupInfo, HandleUpdateGroupInfo);
5754 AddLocalPacketHandler(PacketType.SetGroupAcceptNotices, HandleSetGroupAcceptNotices);
5755 AddLocalPacketHandler(PacketType.GroupTitleUpdate, HandleGroupTitleUpdate);
5756 AddLocalPacketHandler(PacketType.ParcelDeedToGroup, HandleParcelDeedToGroup);
5757 AddLocalPacketHandler(PacketType.GroupNoticesListRequest, HandleGroupNoticesListRequest);
5758 AddLocalPacketHandler(PacketType.GroupNoticeRequest, HandleGroupNoticeRequest);
5759 AddLocalPacketHandler(PacketType.GroupRoleUpdate, HandleGroupRoleUpdate);
5760 AddLocalPacketHandler(PacketType.GroupRoleChanges, HandleGroupRoleChanges);
5761 AddLocalPacketHandler(PacketType.JoinGroupRequest, HandleJoinGroupRequest);
5762 AddLocalPacketHandler(PacketType.LeaveGroupRequest, HandleLeaveGroupRequest);
5763 AddLocalPacketHandler(PacketType.EjectGroupMemberRequest, HandleEjectGroupMemberRequest);
5764 AddLocalPacketHandler(PacketType.InviteGroupRequest, HandleInviteGroupRequest);
5765 AddLocalPacketHandler(PacketType.StartLure, HandleStartLure);
5766 AddLocalPacketHandler(PacketType.TeleportLureRequest, HandleTeleportLureRequest);
5767 AddLocalPacketHandler(PacketType.ClassifiedInfoRequest, HandleClassifiedInfoRequest);
5768 AddLocalPacketHandler(PacketType.ClassifiedInfoUpdate, HandleClassifiedInfoUpdate);
5769 AddLocalPacketHandler(PacketType.ClassifiedDelete, HandleClassifiedDelete);
5770 AddLocalPacketHandler(PacketType.ClassifiedGodDelete, HandleClassifiedGodDelete);
5771 AddLocalPacketHandler(PacketType.EventGodDelete, HandleEventGodDelete);
5772 AddLocalPacketHandler(PacketType.EventNotificationAddRequest, HandleEventNotificationAddRequest);
5773 AddLocalPacketHandler(PacketType.EventNotificationRemoveRequest, HandleEventNotificationRemoveRequest);
5774 AddLocalPacketHandler(PacketType.RetrieveInstantMessages, HandleRetrieveInstantMessages);
5775 AddLocalPacketHandler(PacketType.PickDelete, HandlePickDelete);
5776 AddLocalPacketHandler(PacketType.PickGodDelete, HandlePickGodDelete);
5777 AddLocalPacketHandler(PacketType.PickInfoUpdate, HandlePickInfoUpdate);
5778 AddLocalPacketHandler(PacketType.AvatarNotesUpdate, HandleAvatarNotesUpdate, true, true);
5779 AddLocalPacketHandler(PacketType.AvatarInterestsUpdate, HandleAvatarInterestsUpdate, true, true);
5780 AddLocalPacketHandler(PacketType.GrantUserRights, HandleGrantUserRights);
5781 AddLocalPacketHandler(PacketType.PlacesQuery, HandlePlacesQuery);
5782 AddLocalPacketHandler(PacketType.UpdateMuteListEntry, HandleUpdateMuteListEntry);
5783 AddLocalPacketHandler(PacketType.RemoveMuteListEntry, HandleRemoveMuteListEntry);
5784 AddLocalPacketHandler(PacketType.UserReport, HandleUserReport);
5785 AddLocalPacketHandler(PacketType.FindAgent, HandleFindAgent);
5786 AddLocalPacketHandler(PacketType.TrackAgent, HandleTrackAgent);
5787 AddLocalPacketHandler(PacketType.GodUpdateRegionInfo, HandleGodUpdateRegionInfoUpdate);
5788 AddLocalPacketHandler(PacketType.GodlikeMessage, HandleGodlikeMessage);
5789 AddLocalPacketHandler(PacketType.StateSave, HandleSaveStatePacket);
5790 AddLocalPacketHandler(PacketType.GroupAccountDetailsRequest, HandleGroupAccountDetailsRequest);
5791 AddLocalPacketHandler(PacketType.GroupAccountSummaryRequest, HandleGroupAccountSummaryRequest);
5792 AddLocalPacketHandler(PacketType.GroupAccountTransactionsRequest, HandleGroupTransactionsDetailsRequest);
5793 AddLocalPacketHandler(PacketType.FreezeUser, HandleFreezeUser);
5794 AddLocalPacketHandler(PacketType.EjectUser, HandleEjectUser);
5795 AddLocalPacketHandler(PacketType.ParcelBuyPass, HandleParcelBuyPass);
5796 AddLocalPacketHandler(PacketType.ParcelGodMarkAsContent, HandleParcelGodMarkAsContent);
5797 AddLocalPacketHandler(PacketType.GroupActiveProposalsRequest, HandleGroupActiveProposalsRequest);
5798 AddLocalPacketHandler(PacketType.GroupVoteHistoryRequest, HandleGroupVoteHistoryRequest);
5799 AddLocalPacketHandler(PacketType.SimWideDeletes, HandleSimWideDeletes);
5800 AddLocalPacketHandler(PacketType.SendPostcard, HandleSendPostcard);
5801
5802 AddGenericPacketHandler("autopilot", HandleAutopilot);
5803 }
5804
5805 #region Packet Handlers
5806
5807 public int TotalAgentUpdates { get; set; }
5808
5809 #region Scene/Avatar
5810
5811 // Threshold for body rotation to be a significant agent update
5812 private const float QDELTA = 0.000001f;
5813 // Threshold for camera rotation to be a significant agent update
5814 private const float VDELTA = 0.01f;
5815
5816 /// <summary>
5817 /// This checks the update significance against the last update made.
5818 /// </summary>
5819 /// <remarks>Can only be called by one thread at a time</remarks>
5820 /// <returns></returns>
5821 /// <param name='x'></param>
5822 public bool CheckAgentUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
5823 {
5824 return CheckAgentMovementUpdateSignificance(x) || CheckAgentCameraUpdateSignificance(x);
5825 }
5826
5827 /// <summary>
5828 /// This checks the movement/state update significance against the last update made.
5829 /// </summary>
5830 /// <remarks>Can only be called by one thread at a time</remarks>
5831 /// <returns></returns>
5832 /// <param name='x'></param>
5833 private bool CheckAgentMovementUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
5834 {
5835 float qdelta1 = 1 - (float)Math.Pow(Quaternion.Dot(x.BodyRotation, m_thisAgentUpdateArgs.BodyRotation), 2);
5836 //qdelta2 = 1 - (float)Math.Pow(Quaternion.Dot(x.HeadRotation, m_thisAgentUpdateArgs.HeadRotation), 2);
5837
5838 bool movementSignificant =
5839 (qdelta1 > QDELTA) // significant if body rotation above threshold
5840 // Ignoring head rotation altogether, because it's not being used for anything interesting up the stack
5841 // || (qdelta2 > QDELTA * 10) // significant if head rotation above threshold
5842 || (x.ControlFlags != m_thisAgentUpdateArgs.ControlFlags) // significant if control flags changed
5843 || (x.ControlFlags != (byte)AgentManager.ControlFlags.NONE) // significant if user supplying any movement update commands
5844 || (x.Far != m_thisAgentUpdateArgs.Far) // significant if far distance changed
5845 || (x.Flags != m_thisAgentUpdateArgs.Flags) // significant if Flags changed
5846 || (x.State != m_thisAgentUpdateArgs.State) // significant if Stats changed
5847 ;
5848 //if (movementSignificant)
5849 //{
5850 //m_log.DebugFormat("[LLCLIENTVIEW]: Bod {0} {1}",
5851 // qdelta1, qdelta2);
5852 //m_log.DebugFormat("[LLCLIENTVIEW]: St {0} {1} {2} {3}",
5853 // x.ControlFlags, x.Flags, x.Far, x.State);
5854 //}
5855 return movementSignificant;
5856 }
5857
5858 /// <summary>
5859 /// This checks the camera update significance against the last update made.
5860 /// </summary>
5861 /// <remarks>Can only be called by one thread at a time</remarks>
5862 /// <returns></returns>
5863 /// <param name='x'></param>
5864 private bool CheckAgentCameraUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
5865 {
5866 float vdelta1 = Vector3.Distance(x.CameraAtAxis, m_thisAgentUpdateArgs.CameraAtAxis);
5867 float vdelta2 = Vector3.Distance(x.CameraCenter, m_thisAgentUpdateArgs.CameraCenter);
5868 float vdelta3 = Vector3.Distance(x.CameraLeftAxis, m_thisAgentUpdateArgs.CameraLeftAxis);
5869 float vdelta4 = Vector3.Distance(x.CameraUpAxis, m_thisAgentUpdateArgs.CameraUpAxis);
5870
5871 bool cameraSignificant =
5872 (vdelta1 > VDELTA) ||
5873 (vdelta2 > VDELTA) ||
5874 (vdelta3 > VDELTA) ||
5875 (vdelta4 > VDELTA)
5876 ;
5877
5878 //if (cameraSignificant)
5879 //{
5880 //m_log.DebugFormat("[LLCLIENTVIEW]: Cam1 {0} {1}",
5881 // x.CameraAtAxis, x.CameraCenter);
5882 //m_log.DebugFormat("[LLCLIENTVIEW]: Cam2 {0} {1}",
5883 // x.CameraLeftAxis, x.CameraUpAxis);
5884 //}
5885
5886 return cameraSignificant;
5887 }
5888
5889 private bool HandleAgentUpdate(IClientAPI sener, Packet packet)
5890 {
5891 // We got here, which means that something in agent update was significant
5892
5893 AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
5894 AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData;
5895
5896 if (x.AgentID != AgentId || x.SessionID != SessionId)
5897 return false;
5898
5899 // Before we update the current m_thisAgentUpdateArgs, let's check this again
5900 // to see what exactly changed
5901 bool movement = CheckAgentMovementUpdateSignificance(x);
5902 bool camera = CheckAgentCameraUpdateSignificance(x);
5903
5904 m_thisAgentUpdateArgs.AgentID = x.AgentID;
5905 m_thisAgentUpdateArgs.BodyRotation = x.BodyRotation;
5906 m_thisAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis;
5907 m_thisAgentUpdateArgs.CameraCenter = x.CameraCenter;
5908 m_thisAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis;
5909 m_thisAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis;
5910 m_thisAgentUpdateArgs.ControlFlags = x.ControlFlags;
5911 m_thisAgentUpdateArgs.Far = x.Far;
5912 m_thisAgentUpdateArgs.Flags = x.Flags;
5913 m_thisAgentUpdateArgs.HeadRotation = x.HeadRotation;
5914 m_thisAgentUpdateArgs.SessionID = x.SessionID;
5915 m_thisAgentUpdateArgs.State = x.State;
5916
5917 UpdateAgent handlerAgentUpdate = OnAgentUpdate;
5918 UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate;
5919 UpdateAgent handlerAgentCameraUpdate = OnAgentCameraUpdate;
5920
5921 // Was there a significant movement/state change?
5922 if (movement)
5923 {
5924 if (handlerPreAgentUpdate != null)
5925 OnPreAgentUpdate(this, m_thisAgentUpdateArgs);
5926
5927 if (handlerAgentUpdate != null)
5928 OnAgentUpdate(this, m_thisAgentUpdateArgs);
5929 }
5930 // Was there a significant camera(s) change?
5931 if (camera)
5932 if (handlerAgentCameraUpdate != null)
5933 handlerAgentCameraUpdate(this, m_thisAgentUpdateArgs);
5934
5935 handlerAgentUpdate = null;
5936 handlerPreAgentUpdate = null;
5937 handlerAgentCameraUpdate = null;
5938
5939 PacketPool.Instance.ReturnPacket(packet);
5940
5941 return true;
5942 }
5943
5944 private bool HandleMoneyTransferRequest(IClientAPI sender, Packet Pack)
5945 {
5946 MoneyTransferRequestPacket money = (MoneyTransferRequestPacket)Pack;
5947 // validate the agent owns the agentID and sessionID
5948 if (money.MoneyData.SourceID == sender.AgentId && money.AgentData.AgentID == sender.AgentId &&
5949 money.AgentData.SessionID == sender.SessionId)
5950 {
5951 MoneyTransferRequest handlerMoneyTransferRequest = OnMoneyTransferRequest;
5952 if (handlerMoneyTransferRequest != null)
5953 {
5954 handlerMoneyTransferRequest(money.MoneyData.SourceID, money.MoneyData.DestID,
5955 money.MoneyData.Amount, money.MoneyData.TransactionType,
5956 Util.FieldToString(money.MoneyData.Description));
5957 }
5958
5959 return true;
5960 }
5961
5962 return false;
5963 }
5964
5965 private bool HandleParcelGodMarkAsContent(IClientAPI client, Packet Packet)
5966 {
5967 ParcelGodMarkAsContentPacket ParcelGodMarkAsContent =
5968 (ParcelGodMarkAsContentPacket)Packet;
5969
5970 ParcelGodMark ParcelGodMarkAsContentHandler = OnParcelGodMark;
5971 if (ParcelGodMarkAsContentHandler != null)
5972 {
5973 ParcelGodMarkAsContentHandler(this,
5974 ParcelGodMarkAsContent.AgentData.AgentID,
5975 ParcelGodMarkAsContent.ParcelData.LocalID);
5976 return true;
5977 }
5978 return false;
5979 }
5980
5981 private bool HandleFreezeUser(IClientAPI client, Packet Packet)
5982 {
5983 FreezeUserPacket FreezeUser = (FreezeUserPacket)Packet;
5984
5985 FreezeUserUpdate FreezeUserHandler = OnParcelFreezeUser;
5986 if (FreezeUserHandler != null)
5987 {
5988 FreezeUserHandler(this,
5989 FreezeUser.AgentData.AgentID,
5990 FreezeUser.Data.Flags,
5991 FreezeUser.Data.TargetID);
5992 return true;
5993 }
5994 return false;
5995 }
5996
5997 private bool HandleEjectUser(IClientAPI client, Packet Packet)
5998 {
5999 EjectUserPacket EjectUser =
6000 (EjectUserPacket)Packet;
6001
6002 EjectUserUpdate EjectUserHandler = OnParcelEjectUser;
6003 if (EjectUserHandler != null)
6004 {
6005 EjectUserHandler(this,
6006 EjectUser.AgentData.AgentID,
6007 EjectUser.Data.Flags,
6008 EjectUser.Data.TargetID);
6009 return true;
6010 }
6011 return false;
6012 }
6013
6014 private bool HandleParcelBuyPass(IClientAPI client, Packet Packet)
6015 {
6016 ParcelBuyPassPacket ParcelBuyPass =
6017 (ParcelBuyPassPacket)Packet;
6018
6019 ParcelBuyPass ParcelBuyPassHandler = OnParcelBuyPass;
6020 if (ParcelBuyPassHandler != null)
6021 {
6022 ParcelBuyPassHandler(this,
6023 ParcelBuyPass.AgentData.AgentID,
6024 ParcelBuyPass.ParcelData.LocalID);
6025 return true;
6026 }
6027 return false;
6028 }
6029
6030 private bool HandleParcelBuyRequest(IClientAPI sender, Packet Pack)
6031 {
6032 ParcelBuyPacket parcel = (ParcelBuyPacket)Pack;
6033 if (parcel.AgentData.AgentID == AgentId && parcel.AgentData.SessionID == SessionId)
6034 {
6035 ParcelBuy handlerParcelBuy = OnParcelBuy;
6036 if (handlerParcelBuy != null)
6037 {
6038 handlerParcelBuy(parcel.AgentData.AgentID, parcel.Data.GroupID, parcel.Data.Final,
6039 parcel.Data.IsGroupOwned,
6040 parcel.Data.RemoveContribution, parcel.Data.LocalID, parcel.ParcelData.Area,
6041 parcel.ParcelData.Price,
6042 false);
6043 }
6044 return true;
6045 }
6046 return false;
6047 }
6048
6049 private bool HandleUUIDGroupNameRequest(IClientAPI sender, Packet Pack)
6050 {
6051 UUIDGroupNameRequestPacket upack = (UUIDGroupNameRequestPacket)Pack;
6052
6053
6054 for (int i = 0; i < upack.UUIDNameBlock.Length; i++)
6055 {
6056 UUIDNameRequest handlerUUIDGroupNameRequest = OnUUIDGroupNameRequest;
6057 if (handlerUUIDGroupNameRequest != null)
6058 {
6059 handlerUUIDGroupNameRequest(upack.UUIDNameBlock[i].ID, this);
6060 }
6061 }
6062
6063 return true;
6064 }
6065
6066 public bool HandleGenericMessage(IClientAPI sender, Packet pack)
6067 {
6068 GenericMessagePacket gmpack = (GenericMessagePacket)pack;
6069 if (m_genericPacketHandlers.Count == 0) return false;
6070 if (gmpack.AgentData.SessionID != SessionId) return false;
6071
6072 GenericMessage handlerGenericMessage = null;
6073
6074 string method = Util.FieldToString(gmpack.MethodData.Method).ToLower().Trim();
6075
6076 if (m_genericPacketHandlers.TryGetValue(method, out handlerGenericMessage))
6077 {
6078 List<string> msg = new List<string>();
6079 List<byte[]> msgBytes = new List<byte[]>();
6080
6081 if (handlerGenericMessage != null)
6082 {
6083 foreach (GenericMessagePacket.ParamListBlock block in gmpack.ParamList)
6084 {
6085 msg.Add(Util.FieldToString(block.Parameter));
6086 msgBytes.Add(block.Parameter);
6087 }
6088 try
6089 {
6090 if (OnBinaryGenericMessage != null)
6091 {
6092 OnBinaryGenericMessage(this, method, msgBytes.ToArray());
6093 }
6094 handlerGenericMessage(sender, method, msg);
6095 return true;
6096 }
6097 catch (Exception e)
6098 {
6099 m_log.ErrorFormat(
6100 "[LLCLIENTVIEW]: Exeception when handling generic message {0}{1}", e.Message, e.StackTrace);
6101 }
6102 }
6103 }
6104
6105 //m_log.Debug("[LLCLIENTVIEW]: Not handling GenericMessage with method-type of: " + method);
6106 return false;
6107 }
6108
6109 public bool HandleObjectGroupRequest(IClientAPI sender, Packet Pack)
6110 {
6111 ObjectGroupPacket ogpack = (ObjectGroupPacket)Pack;
6112 if (ogpack.AgentData.SessionID != SessionId) return false;
6113
6114 RequestObjectPropertiesFamily handlerObjectGroupRequest = OnObjectGroupRequest;
6115 if (handlerObjectGroupRequest != null)
6116 {
6117 for (int i = 0; i < ogpack.ObjectData.Length; i++)
6118 {
6119 handlerObjectGroupRequest(this, ogpack.AgentData.GroupID, ogpack.ObjectData[i].ObjectLocalID, UUID.Zero);
6120 }
6121 }
6122 return true;
6123 }
6124
6125 private bool HandleViewerEffect(IClientAPI sender, Packet Pack)
6126 {
6127 ViewerEffectPacket viewer = (ViewerEffectPacket)Pack;
6128 if (viewer.AgentData.SessionID != SessionId) return false;
6129 ViewerEffectEventHandler handlerViewerEffect = OnViewerEffect;
6130 if (handlerViewerEffect != null)
6131 {
6132 int length = viewer.Effect.Length;
6133 List<ViewerEffectEventHandlerArg> args = new List<ViewerEffectEventHandlerArg>(length);
6134 for (int i = 0; i < length; i++)
6135 {
6136 //copy the effects block arguments into the event handler arg.
6137 ViewerEffectEventHandlerArg argument = new ViewerEffectEventHandlerArg();
6138 argument.AgentID = viewer.Effect[i].AgentID;
6139 argument.Color = viewer.Effect[i].Color;
6140 argument.Duration = viewer.Effect[i].Duration;
6141 argument.ID = viewer.Effect[i].ID;
6142 argument.Type = viewer.Effect[i].Type;
6143 argument.TypeData = viewer.Effect[i].TypeData;
6144 args.Add(argument);
6145 }
6146
6147 handlerViewerEffect(sender, args);
6148 }
6149
6150 return true;
6151 }
6152
6153 private bool HandleAvatarPropertiesRequest(IClientAPI sender, Packet Pack)
6154 {
6155 AvatarPropertiesRequestPacket avatarProperties = (AvatarPropertiesRequestPacket)Pack;
6156
6157 #region Packet Session and User Check
6158 if (m_checkPackets)
6159 {
6160 if (avatarProperties.AgentData.SessionID != SessionId ||
6161 avatarProperties.AgentData.AgentID != AgentId)
6162 return true;
6163 }
6164 #endregion
6165
6166 RequestAvatarProperties handlerRequestAvatarProperties = OnRequestAvatarProperties;
6167 if (handlerRequestAvatarProperties != null)
6168 {
6169 handlerRequestAvatarProperties(this, avatarProperties.AgentData.AvatarID);
6170 }
6171 return true;
6172 }
6173
6174 private bool HandleChatFromViewer(IClientAPI sender, Packet Pack)
6175 {
6176 ChatFromViewerPacket inchatpack = (ChatFromViewerPacket)Pack;
6177
6178 #region Packet Session and User Check
6179 if (m_checkPackets)
6180 {
6181 if (inchatpack.AgentData.SessionID != SessionId ||
6182 inchatpack.AgentData.AgentID != AgentId)
6183 return true;
6184 }
6185 #endregion
6186
6187 string fromName = String.Empty; //ClientAvatar.firstname + " " + ClientAvatar.lastname;
6188 byte[] message = inchatpack.ChatData.Message;
6189 byte type = inchatpack.ChatData.Type;
6190 Vector3 fromPos = new Vector3(); // ClientAvatar.Pos;
6191 // UUID fromAgentID = AgentId;
6192
6193 int channel = inchatpack.ChatData.Channel;
6194
6195 if (OnChatFromClient != null)
6196 {
6197 OSChatMessage args = new OSChatMessage();
6198 args.Channel = channel;
6199 args.From = fromName;
6200 args.Message = Utils.BytesToString(message);
6201 args.Type = (ChatTypeEnum)type;
6202 args.Position = fromPos;
6203
6204 args.Scene = Scene;
6205 args.Sender = this;
6206 args.SenderUUID = this.AgentId;
6207
6208 ChatMessage handlerChatFromClient = OnChatFromClient;
6209 if (handlerChatFromClient != null)
6210 handlerChatFromClient(this, args);
6211 }
6212 return true;
6213 }
6214
6215 private bool HandlerAvatarPropertiesUpdate(IClientAPI sender, Packet Pack)
6216 {
6217 AvatarPropertiesUpdatePacket avatarProps = (AvatarPropertiesUpdatePacket)Pack;
6218
6219 #region Packet Session and User Check
6220 if (m_checkPackets)
6221 {
6222 if (avatarProps.AgentData.SessionID != SessionId ||
6223 avatarProps.AgentData.AgentID != AgentId)
6224 return true;
6225 }
6226 #endregion
6227
6228 UpdateAvatarProperties handlerUpdateAvatarProperties = OnUpdateAvatarProperties;
6229 if (handlerUpdateAvatarProperties != null)
6230 {
6231 AvatarPropertiesUpdatePacket.PropertiesDataBlock Properties = avatarProps.PropertiesData;
6232 UserProfileData UserProfile = new UserProfileData();
6233 UserProfile.ID = AgentId;
6234 UserProfile.AboutText = Utils.BytesToString(Properties.AboutText);
6235 UserProfile.FirstLifeAboutText = Utils.BytesToString(Properties.FLAboutText);
6236 UserProfile.FirstLifeImage = Properties.FLImageID;
6237 UserProfile.Image = Properties.ImageID;
6238 UserProfile.ProfileUrl = Utils.BytesToString(Properties.ProfileURL);
6239 UserProfile.UserFlags &= ~3;
6240 UserProfile.UserFlags |= Properties.AllowPublish ? 1 : 0;
6241 UserProfile.UserFlags |= Properties.MaturePublish ? 2 : 0;
6242
6243 handlerUpdateAvatarProperties(this, UserProfile);
6244 }
6245 return true;
6246 }
6247
6248 private bool HandlerScriptDialogReply(IClientAPI sender, Packet Pack)
6249 {
6250 ScriptDialogReplyPacket rdialog = (ScriptDialogReplyPacket)Pack;
6251
6252 //m_log.DebugFormat("[CLIENT]: Received ScriptDialogReply from {0}", rdialog.Data.ObjectID);
6253
6254 #region Packet Session and User Check
6255 if (m_checkPackets)
6256 {
6257 if (rdialog.AgentData.SessionID != SessionId ||
6258 rdialog.AgentData.AgentID != AgentId)
6259 return true;
6260 }
6261 #endregion
6262
6263 int ch = rdialog.Data.ChatChannel;
6264 byte[] msg = rdialog.Data.ButtonLabel;
6265 if (OnChatFromClient != null)
6266 {
6267 OSChatMessage args = new OSChatMessage();
6268 args.Channel = ch;
6269 args.From = String.Empty;
6270 args.Message = Utils.BytesToString(msg);
6271 args.Type = ChatTypeEnum.Region; //Behaviour in SL is that the response can be heard from any distance
6272 args.Position = new Vector3();
6273 args.Scene = Scene;
6274 args.Sender = this;
6275 ChatMessage handlerChatFromClient2 = OnChatFromClient;
6276 if (handlerChatFromClient2 != null)
6277 handlerChatFromClient2(this, args);
6278 }
6279
6280 return true;
6281 }
6282
6283 private bool HandlerImprovedInstantMessage(IClientAPI sender, Packet Pack)
6284 {
6285 ImprovedInstantMessagePacket msgpack = (ImprovedInstantMessagePacket)Pack;
6286
6287 #region Packet Session and User Check
6288 if (m_checkPackets)
6289 {
6290 if (msgpack.AgentData.SessionID != SessionId ||
6291 msgpack.AgentData.AgentID != AgentId)
6292 return true;
6293 }
6294 #endregion
6295
6296 string IMfromName = Util.FieldToString(msgpack.MessageBlock.FromAgentName);
6297 string IMmessage = Utils.BytesToString(msgpack.MessageBlock.Message);
6298 ImprovedInstantMessage handlerInstantMessage = OnInstantMessage;
6299
6300 if (handlerInstantMessage != null)
6301 {
6302 GridInstantMessage im = new GridInstantMessage(Scene,
6303 msgpack.AgentData.AgentID,
6304 IMfromName,
6305 msgpack.MessageBlock.ToAgentID,
6306 msgpack.MessageBlock.Dialog,
6307 msgpack.MessageBlock.FromGroup,
6308 IMmessage,
6309 msgpack.MessageBlock.ID,
6310 msgpack.MessageBlock.Offline != 0 ? true : false,
6311 msgpack.MessageBlock.Position,
6312 msgpack.MessageBlock.BinaryBucket,
6313 true);
6314
6315 handlerInstantMessage(this, im);
6316 }
6317 return true;
6318
6319 }
6320
6321 private bool HandlerAcceptFriendship(IClientAPI sender, Packet Pack)
6322 {
6323 AcceptFriendshipPacket afriendpack = (AcceptFriendshipPacket)Pack;
6324
6325 #region Packet Session and User Check
6326 if (m_checkPackets)
6327 {
6328 if (afriendpack.AgentData.SessionID != SessionId ||
6329 afriendpack.AgentData.AgentID != AgentId)
6330 return true;
6331 }
6332 #endregion
6333
6334 // My guess is this is the folder to stick the calling card into
6335 List<UUID> callingCardFolders = new List<UUID>();
6336
6337 UUID transactionID = afriendpack.TransactionBlock.TransactionID;
6338
6339 for (int fi = 0; fi < afriendpack.FolderData.Length; fi++)
6340 {
6341 callingCardFolders.Add(afriendpack.FolderData[fi].FolderID);
6342 }
6343
6344 FriendActionDelegate handlerApproveFriendRequest = OnApproveFriendRequest;
6345 if (handlerApproveFriendRequest != null)
6346 {
6347 handlerApproveFriendRequest(this, transactionID, callingCardFolders);
6348 }
6349
6350 return true;
6351 }
6352
6353 private bool HandlerDeclineFriendship(IClientAPI sender, Packet Pack)
6354 {
6355 DeclineFriendshipPacket dfriendpack = (DeclineFriendshipPacket)Pack;
6356
6357 #region Packet Session and User Check
6358 if (m_checkPackets)
6359 {
6360 if (dfriendpack.AgentData.SessionID != SessionId ||
6361 dfriendpack.AgentData.AgentID != AgentId)
6362 return true;
6363 }
6364 #endregion
6365
6366 if (OnDenyFriendRequest != null)
6367 {
6368 OnDenyFriendRequest(this,
6369 dfriendpack.TransactionBlock.TransactionID,
6370 null);
6371 }
6372 return true;
6373 }
6374
6375 private bool HandlerTerminateFriendship(IClientAPI sender, Packet Pack)
6376 {
6377 TerminateFriendshipPacket tfriendpack = (TerminateFriendshipPacket)Pack;
6378
6379 #region Packet Session and User Check
6380 if (m_checkPackets)
6381 {
6382 if (tfriendpack.AgentData.SessionID != SessionId ||
6383 tfriendpack.AgentData.AgentID != AgentId)
6384 return true;
6385 }
6386 #endregion
6387
6388 UUID exFriendID = tfriendpack.ExBlock.OtherID;
6389 FriendshipTermination TerminateFriendshipHandler = OnTerminateFriendship;
6390 if (TerminateFriendshipHandler != null)
6391 {
6392 TerminateFriendshipHandler(this, exFriendID);
6393 return true;
6394 }
6395
6396 return false;
6397 }
6398
6399 private bool HandleFindAgent(IClientAPI client, Packet Packet)
6400 {
6401 FindAgentPacket FindAgent =
6402 (FindAgentPacket)Packet;
6403
6404 FindAgentUpdate FindAgentHandler = OnFindAgent;
6405 if (FindAgentHandler != null)
6406 {
6407 FindAgentHandler(this,FindAgent.AgentBlock.Hunter,FindAgent.AgentBlock.Prey);
6408 return true;
6409 }
6410 return false;
6411 }
6412
6413 private bool HandleTrackAgent(IClientAPI client, Packet Packet)
6414 {
6415 TrackAgentPacket TrackAgent =
6416 (TrackAgentPacket)Packet;
6417
6418 TrackAgentUpdate TrackAgentHandler = OnTrackAgent;
6419 if (TrackAgentHandler != null)
6420 {
6421 TrackAgentHandler(this,
6422 TrackAgent.AgentData.AgentID,
6423 TrackAgent.TargetData.PreyID);
6424 return true;
6425 }
6426 return false;
6427 }
6428
6429 private bool HandlerRezObject(IClientAPI sender, Packet Pack)
6430 {
6431 RezObjectPacket rezPacket = (RezObjectPacket)Pack;
6432
6433 #region Packet Session and User Check
6434 if (m_checkPackets)
6435 {
6436 if (rezPacket.AgentData.SessionID != SessionId ||
6437 rezPacket.AgentData.AgentID != AgentId)
6438 return true;
6439 }
6440 #endregion
6441
6442 RezObject handlerRezObject = OnRezObject;
6443 if (handlerRezObject != null)
6444 {
6445 handlerRezObject(this, rezPacket.InventoryData.ItemID, rezPacket.RezData.RayEnd,
6446 rezPacket.RezData.RayStart, rezPacket.RezData.RayTargetID,
6447 rezPacket.RezData.BypassRaycast, rezPacket.RezData.RayEndIsIntersection,
6448 rezPacket.RezData.RezSelected, rezPacket.RezData.RemoveItem,
6449 rezPacket.RezData.FromTaskID);
6450 }
6451 return true;
6452 }
6453
6454 private bool HandlerDeRezObject(IClientAPI sender, Packet Pack)
6455 {
6456 DeRezObjectPacket DeRezPacket = (DeRezObjectPacket)Pack;
6457
6458 #region Packet Session and User Check
6459 if (m_checkPackets)
6460 {
6461 if (DeRezPacket.AgentData.SessionID != SessionId ||
6462 DeRezPacket.AgentData.AgentID != AgentId)
6463 return true;
6464 }
6465 #endregion
6466
6467 DeRezObject handlerDeRezObject = OnDeRezObject;
6468 if (handlerDeRezObject != null)
6469 {
6470 List<uint> deRezIDs = new List<uint>();
6471
6472 foreach (DeRezObjectPacket.ObjectDataBlock data in
6473 DeRezPacket.ObjectData)
6474 {
6475 deRezIDs.Add(data.ObjectLocalID);
6476 }
6477 // It just so happens that the values on the DeRezAction enumerator match the Destination
6478 // values given by a Second Life client
6479 handlerDeRezObject(this, deRezIDs,
6480 DeRezPacket.AgentBlock.GroupID,
6481 (DeRezAction)DeRezPacket.AgentBlock.Destination,
6482 DeRezPacket.AgentBlock.DestinationID);
6483
6484 }
6485 return true;
6486 }
6487
6488 private bool HandlerModifyLand(IClientAPI sender, Packet Pack)
6489 {
6490 ModifyLandPacket modify = (ModifyLandPacket)Pack;
6491
6492 #region Packet Session and User Check
6493 if (m_checkPackets)
6494 {
6495 if (modify.AgentData.SessionID != SessionId ||
6496 modify.AgentData.AgentID != AgentId)
6497 return true;
6498 }
6499
6500 #endregion
6501 //m_log.Info("[LAND]: LAND:" + modify.ToString());
6502 if (modify.ParcelData.Length > 0)
6503 {
6504 // Note: the ModifyTerrain event handler sends out updated packets before the end of this event. Therefore,
6505 // a simple boolean value should work and perhaps queue up just a few terrain patch packets at the end of the edit.
6506 m_justEditedTerrain = true; // Prevent terrain packet (Land layer) from being queued, make it unreliable
6507 if (OnModifyTerrain != null)
6508 {
6509 for (int i = 0; i < modify.ParcelData.Length; i++)
6510 {
6511 ModifyTerrain handlerModifyTerrain = OnModifyTerrain;
6512 if (handlerModifyTerrain != null)
6513 {
6514 handlerModifyTerrain(AgentId, modify.ModifyBlock.Height, modify.ModifyBlock.Seconds,
6515 modify.ModifyBlock.BrushSize,
6516 modify.ModifyBlock.Action, modify.ParcelData[i].North,
6517 modify.ParcelData[i].West, modify.ParcelData[i].South,
6518 modify.ParcelData[i].East, AgentId);
6519 }
6520 }
6521 }
6522 m_justEditedTerrain = false; // Queue terrain packet (Land layer) if necessary, make it reliable again
6523 }
6524
6525 return true;
6526 }
6527
6528 private bool HandlerRegionHandshakeReply(IClientAPI sender, Packet Pack)
6529 {
6530 Action<IClientAPI> handlerRegionHandShakeReply = OnRegionHandShakeReply;
6531 if (handlerRegionHandShakeReply != null)
6532 {
6533 handlerRegionHandShakeReply(this);
6534 }
6535
6536 return true;
6537 }
6538
6539 private bool HandlerAgentWearablesRequest(IClientAPI sender, Packet Pack)
6540 {
6541 GenericCall1 handlerRequestWearables = OnRequestWearables;
6542
6543 if (handlerRequestWearables != null)
6544 {
6545 handlerRequestWearables(sender);
6546 }
6547
6548 Action<IClientAPI> handlerRequestAvatarsData = OnRequestAvatarsData;
6549
6550 if (handlerRequestAvatarsData != null)
6551 {
6552 handlerRequestAvatarsData(this);
6553 }
6554
6555 return true;
6556 }
6557
6558 private bool HandlerAgentSetAppearance(IClientAPI sender, Packet Pack)
6559 {
6560 AgentSetAppearancePacket appear = (AgentSetAppearancePacket)Pack;
6561
6562 #region Packet Session and User Check
6563 if (m_checkPackets)
6564 {
6565 if (appear.AgentData.SessionID != SessionId ||
6566 appear.AgentData.AgentID != AgentId)
6567 return true;
6568 }
6569 #endregion
6570
6571 SetAppearance handlerSetAppearance = OnSetAppearance;
6572 if (handlerSetAppearance != null)
6573 {
6574 // Temporarily protect ourselves from the mantis #951 failure.
6575 // However, we could do this for several other handlers where a failure isn't terminal
6576 // for the client session anyway, in order to protect ourselves against bad code in plugins
6577 Vector3 avSize = appear.AgentData.Size;
6578 try
6579 {
6580 byte[] visualparams = new byte[appear.VisualParam.Length];
6581 for (int i = 0; i < appear.VisualParam.Length; i++)
6582 visualparams[i] = appear.VisualParam[i].ParamValue;
6583 //var b = appear.WearableData[0];
6584
6585 Primitive.TextureEntry te = null;
6586 if (appear.ObjectData.TextureEntry.Length > 1)
6587 te = new Primitive.TextureEntry(appear.ObjectData.TextureEntry, 0, appear.ObjectData.TextureEntry.Length);
6588
6589 WearableCacheItem[] cacheitems = new WearableCacheItem[appear.WearableData.Length];
6590 for (int i=0; i<appear.WearableData.Length;i++)
6591 cacheitems[i] = new WearableCacheItem(){CacheId = appear.WearableData[i].CacheID,TextureIndex=Convert.ToUInt32(appear.WearableData[i].TextureIndex)};
6592
6593
6594
6595 handlerSetAppearance(sender, te, visualparams,avSize, cacheitems);
6596 }
6597 catch (Exception e)
6598 {
6599 m_log.ErrorFormat(
6600 "[CLIENT VIEW]: AgentSetApperance packet handler threw an exception, {0}",
6601 e);
6602 }
6603 }
6604
6605 return true;
6606 }
6607
6608 private bool HandlerAgentIsNowWearing(IClientAPI sender, Packet Pack)
6609 {
6610 if (OnAvatarNowWearing != null)
6611 {
6612 AgentIsNowWearingPacket nowWearing = (AgentIsNowWearingPacket)Pack;
6613
6614 #region Packet Session and User Check
6615 if (m_checkPackets)
6616 {
6617 if (nowWearing.AgentData.SessionID != SessionId ||
6618 nowWearing.AgentData.AgentID != AgentId)
6619 return true;
6620 }
6621 #endregion
6622
6623 AvatarWearingArgs wearingArgs = new AvatarWearingArgs();
6624 for (int i = 0; i < nowWearing.WearableData.Length; i++)
6625 {
6626 //m_log.DebugFormat("[XXX]: Wearable type {0} item {1}", nowWearing.WearableData[i].WearableType, nowWearing.WearableData[i].ItemID);
6627 AvatarWearingArgs.Wearable wearable =
6628 new AvatarWearingArgs.Wearable(nowWearing.WearableData[i].ItemID,
6629 nowWearing.WearableData[i].WearableType);
6630 wearingArgs.NowWearing.Add(wearable);
6631 }
6632
6633 AvatarNowWearing handlerAvatarNowWearing = OnAvatarNowWearing;
6634 if (handlerAvatarNowWearing != null)
6635 {
6636 handlerAvatarNowWearing(this, wearingArgs);
6637 }
6638 }
6639 return true;
6640 }
6641
6642 private bool HandlerRezSingleAttachmentFromInv(IClientAPI sender, Packet Pack)
6643 {
6644 RezSingleAttachmentFromInv handlerRezSingleAttachment = OnRezSingleAttachmentFromInv;
6645 if (handlerRezSingleAttachment != null)
6646 {
6647 RezSingleAttachmentFromInvPacket rez = (RezSingleAttachmentFromInvPacket)Pack;
6648
6649 #region Packet Session and User Check
6650 if (m_checkPackets)
6651 {
6652 if (rez.AgentData.SessionID != SessionId ||
6653 rez.AgentData.AgentID != AgentId)
6654 return true;
6655 }
6656 #endregion
6657
6658 handlerRezSingleAttachment(this, rez.ObjectData.ItemID,
6659 rez.ObjectData.AttachmentPt);
6660 }
6661
6662 return true;
6663 }
6664
6665 private bool HandleRezMultipleAttachmentsFromInv(IClientAPI sender, Packet Pack)
6666 {
6667 RezMultipleAttachmentsFromInv handlerRezMultipleAttachments = OnRezMultipleAttachmentsFromInv;
6668 if (handlerRezMultipleAttachments != null)
6669 {
6670 List<KeyValuePair<UUID, uint>> rezlist = new List<KeyValuePair<UUID, uint>>();
6671 foreach (RezMultipleAttachmentsFromInvPacket.ObjectDataBlock obj in ((RezMultipleAttachmentsFromInvPacket)Pack).ObjectData)
6672 rezlist.Add(new KeyValuePair<UUID, uint>(obj.ItemID, obj.AttachmentPt));
6673 handlerRezMultipleAttachments(this, rezlist);
6674 }
6675
6676 return true;
6677 }
6678
6679 private bool HandleDetachAttachmentIntoInv(IClientAPI sender, Packet Pack)
6680 {
6681 UUIDNameRequest handlerDetachAttachmentIntoInv = OnDetachAttachmentIntoInv;
6682 if (handlerDetachAttachmentIntoInv != null)
6683 {
6684 DetachAttachmentIntoInvPacket detachtoInv = (DetachAttachmentIntoInvPacket)Pack;
6685
6686 #region Packet Session and User Check
6687 // UNSUPPORTED ON THIS PACKET
6688 #endregion
6689
6690 UUID itemID = detachtoInv.ObjectData.ItemID;
6691 // UUID ATTACH_agentID = detachtoInv.ObjectData.AgentID;
6692
6693 handlerDetachAttachmentIntoInv(itemID, this);
6694 }
6695 return true;
6696 }
6697
6698 private bool HandleObjectAttach(IClientAPI sender, Packet Pack)
6699 {
6700 if (OnObjectAttach != null)
6701 {
6702 ObjectAttachPacket att = (ObjectAttachPacket)Pack;
6703
6704 #region Packet Session and User Check
6705 if (m_checkPackets)
6706 {
6707 if (att.AgentData.SessionID != SessionId ||
6708 att.AgentData.AgentID != AgentId)
6709 return true;
6710 }
6711 #endregion
6712
6713 ObjectAttach handlerObjectAttach = OnObjectAttach;
6714
6715 if (handlerObjectAttach != null)
6716 {
6717 if (att.ObjectData.Length > 0)
6718 {
6719 handlerObjectAttach(this, att.ObjectData[0].ObjectLocalID, att.AgentData.AttachmentPoint, false);
6720 }
6721 }
6722 }
6723 return true;
6724 }
6725
6726 private bool HandleObjectDetach(IClientAPI sender, Packet Pack)
6727 {
6728 ObjectDetachPacket dett = (ObjectDetachPacket)Pack;
6729
6730 #region Packet Session and User Check
6731 if (m_checkPackets)
6732 {
6733 if (dett.AgentData.SessionID != SessionId ||
6734 dett.AgentData.AgentID != AgentId)
6735 return true;
6736 }
6737 #endregion
6738
6739 for (int j = 0; j < dett.ObjectData.Length; j++)
6740 {
6741 uint obj = dett.ObjectData[j].ObjectLocalID;
6742 ObjectDeselect handlerObjectDetach = OnObjectDetach;
6743 if (handlerObjectDetach != null)
6744 {
6745 handlerObjectDetach(obj, this);
6746 }
6747
6748 }
6749 return true;
6750 }
6751
6752 private bool HandleObjectDrop(IClientAPI sender, Packet Pack)
6753 {
6754 ObjectDropPacket dropp = (ObjectDropPacket)Pack;
6755
6756 #region Packet Session and User Check
6757 if (m_checkPackets)
6758 {
6759 if (dropp.AgentData.SessionID != SessionId ||
6760 dropp.AgentData.AgentID != AgentId)
6761 return true;
6762 }
6763 #endregion
6764
6765 for (int j = 0; j < dropp.ObjectData.Length; j++)
6766 {
6767 uint obj = dropp.ObjectData[j].ObjectLocalID;
6768 ObjectDrop handlerObjectDrop = OnObjectDrop;
6769 if (handlerObjectDrop != null)
6770 {
6771 handlerObjectDrop(obj, this);
6772 }
6773 }
6774 return true;
6775 }
6776
6777 private bool HandleSetAlwaysRun(IClientAPI sender, Packet Pack)
6778 {
6779 SetAlwaysRunPacket run = (SetAlwaysRunPacket)Pack;
6780
6781 #region Packet Session and User Check
6782 if (m_checkPackets)
6783 {
6784 if (run.AgentData.SessionID != SessionId ||
6785 run.AgentData.AgentID != AgentId)
6786 return true;
6787 }
6788 #endregion
6789
6790 SetAlwaysRun handlerSetAlwaysRun = OnSetAlwaysRun;
6791 if (handlerSetAlwaysRun != null)
6792 handlerSetAlwaysRun(this, run.AgentData.AlwaysRun);
6793
6794 return true;
6795 }
6796
6797 private bool HandleCompleteAgentMovement(IClientAPI sender, Packet Pack)
6798 {
6799 Action<IClientAPI, bool> handlerCompleteMovementToRegion = OnCompleteMovementToRegion;
6800 if (handlerCompleteMovementToRegion != null)
6801 {
6802 handlerCompleteMovementToRegion(sender, true);
6803 }
6804 handlerCompleteMovementToRegion = null;
6805
6806 return true;
6807 }
6808
6809 private bool HandleAgentAnimation(IClientAPI sender, Packet Pack)
6810 {
6811 AgentAnimationPacket AgentAni = (AgentAnimationPacket)Pack;
6812
6813 #region Packet Session and User Check
6814 if (m_checkPackets)
6815 {
6816 if (AgentAni.AgentData.SessionID != SessionId ||
6817 AgentAni.AgentData.AgentID != AgentId)
6818 return true;
6819 }
6820 #endregion
6821
6822 StartAnim handlerStartAnim = null;
6823 StopAnim handlerStopAnim = null;
6824
6825 for (int i = 0; i < AgentAni.AnimationList.Length; i++)
6826 {
6827 if (AgentAni.AnimationList[i].StartAnim)
6828 {
6829 handlerStartAnim = OnStartAnim;
6830 if (handlerStartAnim != null)
6831 {
6832 handlerStartAnim(this, AgentAni.AnimationList[i].AnimID);
6833 }
6834 }
6835 else
6836 {
6837 handlerStopAnim = OnStopAnim;
6838 if (handlerStopAnim != null)
6839 {
6840 handlerStopAnim(this, AgentAni.AnimationList[i].AnimID);
6841 }
6842 }
6843 }
6844 return true;
6845 }
6846
6847 private bool HandleAgentRequestSit(IClientAPI sender, Packet Pack)
6848 {
6849 if (OnAgentRequestSit != null)
6850 {
6851 AgentRequestSitPacket agentRequestSit = (AgentRequestSitPacket)Pack;
6852
6853 #region Packet Session and User Check
6854 if (m_checkPackets)
6855 {
6856 if (agentRequestSit.AgentData.SessionID != SessionId ||
6857 agentRequestSit.AgentData.AgentID != AgentId)
6858 return true;
6859 }
6860 #endregion
6861
6862 if (SceneAgent.IsChildAgent)
6863 {
6864 SendCantSitBecauseChildAgentResponse();
6865 return true;
6866 }
6867
6868 AgentRequestSit handlerAgentRequestSit = OnAgentRequestSit;
6869
6870 if (handlerAgentRequestSit != null)
6871 handlerAgentRequestSit(this, agentRequestSit.AgentData.AgentID,
6872 agentRequestSit.TargetObject.TargetID, agentRequestSit.TargetObject.Offset);
6873 }
6874 return true;
6875 }
6876
6877 private bool HandleAgentSit(IClientAPI sender, Packet Pack)
6878 {
6879 if (OnAgentSit != null)
6880 {
6881 AgentSitPacket agentSit = (AgentSitPacket)Pack;
6882
6883 #region Packet Session and User Check
6884 if (m_checkPackets)
6885 {
6886 if (agentSit.AgentData.SessionID != SessionId ||
6887 agentSit.AgentData.AgentID != AgentId)
6888 return true;
6889 }
6890 #endregion
6891
6892 if (SceneAgent.IsChildAgent)
6893 {
6894 SendCantSitBecauseChildAgentResponse();
6895 return true;
6896 }
6897
6898 AgentSit handlerAgentSit = OnAgentSit;
6899 if (handlerAgentSit != null)
6900 {
6901 OnAgentSit(this, agentSit.AgentData.AgentID);
6902 }
6903 }
6904 return true;
6905 }
6906
6907 /// <summary>
6908 /// Used when a child agent gets a sit response which should not be fulfilled.
6909 /// </summary>
6910 private void SendCantSitBecauseChildAgentResponse()
6911 {
6912 SendAlertMessage("Try moving closer. Can't sit on object because it is not in the same region as you.");
6913 }
6914
6915 private bool HandleSoundTrigger(IClientAPI sender, Packet Pack)
6916 {
6917 SoundTriggerPacket soundTriggerPacket = (SoundTriggerPacket)Pack;
6918
6919 #region Packet Session and User Check
6920 if (m_checkPackets)
6921 {
6922 // UNSUPPORTED ON THIS PACKET
6923 }
6924 #endregion
6925
6926 SoundTrigger handlerSoundTrigger = OnSoundTrigger;
6927 if (handlerSoundTrigger != null)
6928 {
6929 // UUIDS are sent as zeroes by the client, substitute agent's id
6930 handlerSoundTrigger(soundTriggerPacket.SoundData.SoundID, AgentId,
6931 AgentId, AgentId,
6932 soundTriggerPacket.SoundData.Gain, soundTriggerPacket.SoundData.Position,
6933 soundTriggerPacket.SoundData.Handle, 0);
6934
6935 }
6936 return true;
6937 }
6938
6939 private bool HandleAvatarPickerRequest(IClientAPI sender, Packet Pack)
6940 {
6941 AvatarPickerRequestPacket avRequestQuery = (AvatarPickerRequestPacket)Pack;
6942
6943 #region Packet Session and User Check
6944 if (m_checkPackets)
6945 {
6946 if (avRequestQuery.AgentData.SessionID != SessionId ||
6947 avRequestQuery.AgentData.AgentID != AgentId)
6948 return true;
6949 }
6950 #endregion
6951
6952 AvatarPickerRequestPacket.AgentDataBlock Requestdata = avRequestQuery.AgentData;
6953 AvatarPickerRequestPacket.DataBlock querydata = avRequestQuery.Data;
6954 //m_log.Debug("Agent Sends:" + Utils.BytesToString(querydata.Name));
6955
6956 AvatarPickerRequest handlerAvatarPickerRequest = OnAvatarPickerRequest;
6957 if (handlerAvatarPickerRequest != null)
6958 {
6959 handlerAvatarPickerRequest(this, Requestdata.AgentID, Requestdata.QueryID,
6960 Utils.BytesToString(querydata.Name));
6961 }
6962 return true;
6963 }
6964
6965 private bool HandleAgentDataUpdateRequest(IClientAPI sender, Packet Pack)
6966 {
6967 AgentDataUpdateRequestPacket avRequestDataUpdatePacket = (AgentDataUpdateRequestPacket)Pack;
6968
6969 #region Packet Session and User Check
6970 if (m_checkPackets)
6971 {
6972 if (avRequestDataUpdatePacket.AgentData.SessionID != SessionId ||
6973 avRequestDataUpdatePacket.AgentData.AgentID != AgentId)
6974 return true;
6975 }
6976 #endregion
6977
6978 FetchInventory handlerAgentDataUpdateRequest = OnAgentDataUpdateRequest;
6979
6980 if (handlerAgentDataUpdateRequest != null)
6981 {
6982 handlerAgentDataUpdateRequest(this, avRequestDataUpdatePacket.AgentData.AgentID, avRequestDataUpdatePacket.AgentData.SessionID);
6983 }
6984
6985 return true;
6986 }
6987
6988 private bool HandleUserInfoRequest(IClientAPI sender, Packet Pack)
6989 {
6990 UserInfoRequest handlerUserInfoRequest = OnUserInfoRequest;
6991 if (handlerUserInfoRequest != null)
6992 {
6993 handlerUserInfoRequest(this);
6994 }
6995 else
6996 {
6997 SendUserInfoReply(false, true, "");
6998 }
6999 return true;
7000
7001 }
7002
7003 private bool HandleUpdateUserInfo(IClientAPI sender, Packet Pack)
7004 {
7005 UpdateUserInfoPacket updateUserInfo = (UpdateUserInfoPacket)Pack;
7006
7007 #region Packet Session and User Check
7008 if (m_checkPackets)
7009 {
7010 if (updateUserInfo.AgentData.SessionID != SessionId ||
7011 updateUserInfo.AgentData.AgentID != AgentId)
7012 return true;
7013 }
7014 #endregion
7015
7016 UpdateUserInfo handlerUpdateUserInfo = OnUpdateUserInfo;
7017 if (handlerUpdateUserInfo != null)
7018 {
7019 bool visible = true;
7020 string DirectoryVisibility =
7021 Utils.BytesToString(updateUserInfo.UserData.DirectoryVisibility);
7022 if (DirectoryVisibility == "hidden")
7023 visible = false;
7024
7025 handlerUpdateUserInfo(
7026 updateUserInfo.UserData.IMViaEMail,
7027 visible, this);
7028 }
7029 return true;
7030 }
7031
7032 private bool HandleSetStartLocationRequest(IClientAPI sender, Packet Pack)
7033 {
7034 SetStartLocationRequestPacket avSetStartLocationRequestPacket = (SetStartLocationRequestPacket)Pack;
7035
7036 #region Packet Session and User Check
7037 if (m_checkPackets)
7038 {
7039 if (avSetStartLocationRequestPacket.AgentData.SessionID != SessionId ||
7040 avSetStartLocationRequestPacket.AgentData.AgentID != AgentId)
7041 return true;
7042 }
7043 #endregion
7044
7045 if (avSetStartLocationRequestPacket.AgentData.AgentID == AgentId && avSetStartLocationRequestPacket.AgentData.SessionID == SessionId)
7046 {
7047 // Linden Client limitation..
7048 if (avSetStartLocationRequestPacket.StartLocationData.LocationPos.X == 255.5f
7049 || avSetStartLocationRequestPacket.StartLocationData.LocationPos.Y == 255.5f)
7050 {
7051 ScenePresence avatar = null;
7052 if (((Scene)m_scene).TryGetScenePresence(AgentId, out avatar))
7053 {
7054 if (avSetStartLocationRequestPacket.StartLocationData.LocationPos.X == 255.5f)
7055 {
7056 avSetStartLocationRequestPacket.StartLocationData.LocationPos.X = avatar.AbsolutePosition.X;
7057 }
7058 if (avSetStartLocationRequestPacket.StartLocationData.LocationPos.Y == 255.5f)
7059 {
7060 avSetStartLocationRequestPacket.StartLocationData.LocationPos.Y = avatar.AbsolutePosition.Y;
7061 }
7062 }
7063
7064 }
7065 TeleportLocationRequest handlerSetStartLocationRequest = OnSetStartLocationRequest;
7066 if (handlerSetStartLocationRequest != null)
7067 {
7068 handlerSetStartLocationRequest(this, 0, avSetStartLocationRequestPacket.StartLocationData.LocationPos,
7069 avSetStartLocationRequestPacket.StartLocationData.LocationLookAt,
7070 avSetStartLocationRequestPacket.StartLocationData.LocationID);
7071 }
7072 }
7073 return true;
7074 }
7075
7076 private bool HandleAgentThrottle(IClientAPI sender, Packet Pack)
7077 {
7078 AgentThrottlePacket atpack = (AgentThrottlePacket)Pack;
7079
7080 #region Packet Session and User Check
7081 if (m_checkPackets)
7082 {
7083 if (atpack.AgentData.SessionID != SessionId ||
7084 atpack.AgentData.AgentID != AgentId)
7085 return true;
7086 }
7087 #endregion
7088
7089 m_udpClient.SetThrottles(atpack.Throttle.Throttles);
7090 return true;
7091 }
7092
7093 private bool HandleAgentPause(IClientAPI sender, Packet Pack)
7094 {
7095 m_udpClient.IsPaused = true;
7096 return true;
7097 }
7098
7099 private bool HandleAgentResume(IClientAPI sender, Packet Pack)
7100 {
7101 m_udpClient.IsPaused = false;
7102 SendStartPingCheck(m_udpClient.CurrentPingSequence++);
7103 return true;
7104 }
7105
7106 private bool HandleForceScriptControlRelease(IClientAPI sender, Packet Pack)
7107 {
7108 ForceReleaseControls handlerForceReleaseControls = OnForceReleaseControls;
7109 if (handlerForceReleaseControls != null)
7110 {
7111 handlerForceReleaseControls(this, AgentId);
7112 }
7113 return true;
7114 }
7115
7116 #endregion Scene/Avatar
7117
7118 #region Objects/m_sceneObjects
7119
7120 private bool HandleObjectLink(IClientAPI sender, Packet Pack)
7121 {
7122 ObjectLinkPacket link = (ObjectLinkPacket)Pack;
7123
7124 #region Packet Session and User Check
7125 if (m_checkPackets)
7126 {
7127 if (link.AgentData.SessionID != SessionId ||
7128 link.AgentData.AgentID != AgentId)
7129 return true;
7130 }
7131 #endregion
7132
7133 uint parentprimid = 0;
7134 List<uint> childrenprims = new List<uint>();
7135 if (link.ObjectData.Length > 1)
7136 {
7137 parentprimid = link.ObjectData[0].ObjectLocalID;
7138
7139 for (int i = 1; i < link.ObjectData.Length; i++)
7140 {
7141 childrenprims.Add(link.ObjectData[i].ObjectLocalID);
7142 }
7143 }
7144 LinkObjects handlerLinkObjects = OnLinkObjects;
7145 if (handlerLinkObjects != null)
7146 {
7147 handlerLinkObjects(this, parentprimid, childrenprims);
7148 }
7149 return true;
7150 }
7151
7152 private bool HandleObjectDelink(IClientAPI sender, Packet Pack)
7153 {
7154 ObjectDelinkPacket delink = (ObjectDelinkPacket)Pack;
7155
7156 #region Packet Session and User Check
7157 if (m_checkPackets)
7158 {
7159 if (delink.AgentData.SessionID != SessionId ||
7160 delink.AgentData.AgentID != AgentId)
7161 return true;
7162 }
7163 #endregion
7164
7165 // It appears the prim at index 0 is not always the root prim (for
7166 // instance, when one prim of a link set has been edited independently
7167 // of the others). Therefore, we'll pass all the ids onto the delink
7168 // method for it to decide which is the root.
7169 List<uint> prims = new List<uint>();
7170 for (int i = 0; i < delink.ObjectData.Length; i++)
7171 {
7172 prims.Add(delink.ObjectData[i].ObjectLocalID);
7173 }
7174 DelinkObjects handlerDelinkObjects = OnDelinkObjects;
7175 if (handlerDelinkObjects != null)
7176 {
7177 handlerDelinkObjects(prims, this);
7178 }
7179
7180 return true;
7181 }
7182
7183 private bool HandleObjectAdd(IClientAPI sender, Packet Pack)
7184 {
7185 if (OnAddPrim != null)
7186 {
7187 ObjectAddPacket addPacket = (ObjectAddPacket)Pack;
7188
7189 #region Packet Session and User Check
7190 if (m_checkPackets)
7191 {
7192 if (addPacket.AgentData.SessionID != SessionId ||
7193 addPacket.AgentData.AgentID != AgentId)
7194 return true;
7195 }
7196 #endregion
7197
7198 PrimitiveBaseShape shape = GetShapeFromAddPacket(addPacket);
7199 // m_log.Info("[REZData]: " + addPacket.ToString());
7200 //BypassRaycast: 1
7201 //RayStart: <69.79469, 158.2652, 98.40343>
7202 //RayEnd: <61.97724, 141.995, 92.58341>
7203 //RayTargetID: 00000000-0000-0000-0000-000000000000
7204
7205 //Check to see if adding the prim is allowed; useful for any module wanting to restrict the
7206 //object from rezing initially
7207
7208 AddNewPrim handlerAddPrim = OnAddPrim;
7209 if (handlerAddPrim != null)
7210 handlerAddPrim(AgentId, ActiveGroupId, addPacket.ObjectData.RayEnd, addPacket.ObjectData.Rotation, shape, addPacket.ObjectData.BypassRaycast, addPacket.ObjectData.RayStart, addPacket.ObjectData.RayTargetID, addPacket.ObjectData.RayEndIsIntersection);
7211 }
7212 return true;
7213 }
7214
7215 private bool HandleObjectShape(IClientAPI sender, Packet Pack)
7216 {
7217 ObjectShapePacket shapePacket = (ObjectShapePacket)Pack;
7218
7219 #region Packet Session and User Check
7220 if (m_checkPackets)
7221 {
7222 if (shapePacket.AgentData.SessionID != SessionId ||
7223 shapePacket.AgentData.AgentID != AgentId)
7224 return true;
7225 }
7226 #endregion
7227
7228 UpdateShape handlerUpdatePrimShape = null;
7229 for (int i = 0; i < shapePacket.ObjectData.Length; i++)
7230 {
7231 handlerUpdatePrimShape = OnUpdatePrimShape;
7232 if (handlerUpdatePrimShape != null)
7233 {
7234 UpdateShapeArgs shapeData = new UpdateShapeArgs();
7235 shapeData.ObjectLocalID = shapePacket.ObjectData[i].ObjectLocalID;
7236 shapeData.PathBegin = shapePacket.ObjectData[i].PathBegin;
7237 shapeData.PathCurve = shapePacket.ObjectData[i].PathCurve;
7238 shapeData.PathEnd = shapePacket.ObjectData[i].PathEnd;
7239 shapeData.PathRadiusOffset = shapePacket.ObjectData[i].PathRadiusOffset;
7240 shapeData.PathRevolutions = shapePacket.ObjectData[i].PathRevolutions;
7241 shapeData.PathScaleX = shapePacket.ObjectData[i].PathScaleX;
7242 shapeData.PathScaleY = shapePacket.ObjectData[i].PathScaleY;
7243 shapeData.PathShearX = shapePacket.ObjectData[i].PathShearX;
7244 shapeData.PathShearY = shapePacket.ObjectData[i].PathShearY;
7245 shapeData.PathSkew = shapePacket.ObjectData[i].PathSkew;
7246 shapeData.PathTaperX = shapePacket.ObjectData[i].PathTaperX;
7247 shapeData.PathTaperY = shapePacket.ObjectData[i].PathTaperY;
7248 shapeData.PathTwist = shapePacket.ObjectData[i].PathTwist;
7249 shapeData.PathTwistBegin = shapePacket.ObjectData[i].PathTwistBegin;
7250 shapeData.ProfileBegin = shapePacket.ObjectData[i].ProfileBegin;
7251 shapeData.ProfileCurve = shapePacket.ObjectData[i].ProfileCurve;
7252 shapeData.ProfileEnd = shapePacket.ObjectData[i].ProfileEnd;
7253 shapeData.ProfileHollow = shapePacket.ObjectData[i].ProfileHollow;
7254
7255 handlerUpdatePrimShape(m_agentId, shapePacket.ObjectData[i].ObjectLocalID,
7256 shapeData);
7257 }
7258 }
7259 return true;
7260 }
7261
7262 private bool HandleObjectExtraParams(IClientAPI sender, Packet Pack)
7263 {
7264 ObjectExtraParamsPacket extraPar = (ObjectExtraParamsPacket)Pack;
7265
7266 #region Packet Session and User Check
7267 if (m_checkPackets)
7268 {
7269 if (extraPar.AgentData.SessionID != SessionId ||
7270 extraPar.AgentData.AgentID != AgentId)
7271 return true;
7272 }
7273 #endregion
7274
7275 ObjectExtraParams handlerUpdateExtraParams = OnUpdateExtraParams;
7276 if (handlerUpdateExtraParams != null)
7277 {
7278 for (int i = 0; i < extraPar.ObjectData.Length; i++)
7279 {
7280 handlerUpdateExtraParams(m_agentId, extraPar.ObjectData[i].ObjectLocalID,
7281 extraPar.ObjectData[i].ParamType,
7282 extraPar.ObjectData[i].ParamInUse, extraPar.ObjectData[i].ParamData);
7283 }
7284 }
7285 return true;
7286 }
7287
7288 private bool HandleObjectDuplicate(IClientAPI sender, Packet Pack)
7289 {
7290 ObjectDuplicatePacket dupe = (ObjectDuplicatePacket)Pack;
7291
7292 #region Packet Session and User Check
7293 if (m_checkPackets)
7294 {
7295 if (dupe.AgentData.SessionID != SessionId ||
7296 dupe.AgentData.AgentID != AgentId)
7297 return true;
7298 }
7299 #endregion
7300
7301// ObjectDuplicatePacket.AgentDataBlock AgentandGroupData = dupe.AgentData;
7302
7303 ObjectDuplicate handlerObjectDuplicate = null;
7304
7305 for (int i = 0; i < dupe.ObjectData.Length; i++)
7306 {
7307 handlerObjectDuplicate = OnObjectDuplicate;
7308 if (handlerObjectDuplicate != null)
7309 {
7310 handlerObjectDuplicate(dupe.ObjectData[i].ObjectLocalID, dupe.SharedData.Offset,
7311 dupe.SharedData.DuplicateFlags, AgentId,
7312 ActiveGroupId);
7313 }
7314 }
7315
7316 return true;
7317 }
7318
7319 private bool HandleRequestMultipleObjects(IClientAPI sender, Packet Pack)
7320 {
7321 RequestMultipleObjectsPacket incomingRequest = (RequestMultipleObjectsPacket)Pack;
7322
7323 #region Packet Session and User Check
7324 if (m_checkPackets)
7325 {
7326 if (incomingRequest.AgentData.SessionID != SessionId ||
7327 incomingRequest.AgentData.AgentID != AgentId)
7328 return true;
7329 }
7330 #endregion
7331
7332 ObjectRequest handlerObjectRequest = null;
7333
7334 for (int i = 0; i < incomingRequest.ObjectData.Length; i++)
7335 {
7336 handlerObjectRequest = OnObjectRequest;
7337 if (handlerObjectRequest != null)
7338 {
7339 handlerObjectRequest(incomingRequest.ObjectData[i].ID, this);
7340 }
7341 }
7342 return true;
7343 }
7344
7345 private bool HandleObjectSelect(IClientAPI sender, Packet Pack)
7346 {
7347 ObjectSelectPacket incomingselect = (ObjectSelectPacket)Pack;
7348
7349 #region Packet Session and User Check
7350 if (m_checkPackets)
7351 {
7352 if (incomingselect.AgentData.SessionID != SessionId ||
7353 incomingselect.AgentData.AgentID != AgentId)
7354 return true;
7355 }
7356 #endregion
7357
7358 ObjectSelect handlerObjectSelect = null;
7359
7360 for (int i = 0; i < incomingselect.ObjectData.Length; i++)
7361 {
7362 handlerObjectSelect = OnObjectSelect;
7363 if (handlerObjectSelect != null)
7364 {
7365 handlerObjectSelect(incomingselect.ObjectData[i].ObjectLocalID, this);
7366 }
7367 }
7368 return true;
7369 }
7370
7371 private bool HandleObjectDeselect(IClientAPI sender, Packet Pack)
7372 {
7373 ObjectDeselectPacket incomingdeselect = (ObjectDeselectPacket)Pack;
7374
7375 #region Packet Session and User Check
7376 if (m_checkPackets)
7377 {
7378 if (incomingdeselect.AgentData.SessionID != SessionId ||
7379 incomingdeselect.AgentData.AgentID != AgentId)
7380 return true;
7381 }
7382 #endregion
7383
7384 ObjectDeselect handlerObjectDeselect = null;
7385
7386 for (int i = 0; i < incomingdeselect.ObjectData.Length; i++)
7387 {
7388 handlerObjectDeselect = OnObjectDeselect;
7389 if (handlerObjectDeselect != null)
7390 {
7391 OnObjectDeselect(incomingdeselect.ObjectData[i].ObjectLocalID, this);
7392 }
7393 }
7394 return true;
7395 }
7396
7397 private bool HandleObjectPosition(IClientAPI sender, Packet Pack)
7398 {
7399 // DEPRECATED: but till libsecondlife removes it, people will use it
7400 ObjectPositionPacket position = (ObjectPositionPacket)Pack;
7401
7402 #region Packet Session and User Check
7403 if (m_checkPackets)
7404 {
7405 if (position.AgentData.SessionID != SessionId ||
7406 position.AgentData.AgentID != AgentId)
7407 return true;
7408 }
7409 #endregion
7410
7411
7412 for (int i = 0; i < position.ObjectData.Length; i++)
7413 {
7414 UpdateVector handlerUpdateVector = OnUpdatePrimGroupPosition;
7415 if (handlerUpdateVector != null)
7416 handlerUpdateVector(position.ObjectData[i].ObjectLocalID, position.ObjectData[i].Position, this);
7417 }
7418
7419 return true;
7420 }
7421
7422 private bool HandleObjectScale(IClientAPI sender, Packet Pack)
7423 {
7424 // DEPRECATED: but till libsecondlife removes it, people will use it
7425 ObjectScalePacket scale = (ObjectScalePacket)Pack;
7426
7427 #region Packet Session and User Check
7428 if (m_checkPackets)
7429 {
7430 if (scale.AgentData.SessionID != SessionId ||
7431 scale.AgentData.AgentID != AgentId)
7432 return true;
7433 }
7434 #endregion
7435
7436 for (int i = 0; i < scale.ObjectData.Length; i++)
7437 {
7438 UpdateVector handlerUpdatePrimGroupScale = OnUpdatePrimGroupScale;
7439 if (handlerUpdatePrimGroupScale != null)
7440 handlerUpdatePrimGroupScale(scale.ObjectData[i].ObjectLocalID, scale.ObjectData[i].Scale, this);
7441 }
7442
7443 return true;
7444 }
7445
7446 private bool HandleObjectRotation(IClientAPI sender, Packet Pack)
7447 {
7448 // DEPRECATED: but till libsecondlife removes it, people will use it
7449 ObjectRotationPacket rotation = (ObjectRotationPacket)Pack;
7450
7451 #region Packet Session and User Check
7452 if (m_checkPackets)
7453 {
7454 if (rotation.AgentData.SessionID != SessionId ||
7455 rotation.AgentData.AgentID != AgentId)
7456 return true;
7457 }
7458 #endregion
7459
7460 for (int i = 0; i < rotation.ObjectData.Length; i++)
7461 {
7462 UpdatePrimRotation handlerUpdatePrimRotation = OnUpdatePrimGroupRotation;
7463 if (handlerUpdatePrimRotation != null)
7464 handlerUpdatePrimRotation(rotation.ObjectData[i].ObjectLocalID, rotation.ObjectData[i].Rotation, this);
7465 }
7466
7467 return true;
7468 }
7469
7470 private bool HandleObjectFlagUpdate(IClientAPI sender, Packet Pack)
7471 {
7472 ObjectFlagUpdatePacket flags = (ObjectFlagUpdatePacket)Pack;
7473
7474 #region Packet Session and User Check
7475 if (m_checkPackets)
7476 {
7477 if (flags.AgentData.SessionID != SessionId ||
7478 flags.AgentData.AgentID != AgentId)
7479 return true;
7480 }
7481 #endregion
7482
7483 UpdatePrimFlags handlerUpdatePrimFlags = OnUpdatePrimFlags;
7484
7485 if (handlerUpdatePrimFlags != null)
7486 {
7487// byte[] data = Pack.ToBytes();
7488 // 46,47,48 are special positions within the packet
7489 // This may change so perhaps we need a better way
7490 // of storing this (OMV.FlagUpdatePacket.UsePhysics,etc?)
7491 /*
7492 bool UsePhysics = (data[46] != 0) ? true : false;
7493 bool IsTemporary = (data[47] != 0) ? true : false;
7494 bool IsPhantom = (data[48] != 0) ? true : false;
7495 handlerUpdatePrimFlags(flags.AgentData.ObjectLocalID, UsePhysics, IsTemporary, IsPhantom, this);
7496 */
7497 bool UsePhysics = flags.AgentData.UsePhysics;
7498 bool IsPhantom = flags.AgentData.IsPhantom;
7499 bool IsTemporary = flags.AgentData.IsTemporary;
7500 ObjectFlagUpdatePacket.ExtraPhysicsBlock[] blocks = flags.ExtraPhysics;
7501 ExtraPhysicsData physdata = new ExtraPhysicsData();
7502
7503 if (blocks == null || blocks.Length == 0)
7504 {
7505 physdata.PhysShapeType = PhysShapeType.invalid;
7506 }
7507 else
7508 {
7509 ObjectFlagUpdatePacket.ExtraPhysicsBlock phsblock = blocks[0];
7510 physdata.PhysShapeType = (PhysShapeType)phsblock.PhysicsShapeType;
7511 physdata.Bounce = phsblock.Restitution;
7512 physdata.Density = phsblock.Density;
7513 physdata.Friction = phsblock.Friction;
7514 physdata.GravitationModifier = phsblock.GravityMultiplier;
7515 }
7516
7517 handlerUpdatePrimFlags(flags.AgentData.ObjectLocalID, UsePhysics, IsTemporary, IsPhantom, physdata, this);
7518 }
7519 return true;
7520 }
7521
7522 private bool HandleObjectImage(IClientAPI sender, Packet Pack)
7523 {
7524 ObjectImagePacket imagePack = (ObjectImagePacket)Pack;
7525
7526 UpdatePrimTexture handlerUpdatePrimTexture = null;
7527 for (int i = 0; i < imagePack.ObjectData.Length; i++)
7528 {
7529 handlerUpdatePrimTexture = OnUpdatePrimTexture;
7530 if (handlerUpdatePrimTexture != null)
7531 {
7532 handlerUpdatePrimTexture(imagePack.ObjectData[i].ObjectLocalID,
7533 imagePack.ObjectData[i].TextureEntry, this);
7534 }
7535 }
7536 return true;
7537 }
7538
7539 private bool HandleObjectGrab(IClientAPI sender, Packet Pack)
7540 {
7541 ObjectGrabPacket grab = (ObjectGrabPacket)Pack;
7542
7543 #region Packet Session and User Check
7544 if (m_checkPackets)
7545 {
7546 if (grab.AgentData.SessionID != SessionId ||
7547 grab.AgentData.AgentID != AgentId)
7548 return true;
7549 }
7550 #endregion
7551
7552 GrabObject handlerGrabObject = OnGrabObject;
7553
7554 if (handlerGrabObject != null)
7555 {
7556 List<SurfaceTouchEventArgs> touchArgs = new List<SurfaceTouchEventArgs>();
7557 if ((grab.SurfaceInfo != null) && (grab.SurfaceInfo.Length > 0))
7558 {
7559 foreach (ObjectGrabPacket.SurfaceInfoBlock surfaceInfo in grab.SurfaceInfo)
7560 {
7561 SurfaceTouchEventArgs arg = new SurfaceTouchEventArgs();
7562 arg.Binormal = surfaceInfo.Binormal;
7563 arg.FaceIndex = surfaceInfo.FaceIndex;
7564 arg.Normal = surfaceInfo.Normal;
7565 arg.Position = surfaceInfo.Position;
7566 arg.STCoord = surfaceInfo.STCoord;
7567 arg.UVCoord = surfaceInfo.UVCoord;
7568 touchArgs.Add(arg);
7569 }
7570 }
7571 handlerGrabObject(grab.ObjectData.LocalID, grab.ObjectData.GrabOffset, this, touchArgs);
7572 }
7573 return true;
7574 }
7575
7576 private bool HandleObjectGrabUpdate(IClientAPI sender, Packet Pack)
7577 {
7578 ObjectGrabUpdatePacket grabUpdate = (ObjectGrabUpdatePacket)Pack;
7579
7580 #region Packet Session and User Check
7581 if (m_checkPackets)
7582 {
7583 if (grabUpdate.AgentData.SessionID != SessionId ||
7584 grabUpdate.AgentData.AgentID != AgentId)
7585 return true;
7586 }
7587 #endregion
7588
7589 MoveObject handlerGrabUpdate = OnGrabUpdate;
7590
7591 if (handlerGrabUpdate != null)
7592 {
7593 List<SurfaceTouchEventArgs> touchArgs = new List<SurfaceTouchEventArgs>();
7594 if ((grabUpdate.SurfaceInfo != null) && (grabUpdate.SurfaceInfo.Length > 0))
7595 {
7596 foreach (ObjectGrabUpdatePacket.SurfaceInfoBlock surfaceInfo in grabUpdate.SurfaceInfo)
7597 {
7598 SurfaceTouchEventArgs arg = new SurfaceTouchEventArgs();
7599 arg.Binormal = surfaceInfo.Binormal;
7600 arg.FaceIndex = surfaceInfo.FaceIndex;
7601 arg.Normal = surfaceInfo.Normal;
7602 arg.Position = surfaceInfo.Position;
7603 arg.STCoord = surfaceInfo.STCoord;
7604 arg.UVCoord = surfaceInfo.UVCoord;
7605 touchArgs.Add(arg);
7606 }
7607 }
7608 handlerGrabUpdate(grabUpdate.ObjectData.ObjectID, grabUpdate.ObjectData.GrabOffsetInitial,
7609 grabUpdate.ObjectData.GrabPosition, this, touchArgs);
7610 }
7611 return true;
7612 }
7613
7614 private bool HandleObjectDeGrab(IClientAPI sender, Packet Pack)
7615 {
7616 ObjectDeGrabPacket deGrab = (ObjectDeGrabPacket)Pack;
7617
7618 #region Packet Session and User Check
7619 if (m_checkPackets)
7620 {
7621 if (deGrab.AgentData.SessionID != SessionId ||
7622 deGrab.AgentData.AgentID != AgentId)
7623 return true;
7624 }
7625 #endregion
7626
7627 DeGrabObject handlerDeGrabObject = OnDeGrabObject;
7628 if (handlerDeGrabObject != null)
7629 {
7630 List<SurfaceTouchEventArgs> touchArgs = new List<SurfaceTouchEventArgs>();
7631 if ((deGrab.SurfaceInfo != null) && (deGrab.SurfaceInfo.Length > 0))
7632 {
7633 foreach (ObjectDeGrabPacket.SurfaceInfoBlock surfaceInfo in deGrab.SurfaceInfo)
7634 {
7635 SurfaceTouchEventArgs arg = new SurfaceTouchEventArgs();
7636 arg.Binormal = surfaceInfo.Binormal;
7637 arg.FaceIndex = surfaceInfo.FaceIndex;
7638 arg.Normal = surfaceInfo.Normal;
7639 arg.Position = surfaceInfo.Position;
7640 arg.STCoord = surfaceInfo.STCoord;
7641 arg.UVCoord = surfaceInfo.UVCoord;
7642 touchArgs.Add(arg);
7643 }
7644 }
7645 handlerDeGrabObject(deGrab.ObjectData.LocalID, this, touchArgs);
7646 }
7647 return true;
7648 }
7649
7650 private bool HandleObjectSpinStart(IClientAPI sender, Packet Pack)
7651 {
7652 //m_log.Warn("[CLIENT]: unhandled ObjectSpinStart packet");
7653 ObjectSpinStartPacket spinStart = (ObjectSpinStartPacket)Pack;
7654
7655 #region Packet Session and User Check
7656 if (m_checkPackets)
7657 {
7658 if (spinStart.AgentData.SessionID != SessionId ||
7659 spinStart.AgentData.AgentID != AgentId)
7660 return true;
7661 }
7662 #endregion
7663
7664 SpinStart handlerSpinStart = OnSpinStart;
7665 if (handlerSpinStart != null)
7666 {
7667 handlerSpinStart(spinStart.ObjectData.ObjectID, this);
7668 }
7669 return true;
7670 }
7671
7672 private bool HandleObjectSpinUpdate(IClientAPI sender, Packet Pack)
7673 {
7674 //m_log.Warn("[CLIENT]: unhandled ObjectSpinUpdate packet");
7675 ObjectSpinUpdatePacket spinUpdate = (ObjectSpinUpdatePacket)Pack;
7676
7677 #region Packet Session and User Check
7678 if (m_checkPackets)
7679 {
7680 if (spinUpdate.AgentData.SessionID != SessionId ||
7681 spinUpdate.AgentData.AgentID != AgentId)
7682 return true;
7683 }
7684 #endregion
7685
7686 Vector3 axis;
7687 float angle;
7688 spinUpdate.ObjectData.Rotation.GetAxisAngle(out axis, out angle);
7689 //m_log.Warn("[CLIENT]: ObjectSpinUpdate packet rot axis:" + axis + " angle:" + angle);
7690
7691 SpinObject handlerSpinUpdate = OnSpinUpdate;
7692 if (handlerSpinUpdate != null)
7693 {
7694 handlerSpinUpdate(spinUpdate.ObjectData.ObjectID, spinUpdate.ObjectData.Rotation, this);
7695 }
7696 return true;
7697 }
7698
7699 private bool HandleObjectSpinStop(IClientAPI sender, Packet Pack)
7700 {
7701 //m_log.Warn("[CLIENT]: unhandled ObjectSpinStop packet");
7702 ObjectSpinStopPacket spinStop = (ObjectSpinStopPacket)Pack;
7703
7704 #region Packet Session and User Check
7705 if (m_checkPackets)
7706 {
7707 if (spinStop.AgentData.SessionID != SessionId ||
7708 spinStop.AgentData.AgentID != AgentId)
7709 return true;
7710 }
7711 #endregion
7712
7713 SpinStop handlerSpinStop = OnSpinStop;
7714 if (handlerSpinStop != null)
7715 {
7716 handlerSpinStop(spinStop.ObjectData.ObjectID, this);
7717 }
7718 return true;
7719 }
7720
7721 private bool HandleObjectDescription(IClientAPI sender, Packet Pack)
7722 {
7723 ObjectDescriptionPacket objDes = (ObjectDescriptionPacket)Pack;
7724
7725 #region Packet Session and User Check
7726 if (m_checkPackets)
7727 {
7728 if (objDes.AgentData.SessionID != SessionId ||
7729 objDes.AgentData.AgentID != AgentId)
7730 return true;
7731 }
7732 #endregion
7733
7734 GenericCall7 handlerObjectDescription = null;
7735
7736 for (int i = 0; i < objDes.ObjectData.Length; i++)
7737 {
7738 handlerObjectDescription = OnObjectDescription;
7739 if (handlerObjectDescription != null)
7740 {
7741 handlerObjectDescription(this, objDes.ObjectData[i].LocalID,
7742 Util.FieldToString(objDes.ObjectData[i].Description));
7743 }
7744 }
7745 return true;
7746 }
7747
7748 private bool HandleObjectName(IClientAPI sender, Packet Pack)
7749 {
7750 ObjectNamePacket objName = (ObjectNamePacket)Pack;
7751
7752 #region Packet Session and User Check
7753 if (m_checkPackets)
7754 {
7755 if (objName.AgentData.SessionID != SessionId ||
7756 objName.AgentData.AgentID != AgentId)
7757 return true;
7758 }
7759 #endregion
7760
7761 GenericCall7 handlerObjectName = null;
7762 for (int i = 0; i < objName.ObjectData.Length; i++)
7763 {
7764 handlerObjectName = OnObjectName;
7765 if (handlerObjectName != null)
7766 {
7767 handlerObjectName(this, objName.ObjectData[i].LocalID,
7768 Util.FieldToString(objName.ObjectData[i].Name));
7769 }
7770 }
7771 return true;
7772 }
7773
7774 private bool HandleObjectPermissions(IClientAPI sender, Packet Pack)
7775 {
7776 if (OnObjectPermissions != null)
7777 {
7778 ObjectPermissionsPacket newobjPerms = (ObjectPermissionsPacket)Pack;
7779
7780 #region Packet Session and User Check
7781 if (m_checkPackets)
7782 {
7783 if (newobjPerms.AgentData.SessionID != SessionId ||
7784 newobjPerms.AgentData.AgentID != AgentId)
7785 return true;
7786 }
7787 #endregion
7788
7789 UUID AgentID = newobjPerms.AgentData.AgentID;
7790 UUID SessionID = newobjPerms.AgentData.SessionID;
7791
7792 ObjectPermissions handlerObjectPermissions = null;
7793
7794 for (int i = 0; i < newobjPerms.ObjectData.Length; i++)
7795 {
7796 ObjectPermissionsPacket.ObjectDataBlock permChanges = newobjPerms.ObjectData[i];
7797
7798 byte field = permChanges.Field;
7799 uint localID = permChanges.ObjectLocalID;
7800 uint mask = permChanges.Mask;
7801 byte set = permChanges.Set;
7802
7803 handlerObjectPermissions = OnObjectPermissions;
7804
7805 if (handlerObjectPermissions != null)
7806 handlerObjectPermissions(this, AgentID, SessionID, field, localID, mask, set);
7807 }
7808 }
7809
7810 // Here's our data,
7811 // PermField contains the field the info goes into
7812 // PermField determines which mask we're changing
7813 //
7814 // chmask is the mask of the change
7815 // setTF is whether we're adding it or taking it away
7816 //
7817 // objLocalID is the localID of the object.
7818
7819 // Unfortunately, we have to pass the event the packet because objData is an array
7820 // That means multiple object perms may be updated in a single packet.
7821
7822 return true;
7823 }
7824
7825 private bool HandleUndo(IClientAPI sender, Packet Pack)
7826 {
7827 UndoPacket undoitem = (UndoPacket)Pack;
7828
7829 #region Packet Session and User Check
7830 if (m_checkPackets)
7831 {
7832 if (undoitem.AgentData.SessionID != SessionId ||
7833 undoitem.AgentData.AgentID != AgentId)
7834 return true;
7835 }
7836 #endregion
7837
7838 if (undoitem.ObjectData.Length > 0)
7839 {
7840 for (int i = 0; i < undoitem.ObjectData.Length; i++)
7841 {
7842 UUID objiD = undoitem.ObjectData[i].ObjectID;
7843 AgentSit handlerOnUndo = OnUndo;
7844 if (handlerOnUndo != null)
7845 {
7846 handlerOnUndo(this, objiD);
7847 }
7848
7849 }
7850 }
7851 return true;
7852 }
7853
7854 private bool HandleLandUndo(IClientAPI sender, Packet Pack)
7855 {
7856 UndoLandPacket undolanditem = (UndoLandPacket)Pack;
7857
7858 #region Packet Session and User Check
7859 if (m_checkPackets)
7860 {
7861 if (undolanditem.AgentData.SessionID != SessionId ||
7862 undolanditem.AgentData.AgentID != AgentId)
7863 return true;
7864 }
7865 #endregion
7866
7867 LandUndo handlerOnUndo = OnLandUndo;
7868 if (handlerOnUndo != null)
7869 {
7870 handlerOnUndo(this);
7871 }
7872 return true;
7873 }
7874
7875 private bool HandleRedo(IClientAPI sender, Packet Pack)
7876 {
7877 RedoPacket redoitem = (RedoPacket)Pack;
7878
7879 #region Packet Session and User Check
7880 if (m_checkPackets)
7881 {
7882 if (redoitem.AgentData.SessionID != SessionId ||
7883 redoitem.AgentData.AgentID != AgentId)
7884 return true;
7885 }
7886 #endregion
7887
7888 if (redoitem.ObjectData.Length > 0)
7889 {
7890 for (int i = 0; i < redoitem.ObjectData.Length; i++)
7891 {
7892 UUID objiD = redoitem.ObjectData[i].ObjectID;
7893 AgentSit handlerOnRedo = OnRedo;
7894 if (handlerOnRedo != null)
7895 {
7896 handlerOnRedo(this, objiD);
7897 }
7898
7899 }
7900 }
7901 return true;
7902 }
7903
7904 private bool HandleObjectDuplicateOnRay(IClientAPI sender, Packet Pack)
7905 {
7906 ObjectDuplicateOnRayPacket dupeOnRay = (ObjectDuplicateOnRayPacket)Pack;
7907
7908 #region Packet Session and User Check
7909 if (m_checkPackets)
7910 {
7911 if (dupeOnRay.AgentData.SessionID != SessionId ||
7912 dupeOnRay.AgentData.AgentID != AgentId)
7913 return true;
7914 }
7915 #endregion
7916
7917 ObjectDuplicateOnRay handlerObjectDuplicateOnRay = null;
7918
7919 for (int i = 0; i < dupeOnRay.ObjectData.Length; i++)
7920 {
7921 handlerObjectDuplicateOnRay = OnObjectDuplicateOnRay;
7922 if (handlerObjectDuplicateOnRay != null)
7923 {
7924 handlerObjectDuplicateOnRay(dupeOnRay.ObjectData[i].ObjectLocalID, dupeOnRay.AgentData.DuplicateFlags,
7925 AgentId, ActiveGroupId, dupeOnRay.AgentData.RayTargetID, dupeOnRay.AgentData.RayEnd,
7926 dupeOnRay.AgentData.RayStart, dupeOnRay.AgentData.BypassRaycast, dupeOnRay.AgentData.RayEndIsIntersection,
7927 dupeOnRay.AgentData.CopyCenters, dupeOnRay.AgentData.CopyRotates);
7928 }
7929 }
7930
7931 return true;
7932 }
7933
7934 private bool HandleRequestObjectPropertiesFamily(IClientAPI sender, Packet Pack)
7935 {
7936 //This powers the little tooltip that appears when you move your mouse over an object
7937 RequestObjectPropertiesFamilyPacket packToolTip = (RequestObjectPropertiesFamilyPacket)Pack;
7938
7939 #region Packet Session and User Check
7940 if (m_checkPackets)
7941 {
7942 if (packToolTip.AgentData.SessionID != SessionId ||
7943 packToolTip.AgentData.AgentID != AgentId)
7944 return true;
7945 }
7946 #endregion
7947
7948 RequestObjectPropertiesFamilyPacket.ObjectDataBlock packObjBlock = packToolTip.ObjectData;
7949
7950 RequestObjectPropertiesFamily handlerRequestObjectPropertiesFamily = OnRequestObjectPropertiesFamily;
7951
7952 if (handlerRequestObjectPropertiesFamily != null)
7953 {
7954 handlerRequestObjectPropertiesFamily(this, m_agentId, packObjBlock.RequestFlags,
7955 packObjBlock.ObjectID);
7956 }
7957
7958 return true;
7959 }
7960
7961 private bool HandleObjectIncludeInSearch(IClientAPI sender, Packet Pack)
7962 {
7963 //This lets us set objects to appear in search (stuff like DataSnapshot, etc)
7964 ObjectIncludeInSearchPacket packInSearch = (ObjectIncludeInSearchPacket)Pack;
7965 ObjectIncludeInSearch handlerObjectIncludeInSearch = null;
7966
7967 #region Packet Session and User Check
7968 if (m_checkPackets)
7969 {
7970 if (packInSearch.AgentData.SessionID != SessionId ||
7971 packInSearch.AgentData.AgentID != AgentId)
7972 return true;
7973 }
7974 #endregion
7975
7976 foreach (ObjectIncludeInSearchPacket.ObjectDataBlock objData in packInSearch.ObjectData)
7977 {
7978 bool inSearch = objData.IncludeInSearch;
7979 uint localID = objData.ObjectLocalID;
7980
7981 handlerObjectIncludeInSearch = OnObjectIncludeInSearch;
7982
7983 if (handlerObjectIncludeInSearch != null)
7984 {
7985 handlerObjectIncludeInSearch(this, inSearch, localID);
7986 }
7987 }
7988 return true;
7989 }
7990
7991 private bool HandleScriptAnswerYes(IClientAPI sender, Packet Pack)
7992 {
7993 ScriptAnswerYesPacket scriptAnswer = (ScriptAnswerYesPacket)Pack;
7994
7995 #region Packet Session and User Check
7996 if (m_checkPackets)
7997 {
7998 if (scriptAnswer.AgentData.SessionID != SessionId ||
7999 scriptAnswer.AgentData.AgentID != AgentId)
8000 return true;
8001 }
8002 #endregion
8003
8004 ScriptAnswer handlerScriptAnswer = OnScriptAnswer;
8005 if (handlerScriptAnswer != null)
8006 {
8007 handlerScriptAnswer(this, scriptAnswer.Data.TaskID, scriptAnswer.Data.ItemID, scriptAnswer.Data.Questions);
8008 }
8009 return true;
8010 }
8011
8012 private bool HandleObjectClickAction(IClientAPI sender, Packet Pack)
8013 {
8014 ObjectClickActionPacket ocpacket = (ObjectClickActionPacket)Pack;
8015
8016 #region Packet Session and User Check
8017 if (m_checkPackets)
8018 {
8019 if (ocpacket.AgentData.SessionID != SessionId ||
8020 ocpacket.AgentData.AgentID != AgentId)
8021 return true;
8022 }
8023 #endregion
8024
8025 GenericCall7 handlerObjectClickAction = OnObjectClickAction;
8026 if (handlerObjectClickAction != null)
8027 {
8028 foreach (ObjectClickActionPacket.ObjectDataBlock odata in ocpacket.ObjectData)
8029 {
8030 byte action = odata.ClickAction;
8031 uint localID = odata.ObjectLocalID;
8032 handlerObjectClickAction(this, localID, action.ToString());
8033 }
8034 }
8035 return true;
8036 }
8037
8038 private bool HandleObjectMaterial(IClientAPI sender, Packet Pack)
8039 {
8040 ObjectMaterialPacket ompacket = (ObjectMaterialPacket)Pack;
8041
8042 #region Packet Session and User Check
8043 if (m_checkPackets)
8044 {
8045 if (ompacket.AgentData.SessionID != SessionId ||
8046 ompacket.AgentData.AgentID != AgentId)
8047 return true;
8048 }
8049 #endregion
8050
8051 GenericCall7 handlerObjectMaterial = OnObjectMaterial;
8052 if (handlerObjectMaterial != null)
8053 {
8054 foreach (ObjectMaterialPacket.ObjectDataBlock odata in ompacket.ObjectData)
8055 {
8056 byte material = odata.Material;
8057 uint localID = odata.ObjectLocalID;
8058 handlerObjectMaterial(this, localID, material.ToString());
8059 }
8060 }
8061 return true;
8062 }
8063
8064 #endregion Objects/m_sceneObjects
8065
8066 #region Inventory/Asset/Other related packets
8067
8068 private bool HandleRequestImage(IClientAPI sender, Packet Pack)
8069 {
8070 RequestImagePacket imageRequest = (RequestImagePacket)Pack;
8071 //m_log.Debug("image request: " + Pack.ToString());
8072
8073 #region Packet Session and User Check
8074 if (m_checkPackets)
8075 {
8076 if (imageRequest.AgentData.SessionID != SessionId ||
8077 imageRequest.AgentData.AgentID != AgentId)
8078 return true;
8079 }
8080 #endregion
8081
8082 //handlerTextureRequest = null;
8083 for (int i = 0; i < imageRequest.RequestImage.Length; i++)
8084 {
8085 TextureRequestArgs args = new TextureRequestArgs();
8086
8087 RequestImagePacket.RequestImageBlock block = imageRequest.RequestImage[i];
8088
8089 args.RequestedAssetID = block.Image;
8090 args.DiscardLevel = block.DiscardLevel;
8091 args.PacketNumber = block.Packet;
8092 args.Priority = block.DownloadPriority;
8093 args.requestSequence = imageRequest.Header.Sequence;
8094
8095 // NOTE: This is not a built in part of the LLUDP protocol, but we double the
8096 // priority of avatar textures to get avatars rezzing in faster than the
8097 // surrounding scene
8098 if ((ImageType)block.Type == ImageType.Baked)
8099 args.Priority *= 2.0f;
8100
8101 ImageManager.EnqueueReq(args);
8102 }
8103
8104 return true;
8105 }
8106
8107 /// <summary>
8108 /// This is the entry point for the UDP route by which the client can retrieve asset data. If the request
8109 /// is successful then a TransferInfo packet will be sent back, followed by one or more TransferPackets
8110 /// </summary>
8111 /// <param name="sender"></param>
8112 /// <param name="Pack"></param>
8113 /// <returns>This parameter may be ignored since we appear to return true whatever happens</returns>
8114 private bool HandleTransferRequest(IClientAPI sender, Packet Pack)
8115 {
8116 //m_log.Debug("ClientView.ProcessPackets.cs:ProcessInPacket() - Got transfer request");
8117
8118 TransferRequestPacket transfer = (TransferRequestPacket)Pack;
8119 UUID taskID = UUID.Zero;
8120 if (transfer.TransferInfo.SourceType == (int)SourceType.SimInventoryItem)
8121 {
8122 if (!(((Scene)m_scene).Permissions.BypassPermissions()))
8123 {
8124 // We're spawning a thread because the permissions check can block this thread
8125 Util.FireAndForget(delegate
8126 {
8127 // This requests the asset if needed
8128 HandleSimInventoryTransferRequestWithPermsCheck(sender, transfer);
8129 }, null, "LLClientView.HandleTransferRequest");
8130
8131 return true;
8132 }
8133 }
8134 else if (transfer.TransferInfo.SourceType == (int)SourceType.SimEstate)
8135 {
8136 //TransferRequestPacket does not include covenant uuid?
8137 //get scene covenant uuid
8138 taskID = m_scene.RegionInfo.RegionSettings.Covenant;
8139 }
8140
8141 // This is non-blocking
8142 MakeAssetRequest(transfer, taskID);
8143
8144 return true;
8145 }
8146
8147 private void HandleSimInventoryTransferRequestWithPermsCheck(IClientAPI sender, TransferRequestPacket transfer)
8148 {
8149 UUID taskID = new UUID(transfer.TransferInfo.Params, 48);
8150 UUID itemID = new UUID(transfer.TransferInfo.Params, 64);
8151 UUID requestID = new UUID(transfer.TransferInfo.Params, 80);
8152
8153 //m_log.DebugFormat(
8154 // "[CLIENT]: Got request for asset {0} from item {1} in prim {2} by {3}",
8155 // requestID, itemID, taskID, Name);
8156
8157 //m_log.Debug("Transfer Request: " + transfer.ToString());
8158 // Validate inventory transfers
8159 // Has to be done here, because AssetCache can't do it
8160 //
8161 if (taskID != UUID.Zero) // Prim
8162 {
8163 SceneObjectPart part = ((Scene)m_scene).GetSceneObjectPart(taskID);
8164
8165 if (part == null)
8166 {
8167 m_log.WarnFormat(
8168 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but prim does not exist",
8169 Name, requestID, itemID, taskID);
8170 return;
8171 }
8172
8173 TaskInventoryItem tii = part.Inventory.GetInventoryItem(itemID);
8174 if (tii == null)
8175 {
8176 m_log.WarnFormat(
8177 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item does not exist",
8178 Name, requestID, itemID, taskID);
8179 return;
8180 }
8181
8182 if (tii.Type == (int)AssetType.LSLText)
8183 {
8184 if (!((Scene)m_scene).Permissions.CanEditScript(itemID, taskID, AgentId))
8185 return;
8186 }
8187 else if (tii.Type == (int)AssetType.Notecard)
8188 {
8189 if (!((Scene)m_scene).Permissions.CanEditNotecard(itemID, taskID, AgentId))
8190 return;
8191 }
8192 else
8193 {
8194 // TODO: Change this code to allow items other than notecards and scripts to be successfully
8195 // shared with group. In fact, this whole block of permissions checking should move to an IPermissionsModule
8196 if (part.OwnerID != AgentId)
8197 {
8198 m_log.WarnFormat(
8199 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the prim is owned by {4}",
8200 Name, requestID, itemID, taskID, part.OwnerID);
8201 return;
8202 }
8203
8204 if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0)
8205 {
8206 m_log.WarnFormat(
8207 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but modify permissions are not set",
8208 Name, requestID, itemID, taskID);
8209 return;
8210 }
8211
8212 if (tii.OwnerID != AgentId)
8213 {
8214 m_log.WarnFormat(
8215 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the item is owned by {4}",
8216 Name, requestID, itemID, taskID, tii.OwnerID);
8217 return;
8218 }
8219
8220 if ((
8221 tii.CurrentPermissions & ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer))
8222 != ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer))
8223 {
8224 m_log.WarnFormat(
8225 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item permissions are not modify/copy/transfer",
8226 Name, requestID, itemID, taskID);
8227 return;
8228 }
8229
8230 if (tii.AssetID != requestID)
8231 {
8232 m_log.WarnFormat(
8233 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but this does not match item's asset {4}",
8234 Name, requestID, itemID, taskID, tii.AssetID);
8235 return;
8236 }
8237 }
8238 }
8239 else // Agent
8240 {
8241 IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>();
8242 if (invAccess != null)
8243 {
8244 if (!invAccess.CanGetAgentInventoryItem(this, itemID, requestID))
8245 return;
8246 }
8247 else
8248 {
8249 return;
8250 }
8251 }
8252
8253 // Permissions out of the way, let's request the asset
8254 MakeAssetRequest(transfer, taskID);
8255
8256 }
8257
8258
8259 private bool HandleAssetUploadRequest(IClientAPI sender, Packet Pack)
8260 {
8261 AssetUploadRequestPacket request = (AssetUploadRequestPacket)Pack;
8262
8263 // m_log.Debug("upload request " + request.ToString());
8264 // m_log.Debug("upload request was for assetid: " + request.AssetBlock.TransactionID.Combine(this.SecureSessionId).ToString());
8265 UUID temp = UUID.Combine(request.AssetBlock.TransactionID, SecureSessionId);
8266
8267 UDPAssetUploadRequest handlerAssetUploadRequest = OnAssetUploadRequest;
8268
8269 if (handlerAssetUploadRequest != null)
8270 {
8271 handlerAssetUploadRequest(this, temp,
8272 request.AssetBlock.TransactionID, request.AssetBlock.Type,
8273 request.AssetBlock.AssetData, request.AssetBlock.StoreLocal,
8274 request.AssetBlock.Tempfile);
8275 }
8276 return true;
8277 }
8278
8279 private bool HandleRequestXfer(IClientAPI sender, Packet Pack)
8280 {
8281 RequestXferPacket xferReq = (RequestXferPacket)Pack;
8282
8283 RequestXfer handlerRequestXfer = OnRequestXfer;
8284
8285 if (handlerRequestXfer != null)
8286 {
8287 handlerRequestXfer(this, xferReq.XferID.ID, Util.FieldToString(xferReq.XferID.Filename));
8288 }
8289 return true;
8290 }
8291
8292 private bool HandleSendXferPacket(IClientAPI sender, Packet Pack)
8293 {
8294 SendXferPacketPacket xferRec = (SendXferPacketPacket)Pack;
8295
8296 XferReceive handlerXferReceive = OnXferReceive;
8297 if (handlerXferReceive != null)
8298 {
8299 handlerXferReceive(this, xferRec.XferID.ID, xferRec.XferID.Packet, xferRec.DataPacket.Data);
8300 }
8301 return true;
8302 }
8303
8304 private bool HandleConfirmXferPacket(IClientAPI sender, Packet Pack)
8305 {
8306 ConfirmXferPacketPacket confirmXfer = (ConfirmXferPacketPacket)Pack;
8307
8308 ConfirmXfer handlerConfirmXfer = OnConfirmXfer;
8309 if (handlerConfirmXfer != null)
8310 {
8311 handlerConfirmXfer(this, confirmXfer.XferID.ID, confirmXfer.XferID.Packet);
8312 }
8313 return true;
8314 }
8315
8316 private bool HandleAbortXfer(IClientAPI sender, Packet Pack)
8317 {
8318 AbortXferPacket abortXfer = (AbortXferPacket)Pack;
8319 AbortXfer handlerAbortXfer = OnAbortXfer;
8320 if (handlerAbortXfer != null)
8321 {
8322 handlerAbortXfer(this, abortXfer.XferID.ID);
8323 }
8324
8325 return true;
8326 }
8327
8328 private bool HandleCreateInventoryFolder(IClientAPI sender, Packet Pack)
8329 {
8330 CreateInventoryFolderPacket invFolder = (CreateInventoryFolderPacket)Pack;
8331
8332 #region Packet Session and User Check
8333 if (m_checkPackets)
8334 {
8335 if (invFolder.AgentData.SessionID != SessionId ||
8336 invFolder.AgentData.AgentID != AgentId)
8337 return true;
8338 }
8339 #endregion
8340
8341 CreateInventoryFolder handlerCreateInventoryFolder = OnCreateNewInventoryFolder;
8342 if (handlerCreateInventoryFolder != null)
8343 {
8344 handlerCreateInventoryFolder(this, invFolder.FolderData.FolderID,
8345 (ushort)invFolder.FolderData.Type,
8346 Util.FieldToString(invFolder.FolderData.Name),
8347 invFolder.FolderData.ParentID);
8348 }
8349 return true;
8350 }
8351
8352 private bool HandleUpdateInventoryFolder(IClientAPI sender, Packet Pack)
8353 {
8354 if (OnUpdateInventoryFolder != null)
8355 {
8356 UpdateInventoryFolderPacket invFolderx = (UpdateInventoryFolderPacket)Pack;
8357
8358 #region Packet Session and User Check
8359 if (m_checkPackets)
8360 {
8361 if (invFolderx.AgentData.SessionID != SessionId ||
8362 invFolderx.AgentData.AgentID != AgentId)
8363 return true;
8364 }
8365 #endregion
8366
8367 UpdateInventoryFolder handlerUpdateInventoryFolder = null;
8368
8369 for (int i = 0; i < invFolderx.FolderData.Length; i++)
8370 {
8371 handlerUpdateInventoryFolder = OnUpdateInventoryFolder;
8372 if (handlerUpdateInventoryFolder != null)
8373 {
8374 OnUpdateInventoryFolder(this, invFolderx.FolderData[i].FolderID,
8375 (ushort)invFolderx.FolderData[i].Type,
8376 Util.FieldToString(invFolderx.FolderData[i].Name),
8377 invFolderx.FolderData[i].ParentID);
8378 }
8379 }
8380 }
8381 return true;
8382 }
8383
8384 private bool HandleMoveInventoryFolder(IClientAPI sender, Packet Pack)
8385 {
8386 if (OnMoveInventoryFolder != null)
8387 {
8388 MoveInventoryFolderPacket invFoldery = (MoveInventoryFolderPacket)Pack;
8389
8390 #region Packet Session and User Check
8391 if (m_checkPackets)
8392 {
8393 if (invFoldery.AgentData.SessionID != SessionId ||
8394 invFoldery.AgentData.AgentID != AgentId)
8395 return true;
8396 }
8397 #endregion
8398
8399 MoveInventoryFolder handlerMoveInventoryFolder = null;
8400
8401 for (int i = 0; i < invFoldery.InventoryData.Length; i++)
8402 {
8403 handlerMoveInventoryFolder = OnMoveInventoryFolder;
8404 if (handlerMoveInventoryFolder != null)
8405 {
8406 OnMoveInventoryFolder(this, invFoldery.InventoryData[i].FolderID,
8407 invFoldery.InventoryData[i].ParentID);
8408 }
8409 }
8410 }
8411 return true;
8412 }
8413
8414 private bool HandleCreateInventoryItem(IClientAPI sender, Packet Pack)
8415 {
8416 CreateInventoryItemPacket createItem = (CreateInventoryItemPacket)Pack;
8417
8418 #region Packet Session and User Check
8419 if (m_checkPackets)
8420 {
8421 if (createItem.AgentData.SessionID != SessionId ||
8422 createItem.AgentData.AgentID != AgentId)
8423 return true;
8424 }
8425 #endregion
8426
8427 CreateNewInventoryItem handlerCreateNewInventoryItem = OnCreateNewInventoryItem;
8428 if (handlerCreateNewInventoryItem != null)
8429 {
8430 handlerCreateNewInventoryItem(this, createItem.InventoryBlock.TransactionID,
8431 createItem.InventoryBlock.FolderID,
8432 createItem.InventoryBlock.CallbackID,
8433 Util.FieldToString(createItem.InventoryBlock.Description),
8434 Util.FieldToString(createItem.InventoryBlock.Name),
8435 createItem.InventoryBlock.InvType,
8436 createItem.InventoryBlock.Type,
8437 createItem.InventoryBlock.WearableType,
8438 createItem.InventoryBlock.NextOwnerMask,
8439 Util.UnixTimeSinceEpoch());
8440 }
8441 return true;
8442 }
8443
8444 private bool HandleLinkInventoryItem(IClientAPI sender, Packet Pack)
8445 {
8446 LinkInventoryItemPacket createLink = (LinkInventoryItemPacket)Pack;
8447
8448 #region Packet Session and User Check
8449 if (m_checkPackets)
8450 {
8451 if (createLink.AgentData.SessionID != SessionId ||
8452 createLink.AgentData.AgentID != AgentId)
8453 return true;
8454 }
8455 #endregion
8456
8457 LinkInventoryItem linkInventoryItem = OnLinkInventoryItem;
8458
8459 if (linkInventoryItem != null)
8460 {
8461 linkInventoryItem(
8462 this,
8463 createLink.InventoryBlock.TransactionID,
8464 createLink.InventoryBlock.FolderID,
8465 createLink.InventoryBlock.CallbackID,
8466 Util.FieldToString(createLink.InventoryBlock.Description),
8467 Util.FieldToString(createLink.InventoryBlock.Name),
8468 createLink.InventoryBlock.InvType,
8469 createLink.InventoryBlock.Type,
8470 createLink.InventoryBlock.OldItemID);
8471 }
8472
8473 return true;
8474 }
8475
8476 private bool HandleFetchInventory(IClientAPI sender, Packet Pack)
8477 {
8478 if (OnFetchInventory != null)
8479 {
8480 FetchInventoryPacket FetchInventoryx = (FetchInventoryPacket)Pack;
8481
8482 #region Packet Session and User Check
8483 if (m_checkPackets)
8484 {
8485 if (FetchInventoryx.AgentData.SessionID != SessionId ||
8486 FetchInventoryx.AgentData.AgentID != AgentId)
8487 return true;
8488 }
8489 #endregion
8490
8491 FetchInventory handlerFetchInventory = null;
8492
8493 for (int i = 0; i < FetchInventoryx.InventoryData.Length; i++)
8494 {
8495 handlerFetchInventory = OnFetchInventory;
8496
8497 if (handlerFetchInventory != null)
8498 {
8499 OnFetchInventory(this, FetchInventoryx.InventoryData[i].ItemID,
8500 FetchInventoryx.InventoryData[i].OwnerID);
8501 }
8502 }
8503 }
8504 return true;
8505 }
8506
8507 private bool HandleFetchInventoryDescendents(IClientAPI sender, Packet Pack)
8508 {
8509 FetchInventoryDescendentsPacket Fetch = (FetchInventoryDescendentsPacket)Pack;
8510
8511 #region Packet Session and User Check
8512 if (m_checkPackets)
8513 {
8514 if (Fetch.AgentData.SessionID != SessionId ||
8515 Fetch.AgentData.AgentID != AgentId)
8516 return true;
8517 }
8518 #endregion
8519
8520 FetchInventoryDescendents handlerFetchInventoryDescendents = OnFetchInventoryDescendents;
8521 if (handlerFetchInventoryDescendents != null)
8522 {
8523 handlerFetchInventoryDescendents(this, Fetch.InventoryData.FolderID, Fetch.InventoryData.OwnerID,
8524 Fetch.InventoryData.FetchFolders, Fetch.InventoryData.FetchItems,
8525 Fetch.InventoryData.SortOrder);
8526 }
8527 return true;
8528 }
8529
8530 private bool HandlePurgeInventoryDescendents(IClientAPI sender, Packet Pack)
8531 {
8532 PurgeInventoryDescendentsPacket Purge = (PurgeInventoryDescendentsPacket)Pack;
8533
8534 #region Packet Session and User Check
8535 if (m_checkPackets)
8536 {
8537 if (Purge.AgentData.SessionID != SessionId ||
8538 Purge.AgentData.AgentID != AgentId)
8539 return true;
8540 }
8541 #endregion
8542
8543 PurgeInventoryDescendents handlerPurgeInventoryDescendents = OnPurgeInventoryDescendents;
8544 if (handlerPurgeInventoryDescendents != null)
8545 {
8546 handlerPurgeInventoryDescendents(this, Purge.InventoryData.FolderID);
8547 }
8548 return true;
8549 }
8550
8551 private bool HandleUpdateInventoryItem(IClientAPI sender, Packet Pack)
8552 {
8553 UpdateInventoryItemPacket inventoryItemUpdate = (UpdateInventoryItemPacket)Pack;
8554
8555 #region Packet Session and User Check
8556 if (m_checkPackets)
8557 {
8558 if (inventoryItemUpdate.AgentData.SessionID != SessionId ||
8559 inventoryItemUpdate.AgentData.AgentID != AgentId)
8560 return true;
8561 }
8562 #endregion
8563
8564 if (OnUpdateInventoryItem != null)
8565 {
8566 UpdateInventoryItem handlerUpdateInventoryItem = null;
8567 for (int i = 0; i < inventoryItemUpdate.InventoryData.Length; i++)
8568 {
8569 handlerUpdateInventoryItem = OnUpdateInventoryItem;
8570
8571 if (handlerUpdateInventoryItem != null)
8572 {
8573 InventoryItemBase itemUpd = new InventoryItemBase();
8574 itemUpd.ID = inventoryItemUpdate.InventoryData[i].ItemID;
8575 itemUpd.Name = Util.FieldToString(inventoryItemUpdate.InventoryData[i].Name);
8576 itemUpd.Description = Util.FieldToString(inventoryItemUpdate.InventoryData[i].Description);
8577 itemUpd.GroupID = inventoryItemUpdate.InventoryData[i].GroupID;
8578 itemUpd.GroupOwned = inventoryItemUpdate.InventoryData[i].GroupOwned;
8579 itemUpd.GroupPermissions = inventoryItemUpdate.InventoryData[i].GroupMask;
8580 itemUpd.NextPermissions = inventoryItemUpdate.InventoryData[i].NextOwnerMask;
8581 itemUpd.EveryOnePermissions = inventoryItemUpdate.InventoryData[i].EveryoneMask;
8582 itemUpd.CreationDate = inventoryItemUpdate.InventoryData[i].CreationDate;
8583 itemUpd.Folder = inventoryItemUpdate.InventoryData[i].FolderID;
8584 itemUpd.InvType = inventoryItemUpdate.InventoryData[i].InvType;
8585 itemUpd.SalePrice = inventoryItemUpdate.InventoryData[i].SalePrice;
8586 itemUpd.SaleType = inventoryItemUpdate.InventoryData[i].SaleType;
8587 itemUpd.Flags = inventoryItemUpdate.InventoryData[i].Flags;
8588
8589 OnUpdateInventoryItem(this, inventoryItemUpdate.InventoryData[i].TransactionID,
8590 inventoryItemUpdate.InventoryData[i].ItemID,
8591 itemUpd);
8592 }
8593 }
8594 }
8595 return true;
8596 }
8597
8598 private bool HandleCopyInventoryItem(IClientAPI sender, Packet Pack)
8599 {
8600 CopyInventoryItemPacket copyitem = (CopyInventoryItemPacket)Pack;
8601
8602 #region Packet Session and User Check
8603 if (m_checkPackets)
8604 {
8605 if (copyitem.AgentData.SessionID != SessionId ||
8606 copyitem.AgentData.AgentID != AgentId)
8607 return true;
8608 }
8609 #endregion
8610
8611 CopyInventoryItem handlerCopyInventoryItem = null;
8612 if (OnCopyInventoryItem != null)
8613 {
8614 foreach (CopyInventoryItemPacket.InventoryDataBlock datablock in copyitem.InventoryData)
8615 {
8616 handlerCopyInventoryItem = OnCopyInventoryItem;
8617 if (handlerCopyInventoryItem != null)
8618 {
8619 handlerCopyInventoryItem(this, datablock.CallbackID, datablock.OldAgentID,
8620 datablock.OldItemID, datablock.NewFolderID,
8621 Util.FieldToString(datablock.NewName));
8622 }
8623 }
8624 }
8625 return true;
8626 }
8627
8628 private bool HandleMoveInventoryItem(IClientAPI sender, Packet Pack)
8629 {
8630 MoveInventoryItemPacket moveitem = (MoveInventoryItemPacket)Pack;
8631
8632 #region Packet Session and User Check
8633 if (m_checkPackets)
8634 {
8635 if (moveitem.AgentData.SessionID != SessionId ||
8636 moveitem.AgentData.AgentID != AgentId)
8637 return true;
8638 }
8639 #endregion
8640
8641 if (OnMoveInventoryItem != null)
8642 {
8643 MoveInventoryItem handlerMoveInventoryItem = null;
8644 InventoryItemBase itm = null;
8645 List<InventoryItemBase> items = new List<InventoryItemBase>();
8646 foreach (MoveInventoryItemPacket.InventoryDataBlock datablock in moveitem.InventoryData)
8647 {
8648 itm = new InventoryItemBase(datablock.ItemID, AgentId);
8649 itm.Folder = datablock.FolderID;
8650 itm.Name = Util.FieldToString(datablock.NewName);
8651 // weird, comes out as empty string
8652 //m_log.DebugFormat("[XXX] new name: {0}", itm.Name);
8653 items.Add(itm);
8654 }
8655 handlerMoveInventoryItem = OnMoveInventoryItem;
8656 if (handlerMoveInventoryItem != null)
8657 {
8658 handlerMoveInventoryItem(this, items);
8659 }
8660 }
8661 return true;
8662 }
8663
8664 private bool HandleRemoveInventoryItem(IClientAPI sender, Packet Pack)
8665 {
8666 RemoveInventoryItemPacket removeItem = (RemoveInventoryItemPacket)Pack;
8667
8668 #region Packet Session and User Check
8669 if (m_checkPackets)
8670 {
8671 if (removeItem.AgentData.SessionID != SessionId ||
8672 removeItem.AgentData.AgentID != AgentId)
8673 return true;
8674 }
8675 #endregion
8676
8677 if (OnRemoveInventoryItem != null)
8678 {
8679 RemoveInventoryItem handlerRemoveInventoryItem = null;
8680 List<UUID> uuids = new List<UUID>();
8681 foreach (RemoveInventoryItemPacket.InventoryDataBlock datablock in removeItem.InventoryData)
8682 {
8683 uuids.Add(datablock.ItemID);
8684 }
8685 handlerRemoveInventoryItem = OnRemoveInventoryItem;
8686 if (handlerRemoveInventoryItem != null)
8687 {
8688 handlerRemoveInventoryItem(this, uuids);
8689 }
8690
8691 }
8692 return true;
8693 }
8694
8695 private bool HandleRemoveInventoryFolder(IClientAPI sender, Packet Pack)
8696 {
8697 RemoveInventoryFolderPacket removeFolder = (RemoveInventoryFolderPacket)Pack;
8698
8699 #region Packet Session and User Check
8700 if (m_checkPackets)
8701 {
8702 if (removeFolder.AgentData.SessionID != SessionId ||
8703 removeFolder.AgentData.AgentID != AgentId)
8704 return true;
8705 }
8706 #endregion
8707
8708 if (OnRemoveInventoryFolder != null)
8709 {
8710 RemoveInventoryFolder handlerRemoveInventoryFolder = null;
8711 List<UUID> uuids = new List<UUID>();
8712 foreach (RemoveInventoryFolderPacket.FolderDataBlock datablock in removeFolder.FolderData)
8713 {
8714 uuids.Add(datablock.FolderID);
8715 }
8716 handlerRemoveInventoryFolder = OnRemoveInventoryFolder;
8717 if (handlerRemoveInventoryFolder != null)
8718 {
8719 handlerRemoveInventoryFolder(this, uuids);
8720 }
8721 }
8722 return true;
8723 }
8724
8725 private bool HandleRemoveInventoryObjects(IClientAPI sender, Packet Pack)
8726 {
8727 RemoveInventoryObjectsPacket removeObject = (RemoveInventoryObjectsPacket)Pack;
8728 #region Packet Session and User Check
8729 if (m_checkPackets)
8730 {
8731 if (removeObject.AgentData.SessionID != SessionId ||
8732 removeObject.AgentData.AgentID != AgentId)
8733 return true;
8734 }
8735 #endregion
8736 if (OnRemoveInventoryFolder != null)
8737 {
8738 RemoveInventoryFolder handlerRemoveInventoryFolder = null;
8739 List<UUID> uuids = new List<UUID>();
8740 foreach (RemoveInventoryObjectsPacket.FolderDataBlock datablock in removeObject.FolderData)
8741 {
8742 uuids.Add(datablock.FolderID);
8743 }
8744 handlerRemoveInventoryFolder = OnRemoveInventoryFolder;
8745 if (handlerRemoveInventoryFolder != null)
8746 {
8747 handlerRemoveInventoryFolder(this, uuids);
8748 }
8749 }
8750
8751 if (OnRemoveInventoryItem != null)
8752 {
8753 RemoveInventoryItem handlerRemoveInventoryItem = null;
8754 List<UUID> uuids = new List<UUID>();
8755 foreach (RemoveInventoryObjectsPacket.ItemDataBlock datablock in removeObject.ItemData)
8756 {
8757 uuids.Add(datablock.ItemID);
8758 }
8759 handlerRemoveInventoryItem = OnRemoveInventoryItem;
8760 if (handlerRemoveInventoryItem != null)
8761 {
8762 handlerRemoveInventoryItem(this, uuids);
8763 }
8764 }
8765 return true;
8766 }
8767
8768 private bool HandleRequestTaskInventory(IClientAPI sender, Packet Pack)
8769 {
8770 RequestTaskInventoryPacket requesttask = (RequestTaskInventoryPacket)Pack;
8771
8772 #region Packet Session and User Check
8773 if (m_checkPackets)
8774 {
8775 if (requesttask.AgentData.SessionID != SessionId ||
8776 requesttask.AgentData.AgentID != AgentId)
8777 return true;
8778 }
8779 #endregion
8780
8781 RequestTaskInventory handlerRequestTaskInventory = OnRequestTaskInventory;
8782 if (handlerRequestTaskInventory != null)
8783 {
8784 handlerRequestTaskInventory(this, requesttask.InventoryData.LocalID);
8785 }
8786 return true;
8787 }
8788
8789 private bool HandleUpdateTaskInventory(IClientAPI sender, Packet Pack)
8790 {
8791 UpdateTaskInventoryPacket updatetask = (UpdateTaskInventoryPacket)Pack;
8792
8793 #region Packet Session and User Check
8794 if (m_checkPackets)
8795 {
8796 if (updatetask.AgentData.SessionID != SessionId ||
8797 updatetask.AgentData.AgentID != AgentId)
8798 return true;
8799 }
8800 #endregion
8801
8802 if (OnUpdateTaskInventory != null)
8803 {
8804 if (updatetask.UpdateData.Key == 0)
8805 {
8806 UpdateTaskInventory handlerUpdateTaskInventory = OnUpdateTaskInventory;
8807 if (handlerUpdateTaskInventory != null)
8808 {
8809 TaskInventoryItem newTaskItem = new TaskInventoryItem();
8810 newTaskItem.ItemID = updatetask.InventoryData.ItemID;
8811 newTaskItem.ParentID = updatetask.InventoryData.FolderID;
8812 newTaskItem.CreatorID = updatetask.InventoryData.CreatorID;
8813 newTaskItem.OwnerID = updatetask.InventoryData.OwnerID;
8814 newTaskItem.GroupID = updatetask.InventoryData.GroupID;
8815 newTaskItem.BasePermissions = updatetask.InventoryData.BaseMask;
8816 newTaskItem.CurrentPermissions = updatetask.InventoryData.OwnerMask;
8817 newTaskItem.GroupPermissions = updatetask.InventoryData.GroupMask;
8818 newTaskItem.EveryonePermissions = updatetask.InventoryData.EveryoneMask;
8819 newTaskItem.NextPermissions = updatetask.InventoryData.NextOwnerMask;
8820
8821 // Unused? Clicking share with group sets GroupPermissions instead, so perhaps this is something
8822 // different
8823 //newTaskItem.GroupOwned=updatetask.InventoryData.GroupOwned;
8824 newTaskItem.Type = updatetask.InventoryData.Type;
8825 newTaskItem.InvType = updatetask.InventoryData.InvType;
8826 newTaskItem.Flags = updatetask.InventoryData.Flags;
8827 //newTaskItem.SaleType=updatetask.InventoryData.SaleType;
8828 //newTaskItem.SalePrice=updatetask.InventoryData.SalePrice;
8829 newTaskItem.Name = Util.FieldToString(updatetask.InventoryData.Name);
8830 newTaskItem.Description = Util.FieldToString(updatetask.InventoryData.Description);
8831 newTaskItem.CreationDate = (uint)updatetask.InventoryData.CreationDate;
8832 handlerUpdateTaskInventory(this, updatetask.InventoryData.TransactionID,
8833 newTaskItem, updatetask.UpdateData.LocalID);
8834 }
8835 }
8836 }
8837
8838 return true;
8839 }
8840
8841 private bool HandleRemoveTaskInventory(IClientAPI sender, Packet Pack)
8842 {
8843 RemoveTaskInventoryPacket removeTask = (RemoveTaskInventoryPacket)Pack;
8844
8845 #region Packet Session and User Check
8846 if (m_checkPackets)
8847 {
8848 if (removeTask.AgentData.SessionID != SessionId ||
8849 removeTask.AgentData.AgentID != AgentId)
8850 return true;
8851 }
8852 #endregion
8853
8854 RemoveTaskInventory handlerRemoveTaskItem = OnRemoveTaskItem;
8855
8856 if (handlerRemoveTaskItem != null)
8857 {
8858 handlerRemoveTaskItem(this, removeTask.InventoryData.ItemID, removeTask.InventoryData.LocalID);
8859 }
8860
8861 return true;
8862 }
8863
8864 private bool HandleMoveTaskInventory(IClientAPI sender, Packet Pack)
8865 {
8866 MoveTaskInventoryPacket moveTaskInventoryPacket = (MoveTaskInventoryPacket)Pack;
8867
8868 #region Packet Session and User Check
8869 if (m_checkPackets)
8870 {
8871 if (moveTaskInventoryPacket.AgentData.SessionID != SessionId ||
8872 moveTaskInventoryPacket.AgentData.AgentID != AgentId)
8873 return true;
8874 }
8875 #endregion
8876
8877 MoveTaskInventory handlerMoveTaskItem = OnMoveTaskItem;
8878
8879 if (handlerMoveTaskItem != null)
8880 {
8881 handlerMoveTaskItem(
8882 this, moveTaskInventoryPacket.AgentData.FolderID,
8883 moveTaskInventoryPacket.InventoryData.LocalID,
8884 moveTaskInventoryPacket.InventoryData.ItemID);
8885 }
8886
8887 return true;
8888 }
8889
8890 private bool HandleRezScript(IClientAPI sender, Packet Pack)
8891 {
8892 //m_log.Debug(Pack.ToString());
8893 RezScriptPacket rezScriptx = (RezScriptPacket)Pack;
8894
8895 #region Packet Session and User Check
8896 if (m_checkPackets)
8897 {
8898 if (rezScriptx.AgentData.SessionID != SessionId ||
8899 rezScriptx.AgentData.AgentID != AgentId)
8900 return true;
8901 }
8902 #endregion
8903
8904 RezScript handlerRezScript = OnRezScript;
8905 InventoryItemBase item = new InventoryItemBase();
8906 item.ID = rezScriptx.InventoryBlock.ItemID;
8907 item.Folder = rezScriptx.InventoryBlock.FolderID;
8908 item.CreatorId = rezScriptx.InventoryBlock.CreatorID.ToString();
8909 item.Owner = rezScriptx.InventoryBlock.OwnerID;
8910 item.BasePermissions = rezScriptx.InventoryBlock.BaseMask;
8911 item.CurrentPermissions = rezScriptx.InventoryBlock.OwnerMask;
8912 item.EveryOnePermissions = rezScriptx.InventoryBlock.EveryoneMask;
8913 item.NextPermissions = rezScriptx.InventoryBlock.NextOwnerMask;
8914 item.GroupPermissions = rezScriptx.InventoryBlock.GroupMask;
8915 item.GroupOwned = rezScriptx.InventoryBlock.GroupOwned;
8916 item.GroupID = rezScriptx.InventoryBlock.GroupID;
8917 item.AssetType = rezScriptx.InventoryBlock.Type;
8918 item.InvType = rezScriptx.InventoryBlock.InvType;
8919 item.Flags = rezScriptx.InventoryBlock.Flags;
8920 item.SaleType = rezScriptx.InventoryBlock.SaleType;
8921 item.SalePrice = rezScriptx.InventoryBlock.SalePrice;
8922 item.Name = Util.FieldToString(rezScriptx.InventoryBlock.Name);
8923 item.Description = Util.FieldToString(rezScriptx.InventoryBlock.Description);
8924 item.CreationDate = rezScriptx.InventoryBlock.CreationDate;
8925
8926 if (handlerRezScript != null)
8927 {
8928 handlerRezScript(this, item, rezScriptx.InventoryBlock.TransactionID, rezScriptx.UpdateBlock.ObjectLocalID);
8929 }
8930 return true;
8931 }
8932
8933 private bool HandleMapLayerRequest(IClientAPI sender, Packet Pack)
8934 {
8935 RequestMapLayer();
8936 return true;
8937 }
8938
8939 private bool HandleMapBlockRequest(IClientAPI sender, Packet Pack)
8940 {
8941 MapBlockRequestPacket MapRequest = (MapBlockRequestPacket)Pack;
8942
8943 #region Packet Session and User Check
8944 if (m_checkPackets)
8945 {
8946 if (MapRequest.AgentData.SessionID != SessionId ||
8947 MapRequest.AgentData.AgentID != AgentId)
8948 return true;
8949 }
8950 #endregion
8951
8952 RequestMapBlocks handlerRequestMapBlocks = OnRequestMapBlocks;
8953 if (handlerRequestMapBlocks != null)
8954 {
8955 handlerRequestMapBlocks(this, MapRequest.PositionData.MinX, MapRequest.PositionData.MinY,
8956 MapRequest.PositionData.MaxX, MapRequest.PositionData.MaxY, MapRequest.AgentData.Flags);
8957 }
8958 return true;
8959 }
8960
8961 private bool HandleMapNameRequest(IClientAPI sender, Packet Pack)
8962 {
8963 MapNameRequestPacket map = (MapNameRequestPacket)Pack;
8964
8965 #region Packet Session and User Check
8966 if (m_checkPackets)
8967 {
8968 if (map.AgentData.SessionID != SessionId ||
8969 map.AgentData.AgentID != AgentId)
8970 return true;
8971 }
8972 #endregion
8973 string mapName = Util.UTF8.GetString(map.NameData.Name, 0,
8974 map.NameData.Name.Length - 1);
8975 RequestMapName handlerMapNameRequest = OnMapNameRequest;
8976 if (handlerMapNameRequest != null)
8977 {
8978 handlerMapNameRequest(this, mapName, map.AgentData.Flags);
8979 }
8980 return true;
8981 }
8982
8983 private bool HandleTeleportLandmarkRequest(IClientAPI sender, Packet Pack)
8984 {
8985 TeleportLandmarkRequestPacket tpReq = (TeleportLandmarkRequestPacket)Pack;
8986
8987 #region Packet Session and User Check
8988 if (m_checkPackets)
8989 {
8990 if (tpReq.Info.SessionID != SessionId ||
8991 tpReq.Info.AgentID != AgentId)
8992 return true;
8993 }
8994 #endregion
8995
8996 UUID lmid = tpReq.Info.LandmarkID;
8997 AssetLandmark lm;
8998 if (lmid != UUID.Zero)
8999 {
9000
9001 //AssetBase lma = m_assetCache.GetAsset(lmid, false);
9002 AssetBase lma = m_assetService.Get(lmid.ToString());
9003
9004 if (lma == null)
9005 {
9006 // Failed to find landmark
9007
9008 // Let's try to search in the user's home asset server
9009 lma = FindAssetInUserAssetServer(lmid.ToString());
9010
9011 if (lma == null)
9012 {
9013 // Really doesn't exist
9014 TeleportCancelPacket tpCancel = (TeleportCancelPacket)PacketPool.Instance.GetPacket(PacketType.TeleportCancel);
9015 tpCancel.Info.SessionID = tpReq.Info.SessionID;
9016 tpCancel.Info.AgentID = tpReq.Info.AgentID;
9017 OutPacket(tpCancel, ThrottleOutPacketType.Task);
9018 }
9019 }
9020
9021 try
9022 {
9023 lm = new AssetLandmark(lma);
9024 }
9025 catch (NullReferenceException)
9026 {
9027 // asset not found generates null ref inside the assetlandmark constructor.
9028 TeleportCancelPacket tpCancel = (TeleportCancelPacket)PacketPool.Instance.GetPacket(PacketType.TeleportCancel);
9029 tpCancel.Info.SessionID = tpReq.Info.SessionID;
9030 tpCancel.Info.AgentID = tpReq.Info.AgentID;
9031 OutPacket(tpCancel, ThrottleOutPacketType.Task);
9032 return true;
9033 }
9034 }
9035 else
9036 {
9037 // Teleport home request
9038 UUIDNameRequest handlerTeleportHomeRequest = OnTeleportHomeRequest;
9039 if (handlerTeleportHomeRequest != null)
9040 {
9041 handlerTeleportHomeRequest(AgentId, this);
9042 }
9043 return true;
9044 }
9045
9046 TeleportLandmarkRequest handlerTeleportLandmarkRequest = OnTeleportLandmarkRequest;
9047 if (handlerTeleportLandmarkRequest != null)
9048 {
9049 handlerTeleportLandmarkRequest(this, lm);
9050 }
9051 else
9052 {
9053 //no event handler so cancel request
9054 TeleportCancelPacket tpCancel = (TeleportCancelPacket)PacketPool.Instance.GetPacket(PacketType.TeleportCancel);
9055 tpCancel.Info.AgentID = tpReq.Info.AgentID;
9056 tpCancel.Info.SessionID = tpReq.Info.SessionID;
9057 OutPacket(tpCancel, ThrottleOutPacketType.Task);
9058
9059 }
9060 return true;
9061 }
9062
9063 private bool HandleTeleportCancel(IClientAPI sender, Packet Pack)
9064 {
9065 TeleportCancel handlerTeleportCancel = OnTeleportCancel;
9066 if (handlerTeleportCancel != null)
9067 {
9068 handlerTeleportCancel(this);
9069 }
9070 return true;
9071 }
9072
9073 private AssetBase FindAssetInUserAssetServer(string id)
9074 {
9075 AgentCircuitData aCircuit = ((Scene)Scene).AuthenticateHandler.GetAgentCircuitData(CircuitCode);
9076 if (aCircuit != null && aCircuit.ServiceURLs != null && aCircuit.ServiceURLs.ContainsKey("AssetServerURI"))
9077 {
9078 string assetServer = aCircuit.ServiceURLs["AssetServerURI"].ToString();
9079 if (!string.IsNullOrEmpty(assetServer))
9080 return ((Scene)Scene).AssetService.Get(assetServer + "/" + id);
9081 }
9082
9083 return null;
9084 }
9085
9086 private bool HandleTeleportLocationRequest(IClientAPI sender, Packet Pack)
9087 {
9088 TeleportLocationRequestPacket tpLocReq = (TeleportLocationRequestPacket)Pack;
9089 // m_log.Debug(tpLocReq.ToString());
9090
9091 #region Packet Session and User Check
9092 if (m_checkPackets)
9093 {
9094 if (tpLocReq.AgentData.SessionID != SessionId ||
9095 tpLocReq.AgentData.AgentID != AgentId)
9096 return true;
9097 }
9098 #endregion
9099
9100 TeleportLocationRequest handlerTeleportLocationRequest = OnTeleportLocationRequest;
9101 if (handlerTeleportLocationRequest != null)
9102 {
9103 // Adjust teleport location to base of a larger region if requested to teleport to a sub-region
9104 uint locX, locY;
9105 Util.RegionHandleToWorldLoc(tpLocReq.Info.RegionHandle, out locX, out locY);
9106 if ((locX >= m_scene.RegionInfo.WorldLocX)
9107 && (locX < (m_scene.RegionInfo.WorldLocX + m_scene.RegionInfo.RegionSizeX))
9108 && (locY >= m_scene.RegionInfo.WorldLocY)
9109 && (locY < (m_scene.RegionInfo.WorldLocY + m_scene.RegionInfo.RegionSizeY)) )
9110 {
9111 tpLocReq.Info.RegionHandle = m_scene.RegionInfo.RegionHandle;
9112 tpLocReq.Info.Position.X += locX - m_scene.RegionInfo.WorldLocX;
9113 tpLocReq.Info.Position.Y += locY - m_scene.RegionInfo.WorldLocY;
9114 }
9115
9116 handlerTeleportLocationRequest(this, tpLocReq.Info.RegionHandle, tpLocReq.Info.Position,
9117 tpLocReq.Info.LookAt, 16);
9118 }
9119 else
9120 {
9121 //no event handler so cancel request
9122 TeleportCancelPacket tpCancel = (TeleportCancelPacket)PacketPool.Instance.GetPacket(PacketType.TeleportCancel);
9123 tpCancel.Info.SessionID = tpLocReq.AgentData.SessionID;
9124 tpCancel.Info.AgentID = tpLocReq.AgentData.AgentID;
9125 OutPacket(tpCancel, ThrottleOutPacketType.Task);
9126 }
9127 return true;
9128 }
9129
9130 #endregion Inventory/Asset/Other related packets
9131
9132 private bool HandleUUIDNameRequest(IClientAPI sender, Packet Pack)
9133 {
9134 UUIDNameRequestPacket incoming = (UUIDNameRequestPacket)Pack;
9135
9136 foreach (UUIDNameRequestPacket.UUIDNameBlockBlock UUIDBlock in incoming.UUIDNameBlock)
9137 {
9138 UUIDNameRequest handlerNameRequest = OnNameFromUUIDRequest;
9139 if (handlerNameRequest != null)
9140 {
9141 handlerNameRequest(UUIDBlock.ID, this);
9142 }
9143 }
9144 return true;
9145 }
9146
9147 #region Parcel related packets
9148
9149 private bool HandleRegionHandleRequest(IClientAPI sender, Packet Pack)
9150 {
9151 RegionHandleRequestPacket rhrPack = (RegionHandleRequestPacket)Pack;
9152
9153 RegionHandleRequest handlerRegionHandleRequest = OnRegionHandleRequest;
9154 if (handlerRegionHandleRequest != null)
9155 {
9156 handlerRegionHandleRequest(this, rhrPack.RequestBlock.RegionID);
9157 }
9158 return true;
9159 }
9160
9161 private bool HandleParcelInfoRequest(IClientAPI sender, Packet Pack)
9162 {
9163 ParcelInfoRequestPacket pirPack = (ParcelInfoRequestPacket)Pack;
9164
9165 #region Packet Session and User Check
9166 if (m_checkPackets)
9167 {
9168 if (pirPack.AgentData.SessionID != SessionId ||
9169 pirPack.AgentData.AgentID != AgentId)
9170 return true;
9171 }
9172 #endregion
9173
9174 ParcelInfoRequest handlerParcelInfoRequest = OnParcelInfoRequest;
9175 if (handlerParcelInfoRequest != null)
9176 {
9177 handlerParcelInfoRequest(this, pirPack.Data.ParcelID);
9178 }
9179 return true;
9180 }
9181
9182 private bool HandleParcelAccessListRequest(IClientAPI sender, Packet Pack)
9183 {
9184 ParcelAccessListRequestPacket requestPacket = (ParcelAccessListRequestPacket)Pack;
9185
9186 #region Packet Session and User Check
9187 if (m_checkPackets)
9188 {
9189 if (requestPacket.AgentData.SessionID != SessionId ||
9190 requestPacket.AgentData.AgentID != AgentId)
9191 return true;
9192 }
9193 #endregion
9194
9195 ParcelAccessListRequest handlerParcelAccessListRequest = OnParcelAccessListRequest;
9196
9197 if (handlerParcelAccessListRequest != null)
9198 {
9199 handlerParcelAccessListRequest(requestPacket.AgentData.AgentID, requestPacket.AgentData.SessionID,
9200 requestPacket.Data.Flags, requestPacket.Data.SequenceID,
9201 requestPacket.Data.LocalID, this);
9202 }
9203 return true;
9204 }
9205
9206 private bool HandleParcelAccessListUpdate(IClientAPI sender, Packet Pack)
9207 {
9208 ParcelAccessListUpdatePacket updatePacket = (ParcelAccessListUpdatePacket)Pack;
9209
9210 #region Packet Session and User Check
9211 if (m_checkPackets)
9212 {
9213 if (updatePacket.AgentData.SessionID != SessionId ||
9214 updatePacket.AgentData.AgentID != AgentId)
9215 return true;
9216 }
9217 #endregion
9218
9219 List<LandAccessEntry> entries = new List<LandAccessEntry>();
9220 foreach (ParcelAccessListUpdatePacket.ListBlock block in updatePacket.List)
9221 {
9222 LandAccessEntry entry = new LandAccessEntry();
9223 entry.AgentID = block.ID;
9224 entry.Flags = (AccessList)block.Flags;
9225 entry.Expires = block.Time;
9226 entries.Add(entry);
9227 }
9228
9229 ParcelAccessListUpdateRequest handlerParcelAccessListUpdateRequest = OnParcelAccessListUpdateRequest;
9230 if (handlerParcelAccessListUpdateRequest != null)
9231 {
9232 handlerParcelAccessListUpdateRequest(updatePacket.AgentData.AgentID,
9233 updatePacket.Data.Flags,
9234 updatePacket.Data.LocalID,
9235 updatePacket.Data.TransactionID,
9236 updatePacket.Data.SequenceID,
9237 updatePacket.Data.Sections,
9238 entries, this);
9239 }
9240 return true;
9241 }
9242
9243 private bool HandleParcelPropertiesRequest(IClientAPI sender, Packet Pack)
9244 {
9245 ParcelPropertiesRequestPacket propertiesRequest = (ParcelPropertiesRequestPacket)Pack;
9246
9247 #region Packet Session and User Check
9248 if (m_checkPackets)
9249 {
9250 if (propertiesRequest.AgentData.SessionID != SessionId ||
9251 propertiesRequest.AgentData.AgentID != AgentId)
9252 return true;
9253 }
9254 #endregion
9255
9256 ParcelPropertiesRequest handlerParcelPropertiesRequest = OnParcelPropertiesRequest;
9257 if (handlerParcelPropertiesRequest != null)
9258 {
9259 handlerParcelPropertiesRequest((int)Math.Round(propertiesRequest.ParcelData.West),
9260 (int)Math.Round(propertiesRequest.ParcelData.South),
9261 (int)Math.Round(propertiesRequest.ParcelData.East),
9262 (int)Math.Round(propertiesRequest.ParcelData.North),
9263 propertiesRequest.ParcelData.SequenceID,
9264 propertiesRequest.ParcelData.SnapSelection, this);
9265 }
9266 return true;
9267 }
9268
9269 private bool HandleParcelDivide(IClientAPI sender, Packet Pack)
9270 {
9271 ParcelDividePacket landDivide = (ParcelDividePacket)Pack;
9272
9273 #region Packet Session and User Check
9274 if (m_checkPackets)
9275 {
9276 if (landDivide.AgentData.SessionID != SessionId ||
9277 landDivide.AgentData.AgentID != AgentId)
9278 return true;
9279 }
9280 #endregion
9281
9282 ParcelDivideRequest handlerParcelDivideRequest = OnParcelDivideRequest;
9283 if (handlerParcelDivideRequest != null)
9284 {
9285 handlerParcelDivideRequest((int)Math.Round(landDivide.ParcelData.West),
9286 (int)Math.Round(landDivide.ParcelData.South),
9287 (int)Math.Round(landDivide.ParcelData.East),
9288 (int)Math.Round(landDivide.ParcelData.North), this);
9289 }
9290 return true;
9291 }
9292
9293 private bool HandleParcelJoin(IClientAPI sender, Packet Pack)
9294 {
9295 ParcelJoinPacket landJoin = (ParcelJoinPacket)Pack;
9296
9297 #region Packet Session and User Check
9298 if (m_checkPackets)
9299 {
9300 if (landJoin.AgentData.SessionID != SessionId ||
9301 landJoin.AgentData.AgentID != AgentId)
9302 return true;
9303 }
9304 #endregion
9305
9306 ParcelJoinRequest handlerParcelJoinRequest = OnParcelJoinRequest;
9307
9308 if (handlerParcelJoinRequest != null)
9309 {
9310 handlerParcelJoinRequest((int)Math.Round(landJoin.ParcelData.West),
9311 (int)Math.Round(landJoin.ParcelData.South),
9312 (int)Math.Round(landJoin.ParcelData.East),
9313 (int)Math.Round(landJoin.ParcelData.North), this);
9314 }
9315 return true;
9316 }
9317
9318 private bool HandleParcelPropertiesUpdate(IClientAPI sender, Packet Pack)
9319 {
9320 ParcelPropertiesUpdatePacket parcelPropertiesPacket = (ParcelPropertiesUpdatePacket)Pack;
9321
9322 #region Packet Session and User Check
9323 if (m_checkPackets)
9324 {
9325 if (parcelPropertiesPacket.AgentData.SessionID != SessionId ||
9326 parcelPropertiesPacket.AgentData.AgentID != AgentId)
9327 return true;
9328 }
9329 #endregion
9330
9331 ParcelPropertiesUpdateRequest handlerParcelPropertiesUpdateRequest = OnParcelPropertiesUpdateRequest;
9332
9333 if (handlerParcelPropertiesUpdateRequest != null)
9334 {
9335 LandUpdateArgs args = new LandUpdateArgs();
9336
9337 args.AuthBuyerID = parcelPropertiesPacket.ParcelData.AuthBuyerID;
9338 args.Category = (ParcelCategory)parcelPropertiesPacket.ParcelData.Category;
9339 args.Desc = Utils.BytesToString(parcelPropertiesPacket.ParcelData.Desc);
9340 args.GroupID = parcelPropertiesPacket.ParcelData.GroupID;
9341 args.LandingType = parcelPropertiesPacket.ParcelData.LandingType;
9342 args.MediaAutoScale = parcelPropertiesPacket.ParcelData.MediaAutoScale;
9343 args.MediaID = parcelPropertiesPacket.ParcelData.MediaID;
9344 args.MediaURL = Utils.BytesToString(parcelPropertiesPacket.ParcelData.MediaURL);
9345 args.MusicURL = Utils.BytesToString(parcelPropertiesPacket.ParcelData.MusicURL);
9346 args.Name = Utils.BytesToString(parcelPropertiesPacket.ParcelData.Name);
9347 args.ParcelFlags = parcelPropertiesPacket.ParcelData.ParcelFlags;
9348 args.PassHours = parcelPropertiesPacket.ParcelData.PassHours;
9349 args.PassPrice = parcelPropertiesPacket.ParcelData.PassPrice;
9350 args.SalePrice = parcelPropertiesPacket.ParcelData.SalePrice;
9351 args.SnapshotID = parcelPropertiesPacket.ParcelData.SnapshotID;
9352 args.UserLocation = parcelPropertiesPacket.ParcelData.UserLocation;
9353 args.UserLookAt = parcelPropertiesPacket.ParcelData.UserLookAt;
9354 handlerParcelPropertiesUpdateRequest(args, parcelPropertiesPacket.ParcelData.LocalID, this);
9355 }
9356 return true;
9357 }
9358
9359 private bool HandleParcelSelectObjects(IClientAPI sender, Packet Pack)
9360 {
9361 ParcelSelectObjectsPacket selectPacket = (ParcelSelectObjectsPacket)Pack;
9362
9363 #region Packet Session and User Check
9364 if (m_checkPackets)
9365 {
9366 if (selectPacket.AgentData.SessionID != SessionId ||
9367 selectPacket.AgentData.AgentID != AgentId)
9368 return true;
9369 }
9370 #endregion
9371
9372 List<UUID> returnIDs = new List<UUID>();
9373
9374 foreach (ParcelSelectObjectsPacket.ReturnIDsBlock rb in
9375 selectPacket.ReturnIDs)
9376 {
9377 returnIDs.Add(rb.ReturnID);
9378 }
9379
9380 ParcelSelectObjects handlerParcelSelectObjects = OnParcelSelectObjects;
9381
9382 if (handlerParcelSelectObjects != null)
9383 {
9384 handlerParcelSelectObjects(selectPacket.ParcelData.LocalID,
9385 Convert.ToInt32(selectPacket.ParcelData.ReturnType), returnIDs, this);
9386 }
9387 return true;
9388 }
9389
9390 private bool HandleParcelObjectOwnersRequest(IClientAPI sender, Packet Pack)
9391 {
9392 ParcelObjectOwnersRequestPacket reqPacket = (ParcelObjectOwnersRequestPacket)Pack;
9393
9394 #region Packet Session and User Check
9395 if (m_checkPackets)
9396 {
9397 if (reqPacket.AgentData.SessionID != SessionId ||
9398 reqPacket.AgentData.AgentID != AgentId)
9399 return true;
9400 }
9401 #endregion
9402
9403 ParcelObjectOwnerRequest handlerParcelObjectOwnerRequest = OnParcelObjectOwnerRequest;
9404
9405 if (handlerParcelObjectOwnerRequest != null)
9406 {
9407 handlerParcelObjectOwnerRequest(reqPacket.ParcelData.LocalID, this);
9408 }
9409 return true;
9410
9411 }
9412
9413 private bool HandleParcelGodForceOwner(IClientAPI sender, Packet Pack)
9414 {
9415 ParcelGodForceOwnerPacket godForceOwnerPacket = (ParcelGodForceOwnerPacket)Pack;
9416
9417 #region Packet Session and User Check
9418 if (m_checkPackets)
9419 {
9420 if (godForceOwnerPacket.AgentData.SessionID != SessionId ||
9421 godForceOwnerPacket.AgentData.AgentID != AgentId)
9422 return true;
9423 }
9424 #endregion
9425
9426 ParcelGodForceOwner handlerParcelGodForceOwner = OnParcelGodForceOwner;
9427 if (handlerParcelGodForceOwner != null)
9428 {
9429 handlerParcelGodForceOwner(godForceOwnerPacket.Data.LocalID, godForceOwnerPacket.Data.OwnerID, this);
9430 }
9431 return true;
9432 }
9433
9434 private bool HandleParcelRelease(IClientAPI sender, Packet Pack)
9435 {
9436 ParcelReleasePacket releasePacket = (ParcelReleasePacket)Pack;
9437
9438 #region Packet Session and User Check
9439 if (m_checkPackets)
9440 {
9441 if (releasePacket.AgentData.SessionID != SessionId ||
9442 releasePacket.AgentData.AgentID != AgentId)
9443 return true;
9444 }
9445 #endregion
9446
9447 ParcelAbandonRequest handlerParcelAbandonRequest = OnParcelAbandonRequest;
9448 if (handlerParcelAbandonRequest != null)
9449 {
9450 handlerParcelAbandonRequest(releasePacket.Data.LocalID, this);
9451 }
9452 return true;
9453 }
9454
9455 private bool HandleParcelReclaim(IClientAPI sender, Packet Pack)
9456 {
9457 ParcelReclaimPacket reclaimPacket = (ParcelReclaimPacket)Pack;
9458
9459 #region Packet Session and User Check
9460 if (m_checkPackets)
9461 {
9462 if (reclaimPacket.AgentData.SessionID != SessionId ||
9463 reclaimPacket.AgentData.AgentID != AgentId)
9464 return true;
9465 }
9466 #endregion
9467
9468 ParcelReclaim handlerParcelReclaim = OnParcelReclaim;
9469 if (handlerParcelReclaim != null)
9470 {
9471 handlerParcelReclaim(reclaimPacket.Data.LocalID, this);
9472 }
9473 return true;
9474 }
9475
9476 private bool HandleParcelReturnObjects(IClientAPI sender, Packet Pack)
9477 {
9478 ParcelReturnObjectsPacket parcelReturnObjects = (ParcelReturnObjectsPacket)Pack;
9479
9480 #region Packet Session and User Check
9481 if (m_checkPackets)
9482 {
9483 if (parcelReturnObjects.AgentData.SessionID != SessionId ||
9484 parcelReturnObjects.AgentData.AgentID != AgentId)
9485 return true;
9486 }
9487 #endregion
9488
9489 UUID[] puserselectedOwnerIDs = new UUID[parcelReturnObjects.OwnerIDs.Length];
9490 for (int parceliterator = 0; parceliterator < parcelReturnObjects.OwnerIDs.Length; parceliterator++)
9491 puserselectedOwnerIDs[parceliterator] = parcelReturnObjects.OwnerIDs[parceliterator].OwnerID;
9492
9493 UUID[] puserselectedTaskIDs = new UUID[parcelReturnObjects.TaskIDs.Length];
9494
9495 for (int parceliterator = 0; parceliterator < parcelReturnObjects.TaskIDs.Length; parceliterator++)
9496 puserselectedTaskIDs[parceliterator] = parcelReturnObjects.TaskIDs[parceliterator].TaskID;
9497
9498 ParcelReturnObjectsRequest handlerParcelReturnObjectsRequest = OnParcelReturnObjectsRequest;
9499 if (handlerParcelReturnObjectsRequest != null)
9500 {
9501 handlerParcelReturnObjectsRequest(parcelReturnObjects.ParcelData.LocalID, parcelReturnObjects.ParcelData.ReturnType, puserselectedOwnerIDs, puserselectedTaskIDs, this);
9502
9503 }
9504 return true;
9505 }
9506
9507 private bool HandleParcelSetOtherCleanTime(IClientAPI sender, Packet Pack)
9508 {
9509 ParcelSetOtherCleanTimePacket parcelSetOtherCleanTimePacket = (ParcelSetOtherCleanTimePacket)Pack;
9510
9511 #region Packet Session and User Check
9512 if (m_checkPackets)
9513 {
9514 if (parcelSetOtherCleanTimePacket.AgentData.SessionID != SessionId ||
9515 parcelSetOtherCleanTimePacket.AgentData.AgentID != AgentId)
9516 return true;
9517 }
9518 #endregion
9519
9520 ParcelSetOtherCleanTime handlerParcelSetOtherCleanTime = OnParcelSetOtherCleanTime;
9521 if (handlerParcelSetOtherCleanTime != null)
9522 {
9523 handlerParcelSetOtherCleanTime(this,
9524 parcelSetOtherCleanTimePacket.ParcelData.LocalID,
9525 parcelSetOtherCleanTimePacket.ParcelData.OtherCleanTime);
9526 }
9527 return true;
9528 }
9529
9530 private bool HandleLandStatRequest(IClientAPI sender, Packet Pack)
9531 {
9532 LandStatRequestPacket lsrp = (LandStatRequestPacket)Pack;
9533
9534 #region Packet Session and User Check
9535 if (m_checkPackets)
9536 {
9537 if (lsrp.AgentData.SessionID != SessionId ||
9538 lsrp.AgentData.AgentID != AgentId)
9539 return true;
9540 }
9541 #endregion
9542
9543 GodLandStatRequest handlerLandStatRequest = OnLandStatRequest;
9544 if (handlerLandStatRequest != null)
9545 {
9546 handlerLandStatRequest(lsrp.RequestData.ParcelLocalID, lsrp.RequestData.ReportType, lsrp.RequestData.RequestFlags, Utils.BytesToString(lsrp.RequestData.Filter), this);
9547 }
9548 return true;
9549 }
9550
9551 private bool HandleParcelDwellRequest(IClientAPI sender, Packet Pack)
9552 {
9553 ParcelDwellRequestPacket dwellrq =
9554 (ParcelDwellRequestPacket)Pack;
9555
9556 #region Packet Session and User Check
9557 if (m_checkPackets)
9558 {
9559 if (dwellrq.AgentData.SessionID != SessionId ||
9560 dwellrq.AgentData.AgentID != AgentId)
9561 return true;
9562 }
9563 #endregion
9564
9565 ParcelDwellRequest handlerParcelDwellRequest = OnParcelDwellRequest;
9566 if (handlerParcelDwellRequest != null)
9567 {
9568 handlerParcelDwellRequest(dwellrq.Data.LocalID, this);
9569 }
9570 return true;
9571 }
9572
9573 #endregion Parcel related packets
9574
9575 #region Estate Packets
9576
9577 private bool HandleEstateOwnerMessage(IClientAPI sender, Packet Pack)
9578 {
9579 EstateOwnerMessagePacket messagePacket = (EstateOwnerMessagePacket)Pack;
9580 // m_log.InfoFormat("[LLCLIENTVIEW]: Packet: {0}", Utils.BytesToString(messagePacket.MethodData.Method));
9581 GodLandStatRequest handlerLandStatRequest;
9582
9583 #region Packet Session and User Check
9584 if (m_checkPackets)
9585 {
9586 if (messagePacket.AgentData.SessionID != SessionId ||
9587 messagePacket.AgentData.AgentID != AgentId)
9588 return true;
9589 }
9590 #endregion
9591
9592 string method = Utils.BytesToString(messagePacket.MethodData.Method);
9593
9594 switch (method)
9595 {
9596 case "getinfo":
9597 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
9598 {
9599 OnDetailedEstateDataRequest(this, messagePacket.MethodData.Invoice);
9600 }
9601 return true;
9602 case "setregioninfo":
9603 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
9604 {
9605 OnSetEstateFlagsRequest(convertParamStringToBool(messagePacket.ParamList[0].Parameter), convertParamStringToBool(messagePacket.ParamList[1].Parameter),
9606 convertParamStringToBool(messagePacket.ParamList[2].Parameter), !convertParamStringToBool(messagePacket.ParamList[3].Parameter),
9607 Convert.ToInt16(Convert.ToDecimal(Utils.BytesToString(messagePacket.ParamList[4].Parameter), Culture.NumberFormatInfo)),
9608 (float)Convert.ToDecimal(Utils.BytesToString(messagePacket.ParamList[5].Parameter), Culture.NumberFormatInfo),
9609 Convert.ToInt16(Utils.BytesToString(messagePacket.ParamList[6].Parameter)),
9610 convertParamStringToBool(messagePacket.ParamList[7].Parameter), convertParamStringToBool(messagePacket.ParamList[8].Parameter));
9611 }
9612 return true;
9613 // case "texturebase":
9614 // if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
9615 // {
9616 // foreach (EstateOwnerMessagePacket.ParamListBlock block in messagePacket.ParamList)
9617 // {
9618 // string s = Utils.BytesToString(block.Parameter);
9619 // string[] splitField = s.Split(' ');
9620 // if (splitField.Length == 2)
9621 // {
9622 // UUID tempUUID = new UUID(splitField[1]);
9623 // OnSetEstateTerrainBaseTexture(this, Convert.ToInt16(splitField[0]), tempUUID);
9624 // }
9625 // }
9626 // }
9627 // break;
9628 case "texturedetail":
9629 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
9630 {
9631 foreach (EstateOwnerMessagePacket.ParamListBlock block in messagePacket.ParamList)
9632 {
9633 string s = Utils.BytesToString(block.Parameter);
9634 string[] splitField = s.Split(' ');
9635 if (splitField.Length == 2)
9636 {
9637 Int16 corner = Convert.ToInt16(splitField[0]);
9638 UUID textureUUID = new UUID(splitField[1]);
9639
9640 OnSetEstateTerrainDetailTexture(this, corner, textureUUID);
9641 }
9642 }
9643 }
9644
9645 return true;
9646 case "textureheights":
9647 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
9648 {
9649 foreach (EstateOwnerMessagePacket.ParamListBlock block in messagePacket.ParamList)
9650 {
9651 string s = Utils.BytesToString(block.Parameter);
9652 string[] splitField = s.Split(' ');
9653 if (splitField.Length == 3)
9654 {
9655 Int16 corner = Convert.ToInt16(splitField[0]);
9656 float lowValue = (float)Convert.ToDecimal(splitField[1], Culture.NumberFormatInfo);
9657 float highValue = (float)Convert.ToDecimal(splitField[2], Culture.NumberFormatInfo);
9658
9659 OnSetEstateTerrainTextureHeights(this, corner, lowValue, highValue);
9660 }
9661 }
9662 }
9663 return true;
9664 case "texturecommit":
9665 OnCommitEstateTerrainTextureRequest(this);
9666 return true;
9667 case "setregionterrain":
9668 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
9669 {
9670 if (messagePacket.ParamList.Length != 9)
9671 {
9672 m_log.Error("EstateOwnerMessage: SetRegionTerrain method has a ParamList of invalid length");
9673 }
9674 else
9675 {
9676 try
9677 {
9678 string tmp = Utils.BytesToString(messagePacket.ParamList[0].Parameter);
9679 if (!tmp.Contains(".")) tmp += ".00";
9680 float WaterHeight = (float)Convert.ToDecimal(tmp, Culture.NumberFormatInfo);
9681 tmp = Utils.BytesToString(messagePacket.ParamList[1].Parameter);
9682 if (!tmp.Contains(".")) tmp += ".00";
9683 float TerrainRaiseLimit = (float)Convert.ToDecimal(tmp, Culture.NumberFormatInfo);
9684 tmp = Utils.BytesToString(messagePacket.ParamList[2].Parameter);
9685 if (!tmp.Contains(".")) tmp += ".00";
9686 float TerrainLowerLimit = (float)Convert.ToDecimal(tmp, Culture.NumberFormatInfo);
9687 bool UseEstateSun = convertParamStringToBool(messagePacket.ParamList[3].Parameter);
9688 bool UseFixedSun = convertParamStringToBool(messagePacket.ParamList[4].Parameter);
9689 float SunHour = (float)Convert.ToDecimal(Utils.BytesToString(messagePacket.ParamList[5].Parameter), Culture.NumberFormatInfo);
9690 bool UseGlobal = convertParamStringToBool(messagePacket.ParamList[6].Parameter);
9691 bool EstateFixedSun = convertParamStringToBool(messagePacket.ParamList[7].Parameter);
9692 float EstateSunHour = (float)Convert.ToDecimal(Utils.BytesToString(messagePacket.ParamList[8].Parameter), Culture.NumberFormatInfo);
9693
9694 OnSetRegionTerrainSettings(WaterHeight, TerrainRaiseLimit, TerrainLowerLimit, UseEstateSun, UseFixedSun, SunHour, UseGlobal, EstateFixedSun, EstateSunHour);
9695
9696 }
9697 catch (Exception ex)
9698 {
9699 m_log.Error("EstateOwnerMessage: Exception while setting terrain settings: \n" + messagePacket + "\n" + ex);
9700 }
9701 }
9702 }
9703
9704 return true;
9705 case "restart":
9706 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
9707 {
9708 // There's only 1 block in the estateResetSim.. and that's the number of seconds till restart.
9709 foreach (EstateOwnerMessagePacket.ParamListBlock block in messagePacket.ParamList)
9710 {
9711 float timeSeconds;
9712 Utils.TryParseSingle(Utils.BytesToString(block.Parameter), out timeSeconds);
9713 timeSeconds = (int)timeSeconds;
9714 OnEstateRestartSimRequest(this, (int)timeSeconds);
9715
9716 }
9717 }
9718 return true;
9719 case "estatechangecovenantid":
9720 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
9721 {
9722 foreach (EstateOwnerMessagePacket.ParamListBlock block in messagePacket.ParamList)
9723 {
9724 UUID newCovenantID = new UUID(Utils.BytesToString(block.Parameter));
9725 OnEstateChangeCovenantRequest(this, newCovenantID);
9726 }
9727 }
9728 return true;
9729 case "estateaccessdelta": // Estate access delta manages the banlist and allow list too.
9730 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
9731 {
9732 int estateAccessType = Convert.ToInt16(Utils.BytesToString(messagePacket.ParamList[1].Parameter));
9733 OnUpdateEstateAccessDeltaRequest(this, messagePacket.MethodData.Invoice, estateAccessType, new UUID(Utils.BytesToString(messagePacket.ParamList[2].Parameter)));
9734
9735 }
9736 return true;
9737 case "simulatormessage":
9738 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
9739 {
9740 UUID invoice = messagePacket.MethodData.Invoice;
9741 UUID SenderID = new UUID(Utils.BytesToString(messagePacket.ParamList[2].Parameter));
9742 string SenderName = Utils.BytesToString(messagePacket.ParamList[3].Parameter);
9743 string Message = Utils.BytesToString(messagePacket.ParamList[4].Parameter);
9744 UUID sessionID = messagePacket.AgentData.SessionID;
9745 OnSimulatorBlueBoxMessageRequest(this, invoice, SenderID, sessionID, SenderName, Message);
9746 }
9747 return true;
9748 case "instantmessage":
9749 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
9750 {
9751 if (messagePacket.ParamList.Length < 2)
9752 return true;
9753
9754 UUID invoice = messagePacket.MethodData.Invoice;
9755 UUID sessionID = messagePacket.AgentData.SessionID;
9756
9757 UUID SenderID;
9758 string SenderName;
9759 string Message;
9760
9761 if (messagePacket.ParamList.Length < 5)
9762 {
9763 SenderID = AgentId;
9764 SenderName = Utils.BytesToString(messagePacket.ParamList[0].Parameter);
9765 Message = Utils.BytesToString(messagePacket.ParamList[1].Parameter);
9766 }
9767 else
9768 {
9769 SenderID = new UUID(Utils.BytesToString(messagePacket.ParamList[2].Parameter));
9770 SenderName = Utils.BytesToString(messagePacket.ParamList[3].Parameter);
9771 Message = Utils.BytesToString(messagePacket.ParamList[4].Parameter);
9772 }
9773
9774 OnEstateBlueBoxMessageRequest(this, invoice, SenderID, sessionID, SenderName, Message);
9775 }
9776 return true;
9777 case "setregiondebug":
9778 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
9779 {
9780 UUID invoice = messagePacket.MethodData.Invoice;
9781 UUID SenderID = messagePacket.AgentData.AgentID;
9782 bool scripted = convertParamStringToBool(messagePacket.ParamList[0].Parameter);
9783 bool collisionEvents = convertParamStringToBool(messagePacket.ParamList[1].Parameter);
9784 bool physics = convertParamStringToBool(messagePacket.ParamList[2].Parameter);
9785
9786 OnEstateDebugRegionRequest(this, invoice, SenderID, scripted, collisionEvents, physics);
9787 }
9788 return true;
9789 case "teleporthomeuser":
9790 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
9791 {
9792 UUID invoice = messagePacket.MethodData.Invoice;
9793 UUID SenderID = messagePacket.AgentData.AgentID;
9794 UUID Prey;
9795
9796 UUID.TryParse(Utils.BytesToString(messagePacket.ParamList[1].Parameter), out Prey);
9797
9798 OnEstateTeleportOneUserHomeRequest(this, invoice, SenderID, Prey);
9799 }
9800 return true;
9801 case "teleporthomeallusers":
9802 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
9803 {
9804 UUID invoice = messagePacket.MethodData.Invoice;
9805 UUID SenderID = messagePacket.AgentData.AgentID;
9806 OnEstateTeleportAllUsersHomeRequest(this, invoice, SenderID);
9807 }
9808 return true;
9809 case "colliders":
9810 handlerLandStatRequest = OnLandStatRequest;
9811 if (handlerLandStatRequest != null)
9812 {
9813 handlerLandStatRequest(0, 1, 0, "", this);
9814 }
9815 return true;
9816 case "scripts":
9817 handlerLandStatRequest = OnLandStatRequest;
9818 if (handlerLandStatRequest != null)
9819 {
9820 handlerLandStatRequest(0, 0, 0, "", this);
9821 }
9822 return true;
9823 case "terrain":
9824 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
9825 {
9826 if (messagePacket.ParamList.Length > 0)
9827 {
9828 if (Utils.BytesToString(messagePacket.ParamList[0].Parameter) == "bake")
9829 {
9830 BakeTerrain handlerBakeTerrain = OnBakeTerrain;
9831 if (handlerBakeTerrain != null)
9832 {
9833 handlerBakeTerrain(this);
9834 }
9835 }
9836 if (Utils.BytesToString(messagePacket.ParamList[0].Parameter) == "download filename")
9837 {
9838 if (messagePacket.ParamList.Length > 1)
9839 {
9840 RequestTerrain handlerRequestTerrain = OnRequestTerrain;
9841 if (handlerRequestTerrain != null)
9842 {
9843 handlerRequestTerrain(this, Utils.BytesToString(messagePacket.ParamList[1].Parameter));
9844 }
9845 }
9846 }
9847 if (Utils.BytesToString(messagePacket.ParamList[0].Parameter) == "upload filename")
9848 {
9849 if (messagePacket.ParamList.Length > 1)
9850 {
9851 RequestTerrain handlerUploadTerrain = OnUploadTerrain;
9852 if (handlerUploadTerrain != null)
9853 {
9854 handlerUploadTerrain(this, Utils.BytesToString(messagePacket.ParamList[1].Parameter));
9855 }
9856 }
9857 }
9858
9859 }
9860
9861
9862 }
9863 return true;
9864
9865 case "estatechangeinfo":
9866 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
9867 {
9868 UUID invoice = messagePacket.MethodData.Invoice;
9869 UUID SenderID = messagePacket.AgentData.AgentID;
9870 UInt32 param1 = Convert.ToUInt32(Utils.BytesToString(messagePacket.ParamList[1].Parameter));
9871 UInt32 param2 = Convert.ToUInt32(Utils.BytesToString(messagePacket.ParamList[2].Parameter));
9872
9873 EstateChangeInfo handlerEstateChangeInfo = OnEstateChangeInfo;
9874 if (handlerEstateChangeInfo != null)
9875 {
9876 handlerEstateChangeInfo(this, invoice, SenderID, param1, param2);
9877 }
9878 }
9879 return true;
9880
9881 case "telehub":
9882 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
9883 {
9884 UUID invoice = messagePacket.MethodData.Invoice;
9885 UUID SenderID = messagePacket.AgentData.AgentID;
9886 UInt32 param1 = 0u;
9887
9888 string command = (string)Utils.BytesToString(messagePacket.ParamList[0].Parameter);
9889
9890 if (command != "info ui")
9891 {
9892 try
9893 {
9894 param1 = Convert.ToUInt32(Utils.BytesToString(messagePacket.ParamList[1].Parameter));
9895 }
9896 catch
9897 {
9898 }
9899 }
9900
9901 EstateManageTelehub handlerEstateManageTelehub = OnEstateManageTelehub;
9902 if (handlerEstateManageTelehub != null)
9903 {
9904 handlerEstateManageTelehub(this, invoice, SenderID, command, param1);
9905 }
9906 }
9907 return true;
9908
9909 case "kickestate":
9910
9911 if(((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
9912 {
9913 UUID invoice = messagePacket.MethodData.Invoice;
9914 UUID SenderID = messagePacket.AgentData.AgentID;
9915 UUID Prey;
9916
9917 UUID.TryParse(Utils.BytesToString(messagePacket.ParamList[0].Parameter), out Prey);
9918
9919 OnEstateTeleportOneUserHomeRequest(this, invoice, SenderID, Prey);
9920 }
9921 return true;
9922
9923 default:
9924 m_log.WarnFormat(
9925 "[LLCLIENTVIEW]: EstateOwnerMessage: Unknown method {0} requested for {1} in {2}",
9926 method, Name, Scene.Name);
9927
9928 for (int i = 0; i < messagePacket.ParamList.Length; i++)
9929 {
9930 EstateOwnerMessagePacket.ParamListBlock block = messagePacket.ParamList[i];
9931 string data = (string)Utils.BytesToString(block.Parameter);
9932 m_log.DebugFormat("[LLCLIENTVIEW]: Param {0}={1}", i, data);
9933 }
9934
9935 return true;
9936 }
9937
9938 //int parcelID, uint reportType, uint requestflags, string filter
9939
9940 //lsrp.RequestData.ParcelLocalID;
9941 //lsrp.RequestData.ReportType; // 1 = colliders, 0 = scripts
9942 //lsrp.RequestData.RequestFlags;
9943 //lsrp.RequestData.Filter;
9944 }
9945
9946 private bool HandleRequestRegionInfo(IClientAPI sender, Packet Pack)
9947 {
9948 RequestRegionInfoPacket.AgentDataBlock mPacket = ((RequestRegionInfoPacket)Pack).AgentData;
9949
9950 #region Packet Session and User Check
9951 if (m_checkPackets)
9952 {
9953 if (mPacket.SessionID != SessionId ||
9954 mPacket.AgentID != AgentId)
9955 return true;
9956 }
9957 #endregion
9958
9959 RegionInfoRequest handlerRegionInfoRequest = OnRegionInfoRequest;
9960 if (handlerRegionInfoRequest != null)
9961 {
9962 handlerRegionInfoRequest(this);
9963 }
9964 return true;
9965 }
9966
9967 private bool HandleEstateCovenantRequest(IClientAPI sender, Packet Pack)
9968 {
9969
9970 //EstateCovenantRequestPacket.AgentDataBlock epack =
9971 // ((EstateCovenantRequestPacket)Pack).AgentData;
9972
9973 EstateCovenantRequest handlerEstateCovenantRequest = OnEstateCovenantRequest;
9974 if (handlerEstateCovenantRequest != null)
9975 {
9976 handlerEstateCovenantRequest(this);
9977 }
9978 return true;
9979
9980 }
9981
9982 #endregion Estate Packets
9983
9984 #region GodPackets
9985
9986 private bool HandleRequestGodlikePowers(IClientAPI sender, Packet Pack)
9987 {
9988 RequestGodlikePowersPacket rglpPack = (RequestGodlikePowersPacket)Pack;
9989 RequestGodlikePowersPacket.RequestBlockBlock rblock = rglpPack.RequestBlock;
9990 UUID token = rblock.Token;
9991
9992 RequestGodlikePowersPacket.AgentDataBlock ablock = rglpPack.AgentData;
9993
9994 RequestGodlikePowers handlerReqGodlikePowers = OnRequestGodlikePowers;
9995
9996 if (handlerReqGodlikePowers != null)
9997 {
9998 handlerReqGodlikePowers(ablock.AgentID, ablock.SessionID, token, rblock.Godlike, this);
9999 }
10000
10001 return true;
10002 }
10003
10004 private bool HandleGodUpdateRegionInfoUpdate(IClientAPI client, Packet Packet)
10005 {
10006 GodUpdateRegionInfoPacket GodUpdateRegionInfo =
10007 (GodUpdateRegionInfoPacket)Packet;
10008
10009 GodUpdateRegionInfoUpdate handlerGodUpdateRegionInfo = OnGodUpdateRegionInfoUpdate;
10010 if (handlerGodUpdateRegionInfo != null)
10011 {
10012 handlerGodUpdateRegionInfo(this,
10013 GodUpdateRegionInfo.RegionInfo.BillableFactor,
10014 GodUpdateRegionInfo.RegionInfo.EstateID,
10015 GodUpdateRegionInfo.RegionInfo.RegionFlags,
10016 GodUpdateRegionInfo.RegionInfo.SimName,
10017 GodUpdateRegionInfo.RegionInfo.RedirectGridX,
10018 GodUpdateRegionInfo.RegionInfo.RedirectGridY);
10019 return true;
10020 }
10021 return false;
10022 }
10023
10024 private bool HandleSimWideDeletes(IClientAPI client, Packet Packet)
10025 {
10026 SimWideDeletesPacket SimWideDeletesRequest =
10027 (SimWideDeletesPacket)Packet;
10028 SimWideDeletesDelegate handlerSimWideDeletesRequest = OnSimWideDeletes;
10029 if (handlerSimWideDeletesRequest != null)
10030 {
10031 handlerSimWideDeletesRequest(this, SimWideDeletesRequest.AgentData.AgentID,(int)SimWideDeletesRequest.DataBlock.Flags,SimWideDeletesRequest.DataBlock.TargetID);
10032 return true;
10033 }
10034 return false;
10035 }
10036
10037 private bool HandleGodlikeMessage(IClientAPI client, Packet Packet)
10038 {
10039 GodlikeMessagePacket GodlikeMessage =
10040 (GodlikeMessagePacket)Packet;
10041
10042 GodlikeMessage handlerGodlikeMessage = onGodlikeMessage;
10043 if (handlerGodlikeMessage != null)
10044 {
10045 handlerGodlikeMessage(this,
10046 GodlikeMessage.MethodData.Invoice,
10047 GodlikeMessage.MethodData.Method,
10048 GodlikeMessage.ParamList[0].Parameter);
10049 return true;
10050 }
10051 return false;
10052 }
10053
10054 private bool HandleSaveStatePacket(IClientAPI client, Packet Packet)
10055 {
10056 StateSavePacket SaveStateMessage =
10057 (StateSavePacket)Packet;
10058 SaveStateHandler handlerSaveStatePacket = OnSaveState;
10059 if (handlerSaveStatePacket != null)
10060 {
10061 handlerSaveStatePacket(this,SaveStateMessage.AgentData.AgentID);
10062 return true;
10063 }
10064 return false;
10065 }
10066
10067 private bool HandleGodKickUser(IClientAPI sender, Packet Pack)
10068 {
10069 GodKickUserPacket gkupack = (GodKickUserPacket)Pack;
10070
10071 if (gkupack.UserInfo.GodSessionID == SessionId && AgentId == gkupack.UserInfo.GodID)
10072 {
10073 GodKickUser handlerGodKickUser = OnGodKickUser;
10074 if (handlerGodKickUser != null)
10075 {
10076 handlerGodKickUser(gkupack.UserInfo.GodID, gkupack.UserInfo.GodSessionID,
10077 gkupack.UserInfo.AgentID, gkupack.UserInfo.KickFlags, gkupack.UserInfo.Reason);
10078 }
10079 }
10080 else
10081 {
10082 SendAgentAlertMessage("Kick request denied", false);
10083 }
10084 //KickUserPacket kupack = new KickUserPacket();
10085 //KickUserPacket.UserInfoBlock kupackib = kupack.UserInfo;
10086
10087 //kupack.UserInfo.AgentID = gkupack.UserInfo.AgentID;
10088 //kupack.UserInfo.SessionID = gkupack.UserInfo.GodSessionID;
10089
10090 //kupack.TargetBlock.TargetIP = (uint)0;
10091 //kupack.TargetBlock.TargetPort = (ushort)0;
10092 //kupack.UserInfo.Reason = gkupack.UserInfo.Reason;
10093
10094 //OutPacket(kupack, ThrottleOutPacketType.Task);
10095 return true;
10096 }
10097 #endregion GodPackets
10098
10099 #region Economy/Transaction Packets
10100
10101 private bool HandleMoneyBalanceRequest(IClientAPI sender, Packet Pack)
10102 {
10103 MoneyBalanceRequestPacket moneybalancerequestpacket = (MoneyBalanceRequestPacket)Pack;
10104
10105 #region Packet Session and User Check
10106 if (m_checkPackets)
10107 {
10108 if (moneybalancerequestpacket.AgentData.SessionID != SessionId ||
10109 moneybalancerequestpacket.AgentData.AgentID != AgentId)
10110 return true;
10111 }
10112 #endregion
10113
10114 MoneyBalanceRequest handlerMoneyBalanceRequest = OnMoneyBalanceRequest;
10115
10116 if (handlerMoneyBalanceRequest != null)
10117 {
10118 handlerMoneyBalanceRequest(this, moneybalancerequestpacket.AgentData.AgentID, moneybalancerequestpacket.AgentData.SessionID, moneybalancerequestpacket.MoneyData.TransactionID);
10119 }
10120
10121 return true;
10122 }
10123 private bool HandleEconomyDataRequest(IClientAPI sender, Packet Pack)
10124 {
10125 EconomyDataRequest handlerEconomoyDataRequest = OnEconomyDataRequest;
10126 if (handlerEconomoyDataRequest != null)
10127 {
10128 handlerEconomoyDataRequest(this);
10129 }
10130 return true;
10131 }
10132 private bool HandleRequestPayPrice(IClientAPI sender, Packet Pack)
10133 {
10134 RequestPayPricePacket requestPayPricePacket = (RequestPayPricePacket)Pack;
10135
10136 RequestPayPrice handlerRequestPayPrice = OnRequestPayPrice;
10137 if (handlerRequestPayPrice != null)
10138 {
10139 handlerRequestPayPrice(this, requestPayPricePacket.ObjectData.ObjectID);
10140 }
10141 return true;
10142 }
10143 private bool HandleObjectSaleInfo(IClientAPI sender, Packet Pack)
10144 {
10145 ObjectSaleInfoPacket objectSaleInfoPacket = (ObjectSaleInfoPacket)Pack;
10146
10147 #region Packet Session and User Check
10148 if (m_checkPackets)
10149 {
10150 if (objectSaleInfoPacket.AgentData.SessionID != SessionId ||
10151 objectSaleInfoPacket.AgentData.AgentID != AgentId)
10152 return true;
10153 }
10154 #endregion
10155
10156 ObjectSaleInfo handlerObjectSaleInfo = OnObjectSaleInfo;
10157 if (handlerObjectSaleInfo != null)
10158 {
10159 foreach (ObjectSaleInfoPacket.ObjectDataBlock d
10160 in objectSaleInfoPacket.ObjectData)
10161 {
10162 handlerObjectSaleInfo(this,
10163 objectSaleInfoPacket.AgentData.AgentID,
10164 objectSaleInfoPacket.AgentData.SessionID,
10165 d.LocalID,
10166 d.SaleType,
10167 d.SalePrice);
10168 }
10169 }
10170 return true;
10171 }
10172 private bool HandleObjectBuy(IClientAPI sender, Packet Pack)
10173 {
10174 ObjectBuyPacket objectBuyPacket = (ObjectBuyPacket)Pack;
10175
10176 #region Packet Session and User Check
10177 if (m_checkPackets)
10178 {
10179 if (objectBuyPacket.AgentData.SessionID != SessionId ||
10180 objectBuyPacket.AgentData.AgentID != AgentId)
10181 return true;
10182 }
10183 #endregion
10184
10185 ObjectBuy handlerObjectBuy = OnObjectBuy;
10186
10187 if (handlerObjectBuy != null)
10188 {
10189 foreach (ObjectBuyPacket.ObjectDataBlock d
10190 in objectBuyPacket.ObjectData)
10191 {
10192 handlerObjectBuy(this,
10193 objectBuyPacket.AgentData.AgentID,
10194 objectBuyPacket.AgentData.SessionID,
10195 objectBuyPacket.AgentData.GroupID,
10196 objectBuyPacket.AgentData.CategoryID,
10197 d.ObjectLocalID,
10198 d.SaleType,
10199 d.SalePrice);
10200 }
10201 }
10202 return true;
10203 }
10204
10205 #endregion Economy/Transaction Packets
10206
10207 #region Script Packets
10208 private bool HandleGetScriptRunning(IClientAPI sender, Packet Pack)
10209 {
10210 GetScriptRunningPacket scriptRunning = (GetScriptRunningPacket)Pack;
10211
10212 GetScriptRunning handlerGetScriptRunning = OnGetScriptRunning;
10213 if (handlerGetScriptRunning != null)
10214 {
10215 handlerGetScriptRunning(this, scriptRunning.Script.ObjectID, scriptRunning.Script.ItemID);
10216 }
10217 return true;
10218 }
10219 private bool HandleSetScriptRunning(IClientAPI sender, Packet Pack)
10220 {
10221 SetScriptRunningPacket setScriptRunning = (SetScriptRunningPacket)Pack;
10222
10223 #region Packet Session and User Check
10224 if (m_checkPackets)
10225 {
10226 if (setScriptRunning.AgentData.SessionID != SessionId ||
10227 setScriptRunning.AgentData.AgentID != AgentId)
10228 return true;
10229 }
10230 #endregion
10231
10232 SetScriptRunning handlerSetScriptRunning = OnSetScriptRunning;
10233 if (handlerSetScriptRunning != null)
10234 {
10235 handlerSetScriptRunning(this, setScriptRunning.Script.ObjectID, setScriptRunning.Script.ItemID, setScriptRunning.Script.Running);
10236 }
10237 return true;
10238 }
10239
10240 private bool HandleScriptReset(IClientAPI sender, Packet Pack)
10241 {
10242 ScriptResetPacket scriptResetPacket = (ScriptResetPacket)Pack;
10243
10244 #region Packet Session and User Check
10245 if (m_checkPackets)
10246 {
10247 if (scriptResetPacket.AgentData.SessionID != SessionId ||
10248 scriptResetPacket.AgentData.AgentID != AgentId)
10249 return true;
10250 }
10251 #endregion
10252
10253 ScriptReset handlerScriptReset = OnScriptReset;
10254 if (handlerScriptReset != null)
10255 {
10256 handlerScriptReset(this, scriptResetPacket.Script.ObjectID, scriptResetPacket.Script.ItemID);
10257 }
10258 return true;
10259 }
10260
10261 #endregion Script Packets
10262
10263 #region Gesture Managment
10264
10265 private bool HandleActivateGestures(IClientAPI sender, Packet Pack)
10266 {
10267 ActivateGesturesPacket activateGesturePacket = (ActivateGesturesPacket)Pack;
10268
10269 #region Packet Session and User Check
10270 if (m_checkPackets)
10271 {
10272 if (activateGesturePacket.AgentData.SessionID != SessionId ||
10273 activateGesturePacket.AgentData.AgentID != AgentId)
10274 return true;
10275 }
10276 #endregion
10277
10278 ActivateGesture handlerActivateGesture = OnActivateGesture;
10279 if (handlerActivateGesture != null)
10280 {
10281 handlerActivateGesture(this,
10282 activateGesturePacket.Data[0].AssetID,
10283 activateGesturePacket.Data[0].ItemID);
10284 }
10285 else m_log.Error("Null pointer for activateGesture");
10286
10287 return true;
10288 }
10289 private bool HandleDeactivateGestures(IClientAPI sender, Packet Pack)
10290 {
10291 DeactivateGesturesPacket deactivateGesturePacket = (DeactivateGesturesPacket)Pack;
10292
10293 #region Packet Session and User Check
10294 if (m_checkPackets)
10295 {
10296 if (deactivateGesturePacket.AgentData.SessionID != SessionId ||
10297 deactivateGesturePacket.AgentData.AgentID != AgentId)
10298 return true;
10299 }
10300 #endregion
10301
10302 DeactivateGesture handlerDeactivateGesture = OnDeactivateGesture;
10303 if (handlerDeactivateGesture != null)
10304 {
10305 handlerDeactivateGesture(this, deactivateGesturePacket.Data[0].ItemID);
10306 }
10307 return true;
10308 }
10309 private bool HandleObjectOwner(IClientAPI sender, Packet Pack)
10310 {
10311 ObjectOwnerPacket objectOwnerPacket = (ObjectOwnerPacket)Pack;
10312
10313 #region Packet Session and User Check
10314 if (m_checkPackets)
10315 {
10316 if (objectOwnerPacket.AgentData.SessionID != SessionId ||
10317 objectOwnerPacket.AgentData.AgentID != AgentId)
10318 return true;
10319 }
10320 #endregion
10321
10322 List<uint> localIDs = new List<uint>();
10323
10324 foreach (ObjectOwnerPacket.ObjectDataBlock d in objectOwnerPacket.ObjectData)
10325 localIDs.Add(d.ObjectLocalID);
10326
10327 ObjectOwner handlerObjectOwner = OnObjectOwner;
10328 if (handlerObjectOwner != null)
10329 {
10330 handlerObjectOwner(this, objectOwnerPacket.HeaderData.OwnerID, objectOwnerPacket.HeaderData.GroupID, localIDs);
10331 }
10332 return true;
10333 }
10334
10335 #endregion Gesture Managment
10336
10337 private bool HandleAgentFOV(IClientAPI sender, Packet Pack)
10338 {
10339 AgentFOVPacket fovPacket = (AgentFOVPacket)Pack;
10340
10341 if (fovPacket.FOVBlock.GenCounter > m_agentFOVCounter)
10342 {
10343 m_agentFOVCounter = fovPacket.FOVBlock.GenCounter;
10344 AgentFOV handlerAgentFOV = OnAgentFOV;
10345 if (handlerAgentFOV != null)
10346 {
10347 handlerAgentFOV(this, fovPacket.FOVBlock.VerticalAngle);
10348 }
10349 }
10350 return true;
10351 }
10352
10353 #region unimplemented handlers
10354
10355 private bool HandleViewerStats(IClientAPI sender, Packet Pack)
10356 {
10357 // TODO: handle this packet
10358 //m_log.Warn("[CLIENT]: unhandled ViewerStats packet");
10359 return true;
10360 }
10361
10362 private bool HandleMapItemRequest(IClientAPI sender, Packet Pack)
10363 {
10364 MapItemRequestPacket mirpk = (MapItemRequestPacket)Pack;
10365
10366 #region Packet Session and User Check
10367 if (m_checkPackets)
10368 {
10369 if (mirpk.AgentData.SessionID != SessionId ||
10370 mirpk.AgentData.AgentID != AgentId)
10371 return true;
10372 }
10373 #endregion
10374
10375 //m_log.Debug(mirpk.ToString());
10376 MapItemRequest handlerMapItemRequest = OnMapItemRequest;
10377 if (handlerMapItemRequest != null)
10378 {
10379 handlerMapItemRequest(this, mirpk.AgentData.Flags, mirpk.AgentData.EstateID,
10380 mirpk.AgentData.Godlike, mirpk.RequestData.ItemType,
10381 mirpk.RequestData.RegionHandle);
10382
10383 }
10384 return true;
10385 }
10386
10387 private bool HandleTransferAbort(IClientAPI sender, Packet Pack)
10388 {
10389 return true;
10390 }
10391
10392 private bool HandleMuteListRequest(IClientAPI sender, Packet Pack)
10393 {
10394 MuteListRequestPacket muteListRequest =
10395 (MuteListRequestPacket)Pack;
10396
10397 #region Packet Session and User Check
10398 if (m_checkPackets)
10399 {
10400 if (muteListRequest.AgentData.SessionID != SessionId ||
10401 muteListRequest.AgentData.AgentID != AgentId)
10402 return true;
10403 }
10404 #endregion
10405
10406 MuteListRequest handlerMuteListRequest = OnMuteListRequest;
10407 if (handlerMuteListRequest != null)
10408 {
10409 handlerMuteListRequest(this, muteListRequest.MuteData.MuteCRC);
10410 }
10411 else
10412 {
10413 SendUseCachedMuteList();
10414 }
10415 return true;
10416 }
10417
10418 private bool HandleUpdateMuteListEntry(IClientAPI client, Packet Packet)
10419 {
10420 UpdateMuteListEntryPacket UpdateMuteListEntry =
10421 (UpdateMuteListEntryPacket)Packet;
10422 MuteListEntryUpdate handlerUpdateMuteListEntry = OnUpdateMuteListEntry;
10423 if (handlerUpdateMuteListEntry != null)
10424 {
10425 handlerUpdateMuteListEntry(this, UpdateMuteListEntry.MuteData.MuteID,
10426 Utils.BytesToString(UpdateMuteListEntry.MuteData.MuteName),
10427 UpdateMuteListEntry.MuteData.MuteType,
10428 UpdateMuteListEntry.AgentData.AgentID);
10429 return true;
10430 }
10431 return false;
10432 }
10433
10434 private bool HandleRemoveMuteListEntry(IClientAPI client, Packet Packet)
10435 {
10436 RemoveMuteListEntryPacket RemoveMuteListEntry =
10437 (RemoveMuteListEntryPacket)Packet;
10438 MuteListEntryRemove handlerRemoveMuteListEntry = OnRemoveMuteListEntry;
10439 if (handlerRemoveMuteListEntry != null)
10440 {
10441 handlerRemoveMuteListEntry(this,
10442 RemoveMuteListEntry.MuteData.MuteID,
10443 Utils.BytesToString(RemoveMuteListEntry.MuteData.MuteName),
10444 RemoveMuteListEntry.AgentData.AgentID);
10445 return true;
10446 }
10447 return false;
10448 }
10449
10450 private bool HandleUserReport(IClientAPI client, Packet Packet)
10451 {
10452 UserReportPacket UserReport =
10453 (UserReportPacket)Packet;
10454
10455 NewUserReport handlerUserReport = OnUserReport;
10456 if (handlerUserReport != null)
10457 {
10458 handlerUserReport(this,
10459 Utils.BytesToString(UserReport.ReportData.AbuseRegionName),
10460 UserReport.ReportData.AbuserID,
10461 UserReport.ReportData.Category,
10462 UserReport.ReportData.CheckFlags,
10463 Utils.BytesToString(UserReport.ReportData.Details),
10464 UserReport.ReportData.ObjectID,
10465 UserReport.ReportData.Position,
10466 UserReport.ReportData.ReportType,
10467 UserReport.ReportData.ScreenshotID,
10468 Utils.BytesToString(UserReport.ReportData.Summary),
10469 UserReport.AgentData.AgentID);
10470 return true;
10471 }
10472 return false;
10473 }
10474
10475 private bool HandleSendPostcard(IClientAPI client, Packet packet)
10476 {
10477// SendPostcardPacket SendPostcard =
10478// (SendPostcardPacket)packet;
10479 SendPostcard handlerSendPostcard = OnSendPostcard;
10480 if (handlerSendPostcard != null)
10481 {
10482 handlerSendPostcard(this);
10483 return true;
10484 }
10485 return false;
10486 }
10487
10488 private bool HandleUseCircuitCode(IClientAPI sender, Packet Pack)
10489 {
10490 return true;
10491 }
10492
10493 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack)
10494 {
10495 return true;
10496 }
10497
10498 private bool HandleInventoryDescendents(IClientAPI sender, Packet Pack)
10499 {
10500 return true;
10501 }
10502
10503 #endregion unimplemented handlers
10504
10505 #region Dir handlers
10506
10507 private bool HandleDirPlacesQuery(IClientAPI sender, Packet Pack)
10508 {
10509 DirPlacesQueryPacket dirPlacesQueryPacket = (DirPlacesQueryPacket)Pack;
10510 //m_log.Debug(dirPlacesQueryPacket.ToString());
10511
10512 #region Packet Session and User Check
10513 if (m_checkPackets)
10514 {
10515 if (dirPlacesQueryPacket.AgentData.SessionID != SessionId ||
10516 dirPlacesQueryPacket.AgentData.AgentID != AgentId)
10517 return true;
10518 }
10519 #endregion
10520
10521 DirPlacesQuery handlerDirPlacesQuery = OnDirPlacesQuery;
10522 if (handlerDirPlacesQuery != null)
10523 {
10524 handlerDirPlacesQuery(this,
10525 dirPlacesQueryPacket.QueryData.QueryID,
10526 Utils.BytesToString(
10527 dirPlacesQueryPacket.QueryData.QueryText),
10528 (int)dirPlacesQueryPacket.QueryData.QueryFlags,
10529 (int)dirPlacesQueryPacket.QueryData.Category,
10530 Utils.BytesToString(
10531 dirPlacesQueryPacket.QueryData.SimName),
10532 dirPlacesQueryPacket.QueryData.QueryStart);
10533 }
10534 return true;
10535 }
10536
10537 private bool HandleDirFindQuery(IClientAPI sender, Packet Pack)
10538 {
10539 DirFindQueryPacket dirFindQueryPacket = (DirFindQueryPacket)Pack;
10540
10541 #region Packet Session and User Check
10542 if (m_checkPackets)
10543 {
10544 if (dirFindQueryPacket.AgentData.SessionID != SessionId ||
10545 dirFindQueryPacket.AgentData.AgentID != AgentId)
10546 return true;
10547 }
10548 #endregion
10549
10550 DirFindQuery handlerDirFindQuery = OnDirFindQuery;
10551 if (handlerDirFindQuery != null)
10552 {
10553 handlerDirFindQuery(this,
10554 dirFindQueryPacket.QueryData.QueryID,
10555 Utils.BytesToString(
10556 dirFindQueryPacket.QueryData.QueryText).Trim(),
10557 dirFindQueryPacket.QueryData.QueryFlags,
10558 dirFindQueryPacket.QueryData.QueryStart);
10559 }
10560 return true;
10561 }
10562
10563 private bool HandleDirLandQuery(IClientAPI sender, Packet Pack)
10564 {
10565 DirLandQueryPacket dirLandQueryPacket = (DirLandQueryPacket)Pack;
10566
10567 #region Packet Session and User Check
10568 if (m_checkPackets)
10569 {
10570 if (dirLandQueryPacket.AgentData.SessionID != SessionId ||
10571 dirLandQueryPacket.AgentData.AgentID != AgentId)
10572 return true;
10573 }
10574 #endregion
10575
10576 DirLandQuery handlerDirLandQuery = OnDirLandQuery;
10577 if (handlerDirLandQuery != null)
10578 {
10579 handlerDirLandQuery(this,
10580 dirLandQueryPacket.QueryData.QueryID,
10581 dirLandQueryPacket.QueryData.QueryFlags,
10582 dirLandQueryPacket.QueryData.SearchType,
10583 dirLandQueryPacket.QueryData.Price,
10584 dirLandQueryPacket.QueryData.Area,
10585 dirLandQueryPacket.QueryData.QueryStart);
10586 }
10587 return true;
10588 }
10589
10590 private bool HandleDirPopularQuery(IClientAPI sender, Packet Pack)
10591 {
10592 DirPopularQueryPacket dirPopularQueryPacket = (DirPopularQueryPacket)Pack;
10593
10594 #region Packet Session and User Check
10595 if (m_checkPackets)
10596 {
10597 if (dirPopularQueryPacket.AgentData.SessionID != SessionId ||
10598 dirPopularQueryPacket.AgentData.AgentID != AgentId)
10599 return true;
10600 }
10601 #endregion
10602
10603 DirPopularQuery handlerDirPopularQuery = OnDirPopularQuery;
10604 if (handlerDirPopularQuery != null)
10605 {
10606 handlerDirPopularQuery(this,
10607 dirPopularQueryPacket.QueryData.QueryID,
10608 dirPopularQueryPacket.QueryData.QueryFlags);
10609 }
10610 return true;
10611 }
10612
10613 private bool HandleDirClassifiedQuery(IClientAPI sender, Packet Pack)
10614 {
10615 DirClassifiedQueryPacket dirClassifiedQueryPacket = (DirClassifiedQueryPacket)Pack;
10616
10617 #region Packet Session and User Check
10618 if (m_checkPackets)
10619 {
10620 if (dirClassifiedQueryPacket.AgentData.SessionID != SessionId ||
10621 dirClassifiedQueryPacket.AgentData.AgentID != AgentId)
10622 return true;
10623 }
10624 #endregion
10625
10626 DirClassifiedQuery handlerDirClassifiedQuery = OnDirClassifiedQuery;
10627 if (handlerDirClassifiedQuery != null)
10628 {
10629 handlerDirClassifiedQuery(this,
10630 dirClassifiedQueryPacket.QueryData.QueryID,
10631 Utils.BytesToString(
10632 dirClassifiedQueryPacket.QueryData.QueryText),
10633 dirClassifiedQueryPacket.QueryData.QueryFlags,
10634 dirClassifiedQueryPacket.QueryData.Category,
10635 dirClassifiedQueryPacket.QueryData.QueryStart);
10636 }
10637 return true;
10638 }
10639
10640 private bool HandleEventInfoRequest(IClientAPI sender, Packet Pack)
10641 {
10642 EventInfoRequestPacket eventInfoRequestPacket = (EventInfoRequestPacket)Pack;
10643
10644 #region Packet Session and User Check
10645 if (m_checkPackets)
10646 {
10647 if (eventInfoRequestPacket.AgentData.SessionID != SessionId ||
10648 eventInfoRequestPacket.AgentData.AgentID != AgentId)
10649 return true;
10650 }
10651 #endregion
10652
10653 if (OnEventInfoRequest != null)
10654 {
10655 OnEventInfoRequest(this, eventInfoRequestPacket.EventData.EventID);
10656 }
10657 return true;
10658 }
10659
10660 #endregion
10661
10662 #region Calling Card
10663
10664 private bool HandleOfferCallingCard(IClientAPI sender, Packet Pack)
10665 {
10666 OfferCallingCardPacket offerCallingCardPacket = (OfferCallingCardPacket)Pack;
10667
10668 #region Packet Session and User Check
10669 if (m_checkPackets)
10670 {
10671 if (offerCallingCardPacket.AgentData.SessionID != SessionId ||
10672 offerCallingCardPacket.AgentData.AgentID != AgentId)
10673 return true;
10674 }
10675 #endregion
10676
10677 if (OnOfferCallingCard != null)
10678 {
10679 OnOfferCallingCard(this,
10680 offerCallingCardPacket.AgentBlock.DestID,
10681 offerCallingCardPacket.AgentBlock.TransactionID);
10682 }
10683 return true;
10684 }
10685
10686 private bool HandleAcceptCallingCard(IClientAPI sender, Packet Pack)
10687 {
10688 AcceptCallingCardPacket acceptCallingCardPacket = (AcceptCallingCardPacket)Pack;
10689
10690 #region Packet Session and User Check
10691 if (m_checkPackets)
10692 {
10693 if (acceptCallingCardPacket.AgentData.SessionID != SessionId ||
10694 acceptCallingCardPacket.AgentData.AgentID != AgentId)
10695 return true;
10696 }
10697 #endregion
10698
10699 // according to http://wiki.secondlife.com/wiki/AcceptCallingCard FolderData should
10700 // contain exactly one entry
10701 if (OnAcceptCallingCard != null && acceptCallingCardPacket.FolderData.Length > 0)
10702 {
10703 OnAcceptCallingCard(this,
10704 acceptCallingCardPacket.TransactionBlock.TransactionID,
10705 acceptCallingCardPacket.FolderData[0].FolderID);
10706 }
10707 return true;
10708 }
10709
10710 private bool HandleDeclineCallingCard(IClientAPI sender, Packet Pack)
10711 {
10712 DeclineCallingCardPacket declineCallingCardPacket = (DeclineCallingCardPacket)Pack;
10713
10714 #region Packet Session and User Check
10715 if (m_checkPackets)
10716 {
10717 if (declineCallingCardPacket.AgentData.SessionID != SessionId ||
10718 declineCallingCardPacket.AgentData.AgentID != AgentId)
10719 return true;
10720 }
10721 #endregion
10722
10723 if (OnDeclineCallingCard != null)
10724 {
10725 OnDeclineCallingCard(this,
10726 declineCallingCardPacket.TransactionBlock.TransactionID);
10727 }
10728 return true;
10729 }
10730
10731 #endregion Calling Card
10732
10733 #region Groups
10734
10735 private bool HandleActivateGroup(IClientAPI sender, Packet Pack)
10736 {
10737 ActivateGroupPacket activateGroupPacket = (ActivateGroupPacket)Pack;
10738
10739 #region Packet Session and User Check
10740 if (m_checkPackets)
10741 {
10742 if (activateGroupPacket.AgentData.SessionID != SessionId ||
10743 activateGroupPacket.AgentData.AgentID != AgentId)
10744 return true;
10745 }
10746 #endregion
10747
10748 if (m_GroupsModule != null)
10749 {
10750 m_GroupsModule.ActivateGroup(this, activateGroupPacket.AgentData.GroupID);
10751 m_GroupsModule.SendAgentGroupDataUpdate(this);
10752 }
10753 return true;
10754
10755 }
10756
10757 private bool HandleGroupVoteHistoryRequest(IClientAPI client, Packet Packet)
10758 {
10759 GroupVoteHistoryRequestPacket GroupVoteHistoryRequest =
10760 (GroupVoteHistoryRequestPacket)Packet;
10761 GroupVoteHistoryRequest handlerGroupVoteHistoryRequest = OnGroupVoteHistoryRequest;
10762 if (handlerGroupVoteHistoryRequest != null)
10763 {
10764 handlerGroupVoteHistoryRequest(this, GroupVoteHistoryRequest.AgentData.AgentID,GroupVoteHistoryRequest.AgentData.SessionID,GroupVoteHistoryRequest.GroupData.GroupID,GroupVoteHistoryRequest.TransactionData.TransactionID);
10765 return true;
10766 }
10767 return false;
10768 }
10769
10770 private bool HandleGroupActiveProposalsRequest(IClientAPI client, Packet Packet)
10771 {
10772 GroupActiveProposalsRequestPacket GroupActiveProposalsRequest =
10773 (GroupActiveProposalsRequestPacket)Packet;
10774 GroupActiveProposalsRequest handlerGroupActiveProposalsRequest = OnGroupActiveProposalsRequest;
10775 if (handlerGroupActiveProposalsRequest != null)
10776 {
10777 handlerGroupActiveProposalsRequest(this, GroupActiveProposalsRequest.AgentData.AgentID,GroupActiveProposalsRequest.AgentData.SessionID,GroupActiveProposalsRequest.GroupData.GroupID,GroupActiveProposalsRequest.TransactionData.TransactionID);
10778 return true;
10779 }
10780 return false;
10781 }
10782
10783 private bool HandleGroupAccountDetailsRequest(IClientAPI client, Packet Packet)
10784 {
10785 GroupAccountDetailsRequestPacket GroupAccountDetailsRequest =
10786 (GroupAccountDetailsRequestPacket)Packet;
10787 GroupAccountDetailsRequest handlerGroupAccountDetailsRequest = OnGroupAccountDetailsRequest;
10788 if (handlerGroupAccountDetailsRequest != null)
10789 {
10790 handlerGroupAccountDetailsRequest(this, GroupAccountDetailsRequest.AgentData.AgentID,GroupAccountDetailsRequest.AgentData.GroupID,GroupAccountDetailsRequest.MoneyData.RequestID,GroupAccountDetailsRequest.AgentData.SessionID);
10791 return true;
10792 }
10793 return false;
10794 }
10795
10796 private bool HandleGroupAccountSummaryRequest(IClientAPI client, Packet Packet)
10797 {
10798 GroupAccountSummaryRequestPacket GroupAccountSummaryRequest =
10799 (GroupAccountSummaryRequestPacket)Packet;
10800 GroupAccountSummaryRequest handlerGroupAccountSummaryRequest = OnGroupAccountSummaryRequest;
10801 if (handlerGroupAccountSummaryRequest != null)
10802 {
10803 handlerGroupAccountSummaryRequest(this, GroupAccountSummaryRequest.AgentData.AgentID,GroupAccountSummaryRequest.AgentData.GroupID);
10804 return true;
10805 }
10806 return false;
10807 }
10808
10809 private bool HandleGroupTransactionsDetailsRequest(IClientAPI client, Packet Packet)
10810 {
10811 GroupAccountTransactionsRequestPacket GroupAccountTransactionsRequest =
10812 (GroupAccountTransactionsRequestPacket)Packet;
10813 GroupAccountTransactionsRequest handlerGroupAccountTransactionsRequest = OnGroupAccountTransactionsRequest;
10814 if (handlerGroupAccountTransactionsRequest != null)
10815 {
10816 handlerGroupAccountTransactionsRequest(this, GroupAccountTransactionsRequest.AgentData.AgentID,GroupAccountTransactionsRequest.AgentData.GroupID,GroupAccountTransactionsRequest.MoneyData.RequestID,GroupAccountTransactionsRequest.AgentData.SessionID);
10817 return true;
10818 }
10819 return false;
10820 }
10821
10822 private bool HandleGroupTitlesRequest(IClientAPI sender, Packet Pack)
10823 {
10824 GroupTitlesRequestPacket groupTitlesRequest =
10825 (GroupTitlesRequestPacket)Pack;
10826
10827 #region Packet Session and User Check
10828 if (m_checkPackets)
10829 {
10830 if (groupTitlesRequest.AgentData.SessionID != SessionId ||
10831 groupTitlesRequest.AgentData.AgentID != AgentId)
10832 return true;
10833 }
10834 #endregion
10835
10836 if (m_GroupsModule != null)
10837 {
10838 GroupTitlesReplyPacket groupTitlesReply = (GroupTitlesReplyPacket)PacketPool.Instance.GetPacket(PacketType.GroupTitlesReply);
10839
10840 groupTitlesReply.AgentData =
10841 new GroupTitlesReplyPacket.AgentDataBlock();
10842
10843 groupTitlesReply.AgentData.AgentID = AgentId;
10844 groupTitlesReply.AgentData.GroupID =
10845 groupTitlesRequest.AgentData.GroupID;
10846
10847 groupTitlesReply.AgentData.RequestID =
10848 groupTitlesRequest.AgentData.RequestID;
10849
10850 List<GroupTitlesData> titles =
10851 m_GroupsModule.GroupTitlesRequest(this,
10852 groupTitlesRequest.AgentData.GroupID);
10853
10854 groupTitlesReply.GroupData =
10855 new GroupTitlesReplyPacket.GroupDataBlock[titles.Count];
10856
10857 int i = 0;
10858 foreach (GroupTitlesData d in titles)
10859 {
10860 groupTitlesReply.GroupData[i] =
10861 new GroupTitlesReplyPacket.GroupDataBlock();
10862
10863 groupTitlesReply.GroupData[i].Title =
10864 Util.StringToBytes256(d.Name);
10865 groupTitlesReply.GroupData[i].RoleID =
10866 d.UUID;
10867 groupTitlesReply.GroupData[i].Selected =
10868 d.Selected;
10869 i++;
10870 }
10871
10872 OutPacket(groupTitlesReply, ThrottleOutPacketType.Task);
10873 }
10874 return true;
10875 }
10876 private bool HandleGroupProfileRequest(IClientAPI sender, Packet Pack)
10877 {
10878 GroupProfileRequestPacket groupProfileRequest =
10879 (GroupProfileRequestPacket)Pack;
10880
10881 #region Packet Session and User Check
10882 if (m_checkPackets)
10883 {
10884 if (groupProfileRequest.AgentData.SessionID != SessionId ||
10885 groupProfileRequest.AgentData.AgentID != AgentId)
10886 return true;
10887 }
10888 #endregion
10889
10890 if (m_GroupsModule != null)
10891 {
10892 GroupProfileReplyPacket groupProfileReply = (GroupProfileReplyPacket)PacketPool.Instance.GetPacket(PacketType.GroupProfileReply);
10893
10894 groupProfileReply.AgentData = new GroupProfileReplyPacket.AgentDataBlock();
10895 groupProfileReply.GroupData = new GroupProfileReplyPacket.GroupDataBlock();
10896 groupProfileReply.AgentData.AgentID = AgentId;
10897
10898 GroupProfileData d = m_GroupsModule.GroupProfileRequest(this,
10899 groupProfileRequest.GroupData.GroupID);
10900
10901 groupProfileReply.GroupData.GroupID = d.GroupID;
10902 groupProfileReply.GroupData.Name = Util.StringToBytes256(d.Name);
10903 groupProfileReply.GroupData.Charter = Util.StringToBytes1024(d.Charter);
10904 groupProfileReply.GroupData.ShowInList = d.ShowInList;
10905 groupProfileReply.GroupData.MemberTitle = Util.StringToBytes256(d.MemberTitle);
10906 groupProfileReply.GroupData.PowersMask = d.PowersMask;
10907 groupProfileReply.GroupData.InsigniaID = d.InsigniaID;
10908 groupProfileReply.GroupData.FounderID = d.FounderID;
10909 groupProfileReply.GroupData.MembershipFee = d.MembershipFee;
10910 groupProfileReply.GroupData.OpenEnrollment = d.OpenEnrollment;
10911 groupProfileReply.GroupData.Money = d.Money;
10912 groupProfileReply.GroupData.GroupMembershipCount = d.GroupMembershipCount;
10913 groupProfileReply.GroupData.GroupRolesCount = d.GroupRolesCount;
10914 groupProfileReply.GroupData.AllowPublish = d.AllowPublish;
10915 groupProfileReply.GroupData.MaturePublish = d.MaturePublish;
10916 groupProfileReply.GroupData.OwnerRole = d.OwnerRole;
10917
10918 OutPacket(groupProfileReply, ThrottleOutPacketType.Task);
10919 }
10920 return true;
10921 }
10922 private bool HandleGroupMembersRequest(IClientAPI sender, Packet Pack)
10923 {
10924 GroupMembersRequestPacket groupMembersRequestPacket =
10925 (GroupMembersRequestPacket)Pack;
10926
10927 #region Packet Session and User Check
10928 if (m_checkPackets)
10929 {
10930 if (groupMembersRequestPacket.AgentData.SessionID != SessionId ||
10931 groupMembersRequestPacket.AgentData.AgentID != AgentId)
10932 return true;
10933 }
10934 #endregion
10935
10936 if (m_GroupsModule != null)
10937 {
10938 List<GroupMembersData> members =
10939 m_GroupsModule.GroupMembersRequest(this, groupMembersRequestPacket.GroupData.GroupID);
10940
10941 int memberCount = members.Count;
10942
10943 while (true)
10944 {
10945 int blockCount = members.Count;
10946 if (blockCount > 40)
10947 blockCount = 40;
10948
10949 GroupMembersReplyPacket groupMembersReply = (GroupMembersReplyPacket)PacketPool.Instance.GetPacket(PacketType.GroupMembersReply);
10950
10951 groupMembersReply.AgentData =
10952 new GroupMembersReplyPacket.AgentDataBlock();
10953 groupMembersReply.GroupData =
10954 new GroupMembersReplyPacket.GroupDataBlock();
10955 groupMembersReply.MemberData =
10956 new GroupMembersReplyPacket.MemberDataBlock[
10957 blockCount];
10958
10959 groupMembersReply.AgentData.AgentID = AgentId;
10960 groupMembersReply.GroupData.GroupID =
10961 groupMembersRequestPacket.GroupData.GroupID;
10962 groupMembersReply.GroupData.RequestID =
10963 groupMembersRequestPacket.GroupData.RequestID;
10964 groupMembersReply.GroupData.MemberCount = memberCount;
10965
10966 for (int i = 0; i < blockCount; i++)
10967 {
10968 GroupMembersData m = members[0];
10969 members.RemoveAt(0);
10970
10971 groupMembersReply.MemberData[i] =
10972 new GroupMembersReplyPacket.MemberDataBlock();
10973 groupMembersReply.MemberData[i].AgentID =
10974 m.AgentID;
10975 groupMembersReply.MemberData[i].Contribution =
10976 m.Contribution;
10977 groupMembersReply.MemberData[i].OnlineStatus =
10978 Util.StringToBytes256(m.OnlineStatus);
10979 groupMembersReply.MemberData[i].AgentPowers =
10980 m.AgentPowers;
10981 groupMembersReply.MemberData[i].Title =
10982 Util.StringToBytes256(m.Title);
10983 groupMembersReply.MemberData[i].IsOwner =
10984 m.IsOwner;
10985 }
10986 OutPacket(groupMembersReply, ThrottleOutPacketType.Task);
10987 if (members.Count == 0)
10988 return true;
10989 }
10990 }
10991 return true;
10992 }
10993 private bool HandleGroupRoleDataRequest(IClientAPI sender, Packet Pack)
10994 {
10995 GroupRoleDataRequestPacket groupRolesRequest =
10996 (GroupRoleDataRequestPacket)Pack;
10997
10998 #region Packet Session and User Check
10999 if (m_checkPackets)
11000 {
11001 if (groupRolesRequest.AgentData.SessionID != SessionId ||
11002 groupRolesRequest.AgentData.AgentID != AgentId)
11003 return true;
11004 }
11005 #endregion
11006
11007 if (m_GroupsModule != null)
11008 {
11009 GroupRoleDataReplyPacket groupRolesReply = (GroupRoleDataReplyPacket)PacketPool.Instance.GetPacket(PacketType.GroupRoleDataReply);
11010
11011 groupRolesReply.AgentData =
11012 new GroupRoleDataReplyPacket.AgentDataBlock();
11013
11014 groupRolesReply.AgentData.AgentID = AgentId;
11015
11016 groupRolesReply.GroupData =
11017 new GroupRoleDataReplyPacket.GroupDataBlock();
11018
11019 groupRolesReply.GroupData.GroupID =
11020 groupRolesRequest.GroupData.GroupID;
11021
11022 groupRolesReply.GroupData.RequestID =
11023 groupRolesRequest.GroupData.RequestID;
11024
11025 List<GroupRolesData> titles =
11026 m_GroupsModule.GroupRoleDataRequest(this,
11027 groupRolesRequest.GroupData.GroupID);
11028
11029 groupRolesReply.GroupData.RoleCount =
11030 titles.Count;
11031
11032 groupRolesReply.RoleData =
11033 new GroupRoleDataReplyPacket.RoleDataBlock[titles.Count];
11034
11035 int i = 0;
11036 foreach (GroupRolesData d in titles)
11037 {
11038 groupRolesReply.RoleData[i] =
11039 new GroupRoleDataReplyPacket.RoleDataBlock();
11040
11041 groupRolesReply.RoleData[i].RoleID =
11042 d.RoleID;
11043 groupRolesReply.RoleData[i].Name =
11044 Util.StringToBytes256(d.Name);
11045 groupRolesReply.RoleData[i].Title =
11046 Util.StringToBytes256(d.Title);
11047 groupRolesReply.RoleData[i].Description =
11048 Util.StringToBytes1024(d.Description);
11049 groupRolesReply.RoleData[i].Powers =
11050 d.Powers;
11051 groupRolesReply.RoleData[i].Members =
11052 (uint)d.Members;
11053
11054 i++;
11055 }
11056
11057 OutPacket(groupRolesReply, ThrottleOutPacketType.Task);
11058 }
11059 return true;
11060 }
11061
11062 private bool HandleGroupRoleMembersRequest(IClientAPI sender, Packet Pack)
11063 {
11064 GroupRoleMembersRequestPacket groupRoleMembersRequest =
11065 (GroupRoleMembersRequestPacket)Pack;
11066
11067 #region Packet Session and User Check
11068 if (m_checkPackets)
11069 {
11070 if (groupRoleMembersRequest.AgentData.SessionID != SessionId ||
11071 groupRoleMembersRequest.AgentData.AgentID != AgentId)
11072 return true;
11073 }
11074 #endregion
11075
11076 if (m_GroupsModule != null)
11077 {
11078 List<GroupRoleMembersData> mappings =
11079 m_GroupsModule.GroupRoleMembersRequest(this,
11080 groupRoleMembersRequest.GroupData.GroupID);
11081
11082 int mappingsCount = mappings.Count;
11083
11084 while (mappings.Count > 0)
11085 {
11086 int pairs = mappings.Count;
11087 if (pairs > 32)
11088 pairs = 32;
11089
11090 GroupRoleMembersReplyPacket groupRoleMembersReply = (GroupRoleMembersReplyPacket)PacketPool.Instance.GetPacket(PacketType.GroupRoleMembersReply);
11091 groupRoleMembersReply.AgentData =
11092 new GroupRoleMembersReplyPacket.AgentDataBlock();
11093 groupRoleMembersReply.AgentData.AgentID =
11094 AgentId;
11095 groupRoleMembersReply.AgentData.GroupID =
11096 groupRoleMembersRequest.GroupData.GroupID;
11097 groupRoleMembersReply.AgentData.RequestID =
11098 groupRoleMembersRequest.GroupData.RequestID;
11099
11100 groupRoleMembersReply.AgentData.TotalPairs =
11101 (uint)mappingsCount;
11102
11103 groupRoleMembersReply.MemberData =
11104 new GroupRoleMembersReplyPacket.MemberDataBlock[pairs];
11105
11106 for (int i = 0; i < pairs; i++)
11107 {
11108 GroupRoleMembersData d = mappings[0];
11109 mappings.RemoveAt(0);
11110
11111 groupRoleMembersReply.MemberData[i] =
11112 new GroupRoleMembersReplyPacket.MemberDataBlock();
11113
11114 groupRoleMembersReply.MemberData[i].RoleID =
11115 d.RoleID;
11116 groupRoleMembersReply.MemberData[i].MemberID =
11117 d.MemberID;
11118 }
11119
11120 OutPacket(groupRoleMembersReply, ThrottleOutPacketType.Task);
11121 }
11122 }
11123 return true;
11124 }
11125 private bool HandleCreateGroupRequest(IClientAPI sender, Packet Pack)
11126 {
11127 CreateGroupRequestPacket createGroupRequest =
11128 (CreateGroupRequestPacket)Pack;
11129
11130 #region Packet Session and User Check
11131 if (m_checkPackets)
11132 {
11133 if (createGroupRequest.AgentData.SessionID != SessionId ||
11134 createGroupRequest.AgentData.AgentID != AgentId)
11135 return true;
11136 }
11137 #endregion
11138
11139 if (m_GroupsModule != null)
11140 {
11141 m_GroupsModule.CreateGroup(this,
11142 Utils.BytesToString(createGroupRequest.GroupData.Name),
11143 Utils.BytesToString(createGroupRequest.GroupData.Charter),
11144 createGroupRequest.GroupData.ShowInList,
11145 createGroupRequest.GroupData.InsigniaID,
11146 createGroupRequest.GroupData.MembershipFee,
11147 createGroupRequest.GroupData.OpenEnrollment,
11148 createGroupRequest.GroupData.AllowPublish,
11149 createGroupRequest.GroupData.MaturePublish);
11150 }
11151 return true;
11152 }
11153 private bool HandleUpdateGroupInfo(IClientAPI sender, Packet Pack)
11154 {
11155 UpdateGroupInfoPacket updateGroupInfo =
11156 (UpdateGroupInfoPacket)Pack;
11157
11158 #region Packet Session and User Check
11159 if (m_checkPackets)
11160 {
11161 if (updateGroupInfo.AgentData.SessionID != SessionId ||
11162 updateGroupInfo.AgentData.AgentID != AgentId)
11163 return true;
11164 }
11165 #endregion
11166
11167 if (m_GroupsModule != null)
11168 {
11169 m_GroupsModule.UpdateGroupInfo(this,
11170 updateGroupInfo.GroupData.GroupID,
11171 Utils.BytesToString(updateGroupInfo.GroupData.Charter),
11172 updateGroupInfo.GroupData.ShowInList,
11173 updateGroupInfo.GroupData.InsigniaID,
11174 updateGroupInfo.GroupData.MembershipFee,
11175 updateGroupInfo.GroupData.OpenEnrollment,
11176 updateGroupInfo.GroupData.AllowPublish,
11177 updateGroupInfo.GroupData.MaturePublish);
11178 }
11179
11180 return true;
11181 }
11182 private bool HandleSetGroupAcceptNotices(IClientAPI sender, Packet Pack)
11183 {
11184 SetGroupAcceptNoticesPacket setGroupAcceptNotices =
11185 (SetGroupAcceptNoticesPacket)Pack;
11186
11187 #region Packet Session and User Check
11188 if (m_checkPackets)
11189 {
11190 if (setGroupAcceptNotices.AgentData.SessionID != SessionId ||
11191 setGroupAcceptNotices.AgentData.AgentID != AgentId)
11192 return true;
11193 }
11194 #endregion
11195
11196 if (m_GroupsModule != null)
11197 {
11198 m_GroupsModule.SetGroupAcceptNotices(this,
11199 setGroupAcceptNotices.Data.GroupID,
11200 setGroupAcceptNotices.Data.AcceptNotices,
11201 setGroupAcceptNotices.NewData.ListInProfile);
11202 }
11203
11204 return true;
11205 }
11206 private bool HandleGroupTitleUpdate(IClientAPI sender, Packet Pack)
11207 {
11208 GroupTitleUpdatePacket groupTitleUpdate =
11209 (GroupTitleUpdatePacket)Pack;
11210
11211 #region Packet Session and User Check
11212 if (m_checkPackets)
11213 {
11214 if (groupTitleUpdate.AgentData.SessionID != SessionId ||
11215 groupTitleUpdate.AgentData.AgentID != AgentId)
11216 return true;
11217 }
11218 #endregion
11219
11220 if (m_GroupsModule != null)
11221 {
11222 m_GroupsModule.GroupTitleUpdate(this,
11223 groupTitleUpdate.AgentData.GroupID,
11224 groupTitleUpdate.AgentData.TitleRoleID);
11225 }
11226
11227 return true;
11228 }
11229 private bool HandleParcelDeedToGroup(IClientAPI sender, Packet Pack)
11230 {
11231 ParcelDeedToGroupPacket parcelDeedToGroup = (ParcelDeedToGroupPacket)Pack;
11232 if (m_GroupsModule != null)
11233 {
11234 ParcelDeedToGroup handlerParcelDeedToGroup = OnParcelDeedToGroup;
11235 if (handlerParcelDeedToGroup != null)
11236 {
11237 handlerParcelDeedToGroup(parcelDeedToGroup.Data.LocalID, parcelDeedToGroup.Data.GroupID, this);
11238
11239 }
11240 }
11241
11242 return true;
11243 }
11244 private bool HandleGroupNoticesListRequest(IClientAPI sender, Packet Pack)
11245 {
11246 GroupNoticesListRequestPacket groupNoticesListRequest =
11247 (GroupNoticesListRequestPacket)Pack;
11248
11249 #region Packet Session and User Check
11250 if (m_checkPackets)
11251 {
11252 if (groupNoticesListRequest.AgentData.SessionID != SessionId ||
11253 groupNoticesListRequest.AgentData.AgentID != AgentId)
11254 return true;
11255 }
11256 #endregion
11257
11258 if (m_GroupsModule != null)
11259 {
11260 GroupNoticeData[] gn =
11261 m_GroupsModule.GroupNoticesListRequest(this,
11262 groupNoticesListRequest.Data.GroupID);
11263
11264 GroupNoticesListReplyPacket groupNoticesListReply = (GroupNoticesListReplyPacket)PacketPool.Instance.GetPacket(PacketType.GroupNoticesListReply);
11265 groupNoticesListReply.AgentData =
11266 new GroupNoticesListReplyPacket.AgentDataBlock();
11267 groupNoticesListReply.AgentData.AgentID = AgentId;
11268 groupNoticesListReply.AgentData.GroupID = groupNoticesListRequest.Data.GroupID;
11269
11270 groupNoticesListReply.Data = new GroupNoticesListReplyPacket.DataBlock[gn.Length];
11271
11272 int i = 0;
11273 foreach (GroupNoticeData g in gn)
11274 {
11275 groupNoticesListReply.Data[i] = new GroupNoticesListReplyPacket.DataBlock();
11276 groupNoticesListReply.Data[i].NoticeID =
11277 g.NoticeID;
11278 groupNoticesListReply.Data[i].Timestamp =
11279 g.Timestamp;
11280 groupNoticesListReply.Data[i].FromName =
11281 Util.StringToBytes256(g.FromName);
11282 groupNoticesListReply.Data[i].Subject =
11283 Util.StringToBytes256(g.Subject);
11284 groupNoticesListReply.Data[i].HasAttachment =
11285 g.HasAttachment;
11286 groupNoticesListReply.Data[i].AssetType =
11287 g.AssetType;
11288 i++;
11289 }
11290
11291 OutPacket(groupNoticesListReply, ThrottleOutPacketType.Task);
11292 }
11293
11294 return true;
11295 }
11296 private bool HandleGroupNoticeRequest(IClientAPI sender, Packet Pack)
11297 {
11298 GroupNoticeRequestPacket groupNoticeRequest =
11299 (GroupNoticeRequestPacket)Pack;
11300
11301 #region Packet Session and User Check
11302 if (m_checkPackets)
11303 {
11304 if (groupNoticeRequest.AgentData.SessionID != SessionId ||
11305 groupNoticeRequest.AgentData.AgentID != AgentId)
11306 return true;
11307 }
11308 #endregion
11309
11310 if (m_GroupsModule != null)
11311 {
11312 m_GroupsModule.GroupNoticeRequest(this,
11313 groupNoticeRequest.Data.GroupNoticeID);
11314 }
11315 return true;
11316 }
11317 private bool HandleGroupRoleUpdate(IClientAPI sender, Packet Pack)
11318 {
11319 GroupRoleUpdatePacket groupRoleUpdate =
11320 (GroupRoleUpdatePacket)Pack;
11321
11322 #region Packet Session and User Check
11323 if (m_checkPackets)
11324 {
11325 if (groupRoleUpdate.AgentData.SessionID != SessionId ||
11326 groupRoleUpdate.AgentData.AgentID != AgentId)
11327 return true;
11328 }
11329 #endregion
11330
11331 if (m_GroupsModule != null)
11332 {
11333 foreach (GroupRoleUpdatePacket.RoleDataBlock d in
11334 groupRoleUpdate.RoleData)
11335 {
11336 m_GroupsModule.GroupRoleUpdate(this,
11337 groupRoleUpdate.AgentData.GroupID,
11338 d.RoleID,
11339 Utils.BytesToString(d.Name),
11340 Utils.BytesToString(d.Description),
11341 Utils.BytesToString(d.Title),
11342 d.Powers,
11343 d.UpdateType);
11344 }
11345 m_GroupsModule.NotifyChange(groupRoleUpdate.AgentData.GroupID);
11346 }
11347 return true;
11348 }
11349 private bool HandleGroupRoleChanges(IClientAPI sender, Packet Pack)
11350 {
11351 GroupRoleChangesPacket groupRoleChanges =
11352 (GroupRoleChangesPacket)Pack;
11353
11354 #region Packet Session and User Check
11355 if (m_checkPackets)
11356 {
11357 if (groupRoleChanges.AgentData.SessionID != SessionId ||
11358 groupRoleChanges.AgentData.AgentID != AgentId)
11359 return true;
11360 }
11361 #endregion
11362
11363 if (m_GroupsModule != null)
11364 {
11365 foreach (GroupRoleChangesPacket.RoleChangeBlock d in
11366 groupRoleChanges.RoleChange)
11367 {
11368 m_GroupsModule.GroupRoleChanges(this,
11369 groupRoleChanges.AgentData.GroupID,
11370 d.RoleID,
11371 d.MemberID,
11372 d.Change);
11373 }
11374 m_GroupsModule.NotifyChange(groupRoleChanges.AgentData.GroupID);
11375 }
11376 return true;
11377 }
11378 private bool HandleJoinGroupRequest(IClientAPI sender, Packet Pack)
11379 {
11380 JoinGroupRequestPacket joinGroupRequest =
11381 (JoinGroupRequestPacket)Pack;
11382
11383 #region Packet Session and User Check
11384 if (m_checkPackets)
11385 {
11386 if (joinGroupRequest.AgentData.SessionID != SessionId ||
11387 joinGroupRequest.AgentData.AgentID != AgentId)
11388 return true;
11389 }
11390 #endregion
11391
11392 if (m_GroupsModule != null)
11393 {
11394 m_GroupsModule.JoinGroupRequest(this,
11395 joinGroupRequest.GroupData.GroupID);
11396 }
11397 return true;
11398 }
11399 private bool HandleLeaveGroupRequest(IClientAPI sender, Packet Pack)
11400 {
11401 LeaveGroupRequestPacket leaveGroupRequest =
11402 (LeaveGroupRequestPacket)Pack;
11403
11404 #region Packet Session and User Check
11405 if (m_checkPackets)
11406 {
11407 if (leaveGroupRequest.AgentData.SessionID != SessionId ||
11408 leaveGroupRequest.AgentData.AgentID != AgentId)
11409 return true;
11410 }
11411 #endregion
11412
11413 if (m_GroupsModule != null)
11414 {
11415 m_GroupsModule.LeaveGroupRequest(this,
11416 leaveGroupRequest.GroupData.GroupID);
11417 }
11418 return true;
11419 }
11420 private bool HandleEjectGroupMemberRequest(IClientAPI sender, Packet Pack)
11421 {
11422 EjectGroupMemberRequestPacket ejectGroupMemberRequest =
11423 (EjectGroupMemberRequestPacket)Pack;
11424
11425 #region Packet Session and User Check
11426 if (m_checkPackets)
11427 {
11428 if (ejectGroupMemberRequest.AgentData.SessionID != SessionId ||
11429 ejectGroupMemberRequest.AgentData.AgentID != AgentId)
11430 return true;
11431 }
11432 #endregion
11433
11434 if (m_GroupsModule != null)
11435 {
11436 foreach (EjectGroupMemberRequestPacket.EjectDataBlock e
11437 in ejectGroupMemberRequest.EjectData)
11438 {
11439 m_GroupsModule.EjectGroupMemberRequest(this,
11440 ejectGroupMemberRequest.GroupData.GroupID,
11441 e.EjecteeID);
11442 }
11443 }
11444 return true;
11445 }
11446 private bool HandleInviteGroupRequest(IClientAPI sender, Packet Pack)
11447 {
11448 InviteGroupRequestPacket inviteGroupRequest =
11449 (InviteGroupRequestPacket)Pack;
11450
11451 #region Packet Session and User Check
11452 if (m_checkPackets)
11453 {
11454 if (inviteGroupRequest.AgentData.SessionID != SessionId ||
11455 inviteGroupRequest.AgentData.AgentID != AgentId)
11456 return true;
11457 }
11458 #endregion
11459
11460 if (m_GroupsModule != null)
11461 {
11462 foreach (InviteGroupRequestPacket.InviteDataBlock b in
11463 inviteGroupRequest.InviteData)
11464 {
11465 m_GroupsModule.InviteGroupRequest(this,
11466 inviteGroupRequest.GroupData.GroupID,
11467 b.InviteeID,
11468 b.RoleID);
11469 }
11470 }
11471 return true;
11472 }
11473
11474 #endregion Groups
11475
11476 private bool HandleStartLure(IClientAPI sender, Packet Pack)
11477 {
11478 StartLurePacket startLureRequest = (StartLurePacket)Pack;
11479
11480 #region Packet Session and User Check
11481 if (m_checkPackets)
11482 {
11483 if (startLureRequest.AgentData.SessionID != SessionId ||
11484 startLureRequest.AgentData.AgentID != AgentId)
11485 return true;
11486 }
11487 #endregion
11488
11489 StartLure handlerStartLure = OnStartLure;
11490 if (handlerStartLure != null)
11491 handlerStartLure(startLureRequest.Info.LureType,
11492 Utils.BytesToString(
11493 startLureRequest.Info.Message),
11494 startLureRequest.TargetData[0].TargetID,
11495 this);
11496 return true;
11497 }
11498 private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack)
11499 {
11500 TeleportLureRequestPacket teleportLureRequest =
11501 (TeleportLureRequestPacket)Pack;
11502
11503 #region Packet Session and User Check
11504 if (m_checkPackets)
11505 {
11506 if (teleportLureRequest.Info.SessionID != SessionId ||
11507 teleportLureRequest.Info.AgentID != AgentId)
11508 return true;
11509 }
11510 #endregion
11511
11512 TeleportLureRequest handlerTeleportLureRequest = OnTeleportLureRequest;
11513 if (handlerTeleportLureRequest != null)
11514 handlerTeleportLureRequest(
11515 teleportLureRequest.Info.LureID,
11516 teleportLureRequest.Info.TeleportFlags,
11517 this);
11518 return true;
11519 }
11520 private bool HandleClassifiedInfoRequest(IClientAPI sender, Packet Pack)
11521 {
11522 ClassifiedInfoRequestPacket classifiedInfoRequest =
11523 (ClassifiedInfoRequestPacket)Pack;
11524
11525 #region Packet Session and User Check
11526 if (m_checkPackets)
11527 {
11528 if (classifiedInfoRequest.AgentData.SessionID != SessionId ||
11529 classifiedInfoRequest.AgentData.AgentID != AgentId)
11530 return true;
11531 }
11532 #endregion
11533
11534 ClassifiedInfoRequest handlerClassifiedInfoRequest = OnClassifiedInfoRequest;
11535 if (handlerClassifiedInfoRequest != null)
11536 handlerClassifiedInfoRequest(
11537 classifiedInfoRequest.Data.ClassifiedID,
11538 this);
11539 return true;
11540 }
11541 private bool HandleClassifiedInfoUpdate(IClientAPI sender, Packet Pack)
11542 {
11543 ClassifiedInfoUpdatePacket classifiedInfoUpdate =
11544 (ClassifiedInfoUpdatePacket)Pack;
11545
11546 #region Packet Session and User Check
11547 if (m_checkPackets)
11548 {
11549 if (classifiedInfoUpdate.AgentData.SessionID != SessionId ||
11550 classifiedInfoUpdate.AgentData.AgentID != AgentId)
11551 return true;
11552 }
11553 #endregion
11554
11555 ClassifiedInfoUpdate handlerClassifiedInfoUpdate = OnClassifiedInfoUpdate;
11556 if (handlerClassifiedInfoUpdate != null)
11557 handlerClassifiedInfoUpdate(
11558 classifiedInfoUpdate.Data.ClassifiedID,
11559 classifiedInfoUpdate.Data.Category,
11560 Utils.BytesToString(
11561 classifiedInfoUpdate.Data.Name),
11562 Utils.BytesToString(
11563 classifiedInfoUpdate.Data.Desc),
11564 classifiedInfoUpdate.Data.ParcelID,
11565 classifiedInfoUpdate.Data.ParentEstate,
11566 classifiedInfoUpdate.Data.SnapshotID,
11567 new Vector3(
11568 classifiedInfoUpdate.Data.PosGlobal),
11569 classifiedInfoUpdate.Data.ClassifiedFlags,
11570 classifiedInfoUpdate.Data.PriceForListing,
11571 this);
11572 return true;
11573 }
11574 private bool HandleClassifiedDelete(IClientAPI sender, Packet Pack)
11575 {
11576 ClassifiedDeletePacket classifiedDelete =
11577 (ClassifiedDeletePacket)Pack;
11578
11579 #region Packet Session and User Check
11580 if (m_checkPackets)
11581 {
11582 if (classifiedDelete.AgentData.SessionID != SessionId ||
11583 classifiedDelete.AgentData.AgentID != AgentId)
11584 return true;
11585 }
11586 #endregion
11587
11588 ClassifiedDelete handlerClassifiedDelete = OnClassifiedDelete;
11589 if (handlerClassifiedDelete != null)
11590 handlerClassifiedDelete(
11591 classifiedDelete.Data.ClassifiedID,
11592 this);
11593 return true;
11594 }
11595 private bool HandleClassifiedGodDelete(IClientAPI sender, Packet Pack)
11596 {
11597 ClassifiedGodDeletePacket classifiedGodDelete =
11598 (ClassifiedGodDeletePacket)Pack;
11599
11600 #region Packet Session and User Check
11601 if (m_checkPackets)
11602 {
11603 if (classifiedGodDelete.AgentData.SessionID != SessionId ||
11604 classifiedGodDelete.AgentData.AgentID != AgentId)
11605 return true;
11606 }
11607 #endregion
11608
11609 ClassifiedDelete handlerClassifiedGodDelete = OnClassifiedGodDelete;
11610 if (handlerClassifiedGodDelete != null)
11611 handlerClassifiedGodDelete(
11612 classifiedGodDelete.Data.ClassifiedID,
11613 this);
11614 return true;
11615 }
11616 private bool HandleEventGodDelete(IClientAPI sender, Packet Pack)
11617 {
11618 EventGodDeletePacket eventGodDelete =
11619 (EventGodDeletePacket)Pack;
11620
11621 #region Packet Session and User Check
11622 if (m_checkPackets)
11623 {
11624 if (eventGodDelete.AgentData.SessionID != SessionId ||
11625 eventGodDelete.AgentData.AgentID != AgentId)
11626 return true;
11627 }
11628 #endregion
11629
11630 EventGodDelete handlerEventGodDelete = OnEventGodDelete;
11631 if (handlerEventGodDelete != null)
11632 handlerEventGodDelete(
11633 eventGodDelete.EventData.EventID,
11634 eventGodDelete.QueryData.QueryID,
11635 Utils.BytesToString(
11636 eventGodDelete.QueryData.QueryText),
11637 eventGodDelete.QueryData.QueryFlags,
11638 eventGodDelete.QueryData.QueryStart,
11639 this);
11640 return true;
11641 }
11642 private bool HandleEventNotificationAddRequest(IClientAPI sender, Packet Pack)
11643 {
11644 EventNotificationAddRequestPacket eventNotificationAdd =
11645 (EventNotificationAddRequestPacket)Pack;
11646
11647 #region Packet Session and User Check
11648 if (m_checkPackets)
11649 {
11650 if (eventNotificationAdd.AgentData.SessionID != SessionId ||
11651 eventNotificationAdd.AgentData.AgentID != AgentId)
11652 return true;
11653 }
11654 #endregion
11655
11656 EventNotificationAddRequest handlerEventNotificationAddRequest = OnEventNotificationAddRequest;
11657 if (handlerEventNotificationAddRequest != null)
11658 handlerEventNotificationAddRequest(
11659 eventNotificationAdd.EventData.EventID, this);
11660 return true;
11661 }
11662 private bool HandleEventNotificationRemoveRequest(IClientAPI sender, Packet Pack)
11663 {
11664 EventNotificationRemoveRequestPacket eventNotificationRemove =
11665 (EventNotificationRemoveRequestPacket)Pack;
11666
11667 #region Packet Session and User Check
11668 if (m_checkPackets)
11669 {
11670 if (eventNotificationRemove.AgentData.SessionID != SessionId ||
11671 eventNotificationRemove.AgentData.AgentID != AgentId)
11672 return true;
11673 }
11674 #endregion
11675
11676 EventNotificationRemoveRequest handlerEventNotificationRemoveRequest = OnEventNotificationRemoveRequest;
11677 if (handlerEventNotificationRemoveRequest != null)
11678 handlerEventNotificationRemoveRequest(
11679 eventNotificationRemove.EventData.EventID, this);
11680 return true;
11681 }
11682 private bool HandleRetrieveInstantMessages(IClientAPI sender, Packet Pack)
11683 {
11684 RetrieveInstantMessagesPacket rimpInstantMessagePack = (RetrieveInstantMessagesPacket)Pack;
11685
11686 #region Packet Session and User Check
11687 if (m_checkPackets)
11688 {
11689 if (rimpInstantMessagePack.AgentData.SessionID != SessionId ||
11690 rimpInstantMessagePack.AgentData.AgentID != AgentId)
11691 return true;
11692 }
11693 #endregion
11694
11695 RetrieveInstantMessages handlerRetrieveInstantMessages = OnRetrieveInstantMessages;
11696 if (handlerRetrieveInstantMessages != null)
11697 handlerRetrieveInstantMessages(this);
11698 return true;
11699 }
11700 private bool HandlePickDelete(IClientAPI sender, Packet Pack)
11701 {
11702 PickDeletePacket pickDelete =
11703 (PickDeletePacket)Pack;
11704
11705 #region Packet Session and User Check
11706 if (m_checkPackets)
11707 {
11708 if (pickDelete.AgentData.SessionID != SessionId ||
11709 pickDelete.AgentData.AgentID != AgentId)
11710 return true;
11711 }
11712 #endregion
11713
11714 PickDelete handlerPickDelete = OnPickDelete;
11715 if (handlerPickDelete != null)
11716 handlerPickDelete(this, pickDelete.Data.PickID);
11717 return true;
11718 }
11719 private bool HandlePickGodDelete(IClientAPI sender, Packet Pack)
11720 {
11721 PickGodDeletePacket pickGodDelete =
11722 (PickGodDeletePacket)Pack;
11723
11724 #region Packet Session and User Check
11725 if (m_checkPackets)
11726 {
11727 if (pickGodDelete.AgentData.SessionID != SessionId ||
11728 pickGodDelete.AgentData.AgentID != AgentId)
11729 return true;
11730 }
11731 #endregion
11732
11733 PickGodDelete handlerPickGodDelete = OnPickGodDelete;
11734 if (handlerPickGodDelete != null)
11735 handlerPickGodDelete(this,
11736 pickGodDelete.AgentData.AgentID,
11737 pickGodDelete.Data.PickID,
11738 pickGodDelete.Data.QueryID);
11739 return true;
11740 }
11741 private bool HandlePickInfoUpdate(IClientAPI sender, Packet Pack)
11742 {
11743 PickInfoUpdatePacket pickInfoUpdate =
11744 (PickInfoUpdatePacket)Pack;
11745
11746 #region Packet Session and User Check
11747 if (m_checkPackets)
11748 {
11749 if (pickInfoUpdate.AgentData.SessionID != SessionId ||
11750 pickInfoUpdate.AgentData.AgentID != AgentId)
11751 return true;
11752 }
11753 #endregion
11754
11755 PickInfoUpdate handlerPickInfoUpdate = OnPickInfoUpdate;
11756 if (handlerPickInfoUpdate != null)
11757 handlerPickInfoUpdate(this,
11758 pickInfoUpdate.Data.PickID,
11759 pickInfoUpdate.Data.CreatorID,
11760 pickInfoUpdate.Data.TopPick,
11761 Utils.BytesToString(pickInfoUpdate.Data.Name),
11762 Utils.BytesToString(pickInfoUpdate.Data.Desc),
11763 pickInfoUpdate.Data.SnapshotID,
11764 pickInfoUpdate.Data.SortOrder,
11765 pickInfoUpdate.Data.Enabled);
11766 return true;
11767 }
11768 private bool HandleAvatarNotesUpdate(IClientAPI sender, Packet Pack)
11769 {
11770 AvatarNotesUpdatePacket avatarNotesUpdate =
11771 (AvatarNotesUpdatePacket)Pack;
11772
11773 #region Packet Session and User Check
11774 if (m_checkPackets)
11775 {
11776 if (avatarNotesUpdate.AgentData.SessionID != SessionId ||
11777 avatarNotesUpdate.AgentData.AgentID != AgentId)
11778 return true;
11779 }
11780 #endregion
11781
11782 AvatarNotesUpdate handlerAvatarNotesUpdate = OnAvatarNotesUpdate;
11783 if (handlerAvatarNotesUpdate != null)
11784 handlerAvatarNotesUpdate(this,
11785 avatarNotesUpdate.Data.TargetID,
11786 Utils.BytesToString(avatarNotesUpdate.Data.Notes));
11787 return true;
11788 }
11789 private bool HandleAvatarInterestsUpdate(IClientAPI sender, Packet Pack)
11790 {
11791 AvatarInterestsUpdatePacket avatarInterestUpdate =
11792 (AvatarInterestsUpdatePacket)Pack;
11793
11794 #region Packet Session and User Check
11795 if (m_checkPackets)
11796 {
11797 if (avatarInterestUpdate.AgentData.SessionID != SessionId ||
11798 avatarInterestUpdate.AgentData.AgentID != AgentId)
11799 return true;
11800 }
11801 #endregion
11802
11803 AvatarInterestUpdate handlerAvatarInterestUpdate = OnAvatarInterestUpdate;
11804 if (handlerAvatarInterestUpdate != null)
11805 handlerAvatarInterestUpdate(this,
11806 avatarInterestUpdate.PropertiesData.WantToMask,
11807 Utils.BytesToString(avatarInterestUpdate.PropertiesData.WantToText),
11808 avatarInterestUpdate.PropertiesData.SkillsMask,
11809 Utils.BytesToString(avatarInterestUpdate.PropertiesData.SkillsText),
11810 Utils.BytesToString(avatarInterestUpdate.PropertiesData.LanguagesText));
11811 return true;
11812 }
11813
11814 private bool HandleGrantUserRights(IClientAPI sender, Packet Pack)
11815 {
11816 GrantUserRightsPacket GrantUserRights =
11817 (GrantUserRightsPacket)Pack;
11818 #region Packet Session and User Check
11819 if (m_checkPackets)
11820 {
11821 if (GrantUserRights.AgentData.SessionID != SessionId ||
11822 GrantUserRights.AgentData.AgentID != AgentId)
11823 return true;
11824 }
11825 #endregion
11826
11827 GrantUserFriendRights GrantUserRightsHandler = OnGrantUserRights;
11828 if (GrantUserRightsHandler != null)
11829 GrantUserRightsHandler(this,
11830 GrantUserRights.Rights[0].AgentRelated,
11831 GrantUserRights.Rights[0].RelatedRights);
11832
11833 return true;
11834 }
11835
11836 private bool HandlePlacesQuery(IClientAPI sender, Packet Pack)
11837 {
11838 PlacesQueryPacket placesQueryPacket =
11839 (PlacesQueryPacket)Pack;
11840
11841 PlacesQuery handlerPlacesQuery = OnPlacesQuery;
11842
11843 if (handlerPlacesQuery != null)
11844 handlerPlacesQuery(placesQueryPacket.AgentData.QueryID,
11845 placesQueryPacket.TransactionData.TransactionID,
11846 Utils.BytesToString(
11847 placesQueryPacket.QueryData.QueryText),
11848 placesQueryPacket.QueryData.QueryFlags,
11849 (byte)placesQueryPacket.QueryData.Category,
11850 Utils.BytesToString(
11851 placesQueryPacket.QueryData.SimName),
11852 this);
11853 return true;
11854 }
11855
11856 #endregion Packet Handlers
11857
11858 public void SendScriptQuestion(UUID taskID, string taskName, string ownerName, UUID itemID, int question)
11859 {
11860 ScriptQuestionPacket scriptQuestion = (ScriptQuestionPacket)PacketPool.Instance.GetPacket(PacketType.ScriptQuestion);
11861 scriptQuestion.Data = new ScriptQuestionPacket.DataBlock();
11862 // TODO: don't create new blocks if recycling an old packet
11863 scriptQuestion.Data.TaskID = taskID;
11864 scriptQuestion.Data.ItemID = itemID;
11865 scriptQuestion.Data.Questions = question;
11866 scriptQuestion.Data.ObjectName = Util.StringToBytes256(taskName);
11867 scriptQuestion.Data.ObjectOwner = Util.StringToBytes256(ownerName);
11868
11869 OutPacket(scriptQuestion, ThrottleOutPacketType.Task);
11870 }
11871
11872 /// <summary>
11873 /// Handler called when we receive a logout packet.
11874 /// </summary>
11875 /// <param name="client"></param>
11876 /// <param name="packet"></param>
11877 /// <returns></returns>
11878 protected virtual bool HandleLogout(IClientAPI client, Packet packet)
11879 {
11880 if (packet.Type == PacketType.LogoutRequest)
11881 {
11882 if (((LogoutRequestPacket)packet).AgentData.SessionID != SessionId) return false;
11883 }
11884
11885 return Logout(client);
11886 }
11887
11888 /// <summary>
11889 ///
11890 /// </summary>
11891 /// <param name="client"></param>
11892 /// <returns></returns>
11893 protected virtual bool Logout(IClientAPI client)
11894 {
11895 m_log.InfoFormat("[CLIENT]: Got a logout request for {0} in {1}", Name, Scene.RegionInfo.RegionName);
11896
11897 Action<IClientAPI> handlerLogout = OnLogout;
11898
11899 if (handlerLogout != null)
11900 {
11901 handlerLogout(client);
11902 }
11903
11904 return true;
11905 }
11906
11907 /// <summary>
11908 /// </summary>
11909 /// <remarks>
11910 /// At the moment, we always reply that there is no cached texture.
11911 /// </remarks>
11912 /// <param name="simclient"></param>
11913 /// <param name="packet"></param>
11914 /// <returns></returns>
11915 protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet)
11916 {
11917 AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet;
11918 AgentCachedTextureResponsePacket cachedresp = (AgentCachedTextureResponsePacket)PacketPool.Instance.GetPacket(PacketType.AgentCachedTextureResponse);
11919
11920 if (cachedtex.AgentData.SessionID != SessionId)
11921 return false;
11922
11923
11924 // TODO: don't create new blocks if recycling an old packet
11925 cachedresp.AgentData.AgentID = AgentId;
11926 cachedresp.AgentData.SessionID = m_sessionId;
11927 cachedresp.AgentData.SerialNum = m_cachedTextureSerial;
11928 m_cachedTextureSerial++;
11929 cachedresp.WearableData =
11930 new AgentCachedTextureResponsePacket.WearableDataBlock[cachedtex.WearableData.Length];
11931
11932 int maxWearablesLoop = cachedtex.WearableData.Length;
11933 if (maxWearablesLoop > AvatarWearable.MAX_WEARABLES)
11934 maxWearablesLoop = AvatarWearable.MAX_WEARABLES;
11935
11936 // Find the cached baked textures for this user, if they're available
11937
11938 IAssetService cache = m_scene.AssetService;
11939 IBakedTextureModule bakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
11940
11941 WearableCacheItem[] cacheItems = null;
11942
11943 if (bakedTextureModule != null && cache != null)
11944 {
11945 ScenePresence p = m_scene.GetScenePresence(AgentId);
11946 if (p.Appearance != null)
11947 {
11948 if (p.Appearance.WearableCacheItems == null || p.Appearance.WearableCacheItemsDirty)
11949 {
11950 try
11951 {
11952 cacheItems = bakedTextureModule.Get(AgentId);
11953 p.Appearance.WearableCacheItems = cacheItems;
11954 p.Appearance.WearableCacheItemsDirty = false;
11955 }
11956 catch (Exception)
11957 {
11958 cacheItems = null;
11959 }
11960
11961 }
11962 else if (p.Appearance.WearableCacheItems != null)
11963 {
11964 cacheItems = p.Appearance.WearableCacheItems;
11965 }
11966 }
11967 }
11968
11969 if (cacheItems != null)
11970 {
11971 // We need to make sure the asset stored in the bake is available on this server also by its assetid before we map it to a Cacheid.
11972 // Copy the baked textures to the sim's assets cache (local only).
11973 foreach (WearableCacheItem item in cacheItems)
11974 {
11975 if (cache.GetCached(item.TextureID.ToString()) == null)
11976 {
11977 item.TextureAsset.Temporary = true;
11978 item.TextureAsset.Local = true;
11979 cache.Store(item.TextureAsset);
11980 }
11981 }
11982
11983 // Return the cached textures
11984 for (int i = 0; i < maxWearablesLoop; i++)
11985 {
11986 WearableCacheItem item =
11987 WearableCacheItem.SearchTextureIndex(cachedtex.WearableData[i].TextureIndex, cacheItems);
11988
11989 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11990 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
11991 cachedresp.WearableData[i].HostName = new byte[0];
11992 if (item != null && cachedtex.WearableData[i].ID == item.CacheId)
11993 {
11994 cachedresp.WearableData[i].TextureID = item.TextureID;
11995 }
11996 else
11997 {
11998 cachedresp.WearableData[i].TextureID = UUID.Zero;
11999 }
12000 }
12001 }
12002 else
12003 {
12004 // Cached textures not available
12005 for (int i = 0; i < maxWearablesLoop; i++)
12006 {
12007 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
12008 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
12009 cachedresp.WearableData[i].TextureID = UUID.Zero;
12010 cachedresp.WearableData[i].HostName = new byte[0];
12011 }
12012 }
12013
12014 cachedresp.Header.Zerocoded = true;
12015 OutPacket(cachedresp, ThrottleOutPacketType.Task);
12016
12017 return true;
12018 }
12019
12020 /// <summary>
12021 /// Send a response back to a client when it asks the asset server (via the region server) if it has
12022 /// its appearance texture cached.
12023 /// </summary>
12024 /// <param name="avatar"></param>
12025 /// <param name="serial"></param>
12026 /// <param name="cachedTextures"></param>
12027 /// <returns></returns>
12028 public void SendCachedTextureResponse(ISceneEntity avatar, int serial, List<CachedTextureResponseArg> cachedTextures)
12029 {
12030 ScenePresence presence = avatar as ScenePresence;
12031 if (presence == null)
12032 return;
12033
12034 AgentCachedTextureResponsePacket cachedresp = (AgentCachedTextureResponsePacket)PacketPool.Instance.GetPacket(PacketType.AgentCachedTextureResponse);
12035
12036 // TODO: don't create new blocks if recycling an old packet
12037 cachedresp.AgentData.AgentID = m_agentId;
12038 cachedresp.AgentData.SessionID = m_sessionId;
12039 cachedresp.AgentData.SerialNum = serial;
12040 cachedresp.WearableData = new AgentCachedTextureResponsePacket.WearableDataBlock[cachedTextures.Count];
12041
12042 for (int i = 0; i < cachedTextures.Count; i++)
12043 {
12044 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
12045 cachedresp.WearableData[i].TextureIndex = (byte)cachedTextures[i].BakedTextureIndex;
12046 cachedresp.WearableData[i].TextureID = cachedTextures[i].BakedTextureID;
12047 cachedresp.WearableData[i].HostName = new byte[0];
12048 }
12049
12050 cachedresp.Header.Zerocoded = true;
12051 OutPacket(cachedresp, ThrottleOutPacketType.Task);
12052 }
12053
12054 protected bool HandleMultipleObjUpdate(IClientAPI simClient, Packet packet)
12055 {
12056 MultipleObjectUpdatePacket multipleupdate = (MultipleObjectUpdatePacket)packet;
12057
12058 if (multipleupdate.AgentData.SessionID != SessionId)
12059 return false;
12060
12061// m_log.DebugFormat(
12062// "[CLIENT]: Incoming MultipleObjectUpdatePacket contained {0} blocks", multipleupdate.ObjectData.Length);
12063
12064 Scene tScene = (Scene)m_scene;
12065
12066 for (int i = 0; i < multipleupdate.ObjectData.Length; i++)
12067 {
12068 MultipleObjectUpdatePacket.ObjectDataBlock block = multipleupdate.ObjectData[i];
12069
12070 // Can't act on Null Data
12071 if (block.Data != null)
12072 {
12073 uint localId = block.ObjectLocalID;
12074 SceneObjectPart part = tScene.GetSceneObjectPart(localId);
12075
12076 if (part == null)
12077 {
12078 // It's a ghost! tell the client to delete it from view.
12079 simClient.SendKillObject(new List<uint> { localId });
12080 }
12081 else
12082 {
12083// m_log.DebugFormat(
12084// "[CLIENT]: Processing block {0} type {1} for {2} {3}",
12085// i, block.Type, part.Name, part.LocalId);
12086
12087// // Do this once since fetch parts creates a new array.
12088// SceneObjectPart[] parts = part.ParentGroup.Parts;
12089// for (int j = 0; j < parts.Length; j++)
12090// {
12091// part.StoreUndoState();
12092// parts[j].IgnoreUndoUpdate = true;
12093// }
12094
12095 UpdatePrimGroupRotation handlerUpdatePrimGroupRotation;
12096
12097 switch (block.Type)
12098 {
12099 case 1:
12100 Vector3 pos1 = new Vector3(block.Data, 0);
12101
12102 UpdateVector handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition;
12103 if (handlerUpdatePrimSinglePosition != null)
12104 {
12105 // m_log.Debug("new movement position is " + pos.X + " , " + pos.Y + " , " + pos.Z);
12106 handlerUpdatePrimSinglePosition(localId, pos1, this);
12107 }
12108 break;
12109
12110 case 2:
12111 Quaternion rot1 = new Quaternion(block.Data, 0, true);
12112
12113 UpdatePrimSingleRotation handlerUpdatePrimSingleRotation = OnUpdatePrimSingleRotation;
12114 if (handlerUpdatePrimSingleRotation != null)
12115 {
12116 // m_log.Info("new tab rotation is " + rot1.X + " , " + rot1.Y + " , " + rot1.Z + " , " + rot1.W);
12117 handlerUpdatePrimSingleRotation(localId, rot1, this);
12118 }
12119 break;
12120
12121 case 3:
12122 Vector3 rotPos = new Vector3(block.Data, 0);
12123 Quaternion rot2 = new Quaternion(block.Data, 12, true);
12124
12125 UpdatePrimSingleRotationPosition handlerUpdatePrimSingleRotationPosition = OnUpdatePrimSingleRotationPosition;
12126 if (handlerUpdatePrimSingleRotationPosition != null)
12127 {
12128 // m_log.Debug("new mouse rotation position is " + rotPos.X + " , " + rotPos.Y + " , " + rotPos.Z);
12129 // m_log.Info("new mouse rotation is " + rot2.X + " , " + rot2.Y + " , " + rot2.Z + " , " + rot2.W);
12130 handlerUpdatePrimSingleRotationPosition(localId, rot2, rotPos, this);
12131 }
12132 break;
12133
12134 case 4:
12135 case 20:
12136 Vector3 scale4 = new Vector3(block.Data, 0);
12137
12138 UpdateVector handlerUpdatePrimScale = OnUpdatePrimScale;
12139 if (handlerUpdatePrimScale != null)
12140 {
12141 // m_log.Debug("new scale is " + scale4.X + " , " + scale4.Y + " , " + scale4.Z);
12142 handlerUpdatePrimScale(localId, scale4, this);
12143 }
12144 break;
12145
12146 case 5:
12147 Vector3 scale1 = new Vector3(block.Data, 12);
12148 Vector3 pos11 = new Vector3(block.Data, 0);
12149
12150 handlerUpdatePrimScale = OnUpdatePrimScale;
12151 if (handlerUpdatePrimScale != null)
12152 {
12153 // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
12154 handlerUpdatePrimScale(localId, scale1, this);
12155
12156 handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition;
12157 if (handlerUpdatePrimSinglePosition != null)
12158 {
12159 handlerUpdatePrimSinglePosition(localId, pos11, this);
12160 }
12161 }
12162 break;
12163
12164 case 9:
12165 Vector3 pos2 = new Vector3(block.Data, 0);
12166
12167 UpdateVector handlerUpdateVector = OnUpdatePrimGroupPosition;
12168
12169 if (handlerUpdateVector != null)
12170 {
12171 handlerUpdateVector(localId, pos2, this);
12172 }
12173 break;
12174
12175 case 10:
12176 Quaternion rot3 = new Quaternion(block.Data, 0, true);
12177
12178 UpdatePrimRotation handlerUpdatePrimRotation = OnUpdatePrimGroupRotation;
12179 if (handlerUpdatePrimRotation != null)
12180 {
12181 // Console.WriteLine("new rotation is " + rot3.X + " , " + rot3.Y + " , " + rot3.Z + " , " + rot3.W);
12182 handlerUpdatePrimRotation(localId, rot3, this);
12183 }
12184 break;
12185
12186 case 11:
12187 Vector3 pos3 = new Vector3(block.Data, 0);
12188 Quaternion rot4 = new Quaternion(block.Data, 12, true);
12189
12190 handlerUpdatePrimGroupRotation = OnUpdatePrimGroupMouseRotation;
12191 if (handlerUpdatePrimGroupRotation != null)
12192 {
12193 // m_log.Debug("new rotation position is " + pos.X + " , " + pos.Y + " , " + pos.Z);
12194 // m_log.Debug("new group mouse rotation is " + rot4.X + " , " + rot4.Y + " , " + rot4.Z + " , " + rot4.W);
12195 handlerUpdatePrimGroupRotation(localId, pos3, rot4, this);
12196 }
12197 break;
12198 case 12:
12199 case 28:
12200 Vector3 scale7 = new Vector3(block.Data, 0);
12201
12202 UpdateVector handlerUpdatePrimGroupScale = OnUpdatePrimGroupScale;
12203 if (handlerUpdatePrimGroupScale != null)
12204 {
12205 // m_log.Debug("new scale is " + scale7.X + " , " + scale7.Y + " , " + scale7.Z);
12206 handlerUpdatePrimGroupScale(localId, scale7, this);
12207 }
12208 break;
12209
12210 case 13:
12211 Vector3 scale2 = new Vector3(block.Data, 12);
12212 Vector3 pos4 = new Vector3(block.Data, 0);
12213
12214 handlerUpdatePrimScale = OnUpdatePrimScale;
12215 if (handlerUpdatePrimScale != null)
12216 {
12217 //m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
12218 handlerUpdatePrimScale(localId, scale2, this);
12219
12220 // Change the position based on scale (for bug number 246)
12221 handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition;
12222 // m_log.Debug("new movement position is " + pos.X + " , " + pos.Y + " , " + pos.Z);
12223 if (handlerUpdatePrimSinglePosition != null)
12224 {
12225 handlerUpdatePrimSinglePosition(localId, pos4, this);
12226 }
12227 }
12228 break;
12229
12230 case 29:
12231 Vector3 scale5 = new Vector3(block.Data, 12);
12232 Vector3 pos5 = new Vector3(block.Data, 0);
12233
12234 handlerUpdatePrimGroupScale = OnUpdatePrimGroupScale;
12235 if (handlerUpdatePrimGroupScale != null)
12236 {
12237 // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
12238 part.StoreUndoState(true);
12239 part.IgnoreUndoUpdate = true;
12240 handlerUpdatePrimGroupScale(localId, scale5, this);
12241 handlerUpdateVector = OnUpdatePrimGroupPosition;
12242
12243 if (handlerUpdateVector != null)
12244 {
12245 handlerUpdateVector(localId, pos5, this);
12246 }
12247
12248 part.IgnoreUndoUpdate = false;
12249 }
12250
12251 break;
12252
12253 case 21:
12254 Vector3 scale6 = new Vector3(block.Data, 12);
12255 Vector3 pos6 = new Vector3(block.Data, 0);
12256
12257 handlerUpdatePrimScale = OnUpdatePrimScale;
12258 if (handlerUpdatePrimScale != null)
12259 {
12260 part.StoreUndoState(false);
12261 part.IgnoreUndoUpdate = true;
12262
12263 // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
12264 handlerUpdatePrimScale(localId, scale6, this);
12265 handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition;
12266 if (handlerUpdatePrimSinglePosition != null)
12267 {
12268 handlerUpdatePrimSinglePosition(localId, pos6, this);
12269 }
12270
12271 part.IgnoreUndoUpdate = false;
12272 }
12273 break;
12274
12275 default:
12276 m_log.Debug("[CLIENT]: MultipleObjUpdate recieved an unknown packet type: " + (block.Type));
12277 break;
12278 }
12279
12280// for (int j = 0; j < parts.Length; j++)
12281// parts[j].IgnoreUndoUpdate = false;
12282 }
12283 }
12284 }
12285
12286 return true;
12287 }
12288
12289 public void RequestMapLayer()
12290 {
12291 //should be getting the map layer from the grid server
12292 //send a layer covering the 800,800 - 1200,1200 area (should be covering the requested area)
12293 MapLayerReplyPacket mapReply = (MapLayerReplyPacket)PacketPool.Instance.GetPacket(PacketType.MapLayerReply);
12294 // TODO: don't create new blocks if recycling an old packet
12295 mapReply.AgentData.AgentID = AgentId;
12296 mapReply.AgentData.Flags = 0;
12297 mapReply.LayerData = new MapLayerReplyPacket.LayerDataBlock[1];
12298 mapReply.LayerData[0] = new MapLayerReplyPacket.LayerDataBlock();
12299 mapReply.LayerData[0].Bottom = 0;
12300 mapReply.LayerData[0].Left = 0;
12301 mapReply.LayerData[0].Top = 30000;
12302 mapReply.LayerData[0].Right = 30000;
12303 mapReply.LayerData[0].ImageID = new UUID("00000000-0000-1111-9999-000000000006");
12304 mapReply.Header.Zerocoded = true;
12305 OutPacket(mapReply, ThrottleOutPacketType.Land);
12306 }
12307
12308 public void RequestMapBlocksX(int minX, int minY, int maxX, int maxY)
12309 {
12310 /*
12311 IList simMapProfiles = m_gridServer.RequestMapBlocks(minX, minY, maxX, maxY);
12312 MapBlockReplyPacket mbReply = new MapBlockReplyPacket();
12313 mbReply.AgentData.AgentId = AgentId;
12314 int len;
12315 if (simMapProfiles == null)
12316 len = 0;
12317 else
12318 len = simMapProfiles.Count;
12319
12320 mbReply.Data = new MapBlockReplyPacket.DataBlock[len];
12321 int iii;
12322 for (iii = 0; iii < len; iii++)
12323 {
12324 Hashtable mp = (Hashtable)simMapProfiles[iii];
12325 mbReply.Data[iii] = new MapBlockReplyPacket.DataBlock();
12326 mbReply.Data[iii].Name = Util.UTF8.GetBytes((string)mp["name"]);
12327 mbReply.Data[iii].Access = System.Convert.ToByte(mp["access"]);
12328 mbReply.Data[iii].Agents = System.Convert.ToByte(mp["agents"]);
12329 mbReply.Data[iii].MapImageID = new UUID((string)mp["map-image-id"]);
12330 mbReply.Data[iii].RegionFlags = System.Convert.ToUInt32(mp["region-flags"]);
12331 mbReply.Data[iii].WaterHeight = System.Convert.ToByte(mp["water-height"]);
12332 mbReply.Data[iii].X = System.Convert.ToUInt16(mp["x"]);
12333 mbReply.Data[iii].Y = System.Convert.ToUInt16(mp["y"]);
12334 }
12335 this.OutPacket(mbReply, ThrottleOutPacketType.Land);
12336 */
12337 }
12338
12339 /// <summary>
12340 /// Sets the throttles from values supplied by the client
12341 /// </summary>
12342 /// <param name="throttles"></param>
12343 public void SetChildAgentThrottle(byte[] throttles)
12344 {
12345 m_udpClient.SetThrottles(throttles);
12346 }
12347
12348 /// <summary>
12349 /// Get the current throttles for this client as a packed byte array
12350 /// </summary>
12351 /// <param name="multiplier">Unused</param>
12352 /// <returns></returns>
12353 public byte[] GetThrottlesPacked(float multiplier)
12354 {
12355 return m_udpClient.GetThrottlesPacked(multiplier);
12356 }
12357
12358 /// <summary>
12359 /// Cruft?
12360 /// </summary>
12361 public virtual void InPacket(object NewPack)
12362 {
12363 throw new NotImplementedException();
12364 }
12365
12366 /// <summary>
12367 /// This is the starting point for sending a simulator packet out to the client
12368 /// </summary>
12369 /// <param name="packet">Packet to send</param>
12370 /// <param name="throttlePacketType">Throttling category for the packet</param>
12371 protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType)
12372 {
12373 #region BinaryStats
12374 LLUDPServer.LogPacketHeader(false, m_circuitCode, 0, packet.Type, (ushort)packet.Length);
12375 #endregion BinaryStats
12376
12377 OutPacket(packet, throttlePacketType, true);
12378 }
12379
12380 /// <summary>
12381 /// This is the starting point for sending a simulator packet out to the client
12382 /// </summary>
12383 /// <param name="packet">Packet to send</param>
12384 /// <param name="throttlePacketType">Throttling category for the packet</param>
12385 /// <param name="doAutomaticSplitting">True to automatically split oversized
12386 /// packets (the default), or false to disable splitting if the calling code
12387 /// handles splitting manually</param>
12388 protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting)
12389 {
12390 OutPacket(packet, throttlePacketType, doAutomaticSplitting, null);
12391 }
12392
12393 /// <summary>
12394 /// This is the starting point for sending a simulator packet out to the client
12395 /// </summary>
12396 /// <param name="packet">Packet to send</param>
12397 /// <param name="throttlePacketType">Throttling category for the packet</param>
12398 /// <param name="doAutomaticSplitting">True to automatically split oversized
12399 /// packets (the default), or false to disable splitting if the calling code
12400 /// handles splitting manually</param>
12401 /// <param name="method">The method to be called in the event this packet is reliable
12402 /// and unacknowledged. The server will provide normal resend capability if you do not
12403 /// provide your own method.</param>
12404 protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting, UnackedPacketMethod method)
12405 {
12406 if (m_outPacketsToDrop != null)
12407 if (m_outPacketsToDrop.Contains(packet.Type.ToString()))
12408 return;
12409
12410 if (DebugPacketLevel > 0)
12411 {
12412 bool logPacket = true;
12413
12414 if (DebugPacketLevel <= 255
12415 && (packet.Type == PacketType.SimStats || packet.Type == PacketType.SimulatorViewerTimeMessage))
12416 logPacket = false;
12417
12418 if (DebugPacketLevel <= 200
12419 && (packet.Type == PacketType.ImagePacket
12420 || packet.Type == PacketType.ImageData
12421 || packet.Type == PacketType.LayerData
12422 || packet.Type == PacketType.CoarseLocationUpdate))
12423 logPacket = false;
12424
12425 if (DebugPacketLevel <= 100 && (packet.Type == PacketType.AvatarAnimation || packet.Type == PacketType.ViewerEffect))
12426 logPacket = false;
12427
12428 if (DebugPacketLevel <= 50
12429 && (packet.Type == PacketType.ImprovedTerseObjectUpdate || packet.Type == PacketType.ObjectUpdate))
12430 logPacket = false;
12431
12432 if (DebugPacketLevel <= 25 && packet.Type == PacketType.ObjectPropertiesFamily)
12433 logPacket = false;
12434
12435 if (logPacket)
12436 m_log.DebugFormat(
12437 "[CLIENT]: PACKET OUT to {0} ({1}) in {2} - {3}",
12438 Name, SceneAgent.IsChildAgent ? "child" : "root ", m_scene.RegionInfo.RegionName, packet.Type);
12439 }
12440
12441 m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting, method);
12442 }
12443
12444 protected void HandleAutopilot(Object sender, string method, List<String> args)
12445 {
12446 float locx = 0;
12447 float locy = 0;
12448 float locz = 0;
12449 uint regionX = 0;
12450 uint regionY = 0;
12451
12452 Utils.LongToUInts(m_scene.RegionInfo.RegionHandle, out regionX, out regionY);
12453 locx = Convert.ToSingle(args[0]) - (float)regionX;
12454 locy = Convert.ToSingle(args[1]) - (float)regionY;
12455 locz = Convert.ToSingle(args[2]);
12456
12457 Action<Vector3, bool, bool> handlerAutoPilotGo = OnAutoPilotGo;
12458 if (handlerAutoPilotGo != null)
12459 handlerAutoPilotGo(new Vector3(locx, locy, locz), false, false);
12460 }
12461
12462 /// <summary>
12463 /// Entryway from the client to the simulator. All UDP packets from the client will end up here
12464 /// </summary>
12465 /// <param name="Pack">OpenMetaverse.packet</param>
12466 public void ProcessInPacket(Packet packet)
12467 {
12468 if (m_inPacketsToDrop != null)
12469 if (m_inPacketsToDrop.Contains(packet.Type.ToString()))
12470 return;
12471
12472 if (DebugPacketLevel > 0)
12473 {
12474 bool logPacket = true;
12475
12476 if (DebugPacketLevel <= 255 && packet.Type == PacketType.AgentUpdate)
12477 logPacket = false;
12478
12479 if (DebugPacketLevel <= 200 && packet.Type == PacketType.RequestImage)
12480 logPacket = false;
12481
12482 if (DebugPacketLevel <= 100 && (packet.Type == PacketType.ViewerEffect || packet.Type == PacketType.AgentAnimation))
12483 logPacket = false;
12484
12485 if (DebugPacketLevel <= 25 && packet.Type == PacketType.RequestObjectPropertiesFamily)
12486 logPacket = false;
12487
12488 if (logPacket)
12489 m_log.DebugFormat(
12490 "[CLIENT]: PACKET IN from {0} ({1}) in {2} - {3}",
12491 Name, SceneAgent.IsChildAgent ? "child" : "root ", Scene.Name, packet.Type);
12492 }
12493
12494 if (!ProcessPacketMethod(packet))
12495 m_log.WarnFormat(
12496 "[CLIENT]: Unhandled packet {0} from {1} ({2}) in {3}. Ignoring.",
12497 packet.Type, Name, SceneAgent.IsChildAgent ? "child" : "root ", Scene.Name);
12498 }
12499
12500 private static PrimitiveBaseShape GetShapeFromAddPacket(ObjectAddPacket addPacket)
12501 {
12502 PrimitiveBaseShape shape = new PrimitiveBaseShape();
12503
12504 shape.PCode = addPacket.ObjectData.PCode;
12505 shape.State = addPacket.ObjectData.State;
12506 shape.LastAttachPoint = addPacket.ObjectData.State;
12507 shape.PathBegin = addPacket.ObjectData.PathBegin;
12508 shape.PathEnd = addPacket.ObjectData.PathEnd;
12509 shape.PathScaleX = addPacket.ObjectData.PathScaleX;
12510 shape.PathScaleY = addPacket.ObjectData.PathScaleY;
12511 shape.PathShearX = addPacket.ObjectData.PathShearX;
12512 shape.PathShearY = addPacket.ObjectData.PathShearY;
12513 shape.PathSkew = addPacket.ObjectData.PathSkew;
12514 shape.ProfileBegin = addPacket.ObjectData.ProfileBegin;
12515 shape.ProfileEnd = addPacket.ObjectData.ProfileEnd;
12516 shape.Scale = addPacket.ObjectData.Scale;
12517 shape.PathCurve = addPacket.ObjectData.PathCurve;
12518 shape.ProfileCurve = addPacket.ObjectData.ProfileCurve;
12519 shape.ProfileHollow = addPacket.ObjectData.ProfileHollow;
12520 shape.PathRadiusOffset = addPacket.ObjectData.PathRadiusOffset;
12521 shape.PathRevolutions = addPacket.ObjectData.PathRevolutions;
12522 shape.PathTaperX = addPacket.ObjectData.PathTaperX;
12523 shape.PathTaperY = addPacket.ObjectData.PathTaperY;
12524 shape.PathTwist = addPacket.ObjectData.PathTwist;
12525 shape.PathTwistBegin = addPacket.ObjectData.PathTwistBegin;
12526 Primitive.TextureEntry ntex = new Primitive.TextureEntry(new UUID("89556747-24cb-43ed-920b-47caed15465f"));
12527 shape.TextureEntry = ntex.GetBytes();
12528 //shape.Textures = ntex;
12529 return shape;
12530 }
12531
12532 public ClientInfo GetClientInfo()
12533 {
12534 ClientInfo info = m_udpClient.GetClientInfo();
12535
12536 info.proxyEP = null;
12537 if (info.agentcircuit == null)
12538 info.agentcircuit = RequestClientInfo();
12539
12540 return info;
12541 }
12542
12543 public void SetClientInfo(ClientInfo info)
12544 {
12545 m_udpClient.SetClientInfo(info);
12546 }
12547
12548 #region Media Parcel Members
12549
12550 public void SendParcelMediaCommand(uint flags, ParcelMediaCommandEnum command, float time)
12551 {
12552 ParcelMediaCommandMessagePacket commandMessagePacket = new ParcelMediaCommandMessagePacket();
12553 commandMessagePacket.CommandBlock.Flags = flags;
12554 commandMessagePacket.CommandBlock.Command = (uint)command;
12555 commandMessagePacket.CommandBlock.Time = time;
12556
12557 OutPacket(commandMessagePacket, ThrottleOutPacketType.Task);
12558 }
12559
12560 public void SendParcelMediaUpdate(string mediaUrl, UUID mediaTextureID,
12561 byte autoScale, string mediaType, string mediaDesc, int mediaWidth, int mediaHeight,
12562 byte mediaLoop)
12563 {
12564 ParcelMediaUpdatePacket updatePacket = new ParcelMediaUpdatePacket();
12565 updatePacket.DataBlock.MediaURL = Util.StringToBytes256(mediaUrl);
12566 updatePacket.DataBlock.MediaID = mediaTextureID;
12567 updatePacket.DataBlock.MediaAutoScale = autoScale;
12568
12569 updatePacket.DataBlockExtended.MediaType = Util.StringToBytes256(mediaType);
12570 updatePacket.DataBlockExtended.MediaDesc = Util.StringToBytes256(mediaDesc);
12571 updatePacket.DataBlockExtended.MediaWidth = mediaWidth;
12572 updatePacket.DataBlockExtended.MediaHeight = mediaHeight;
12573 updatePacket.DataBlockExtended.MediaLoop = mediaLoop;
12574
12575 OutPacket(updatePacket, ThrottleOutPacketType.Task);
12576 }
12577
12578 #endregion
12579
12580 #region Camera
12581
12582 public void SendSetFollowCamProperties(UUID objectID, SortedDictionary<int, float> parameters)
12583 {
12584 SetFollowCamPropertiesPacket packet = (SetFollowCamPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.SetFollowCamProperties);
12585 packet.ObjectData.ObjectID = objectID;
12586 SetFollowCamPropertiesPacket.CameraPropertyBlock[] camPropBlock = new SetFollowCamPropertiesPacket.CameraPropertyBlock[parameters.Count];
12587 uint idx = 0;
12588 foreach (KeyValuePair<int, float> pair in parameters)
12589 {
12590 SetFollowCamPropertiesPacket.CameraPropertyBlock block = new SetFollowCamPropertiesPacket.CameraPropertyBlock();
12591 block.Type = pair.Key;
12592 block.Value = pair.Value;
12593
12594 camPropBlock[idx++] = block;
12595 }
12596 packet.CameraProperty = camPropBlock;
12597 OutPacket(packet, ThrottleOutPacketType.Task);
12598 }
12599
12600 public void SendClearFollowCamProperties(UUID objectID)
12601 {
12602 ClearFollowCamPropertiesPacket packet = (ClearFollowCamPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ClearFollowCamProperties);
12603 packet.ObjectData.ObjectID = objectID;
12604 OutPacket(packet, ThrottleOutPacketType.Task);
12605 }
12606
12607 #endregion
12608
12609 public void SetClientOption(string option, string value)
12610 {
12611 switch (option)
12612 {
12613 default:
12614 break;
12615 }
12616 }
12617
12618 public string GetClientOption(string option)
12619 {
12620 switch (option)
12621 {
12622 default:
12623 break;
12624 }
12625 return string.Empty;
12626 }
12627
12628 #region IClientCore
12629
12630 private readonly Dictionary<Type, object> m_clientInterfaces = new Dictionary<Type, object>();
12631
12632 /// <summary>
12633 /// Register an interface on this client, should only be called in the constructor.
12634 /// </summary>
12635 /// <typeparam name="T"></typeparam>
12636 /// <param name="iface"></param>
12637 protected void RegisterInterface<T>(T iface)
12638 {
12639 lock (m_clientInterfaces)
12640 {
12641 if (!m_clientInterfaces.ContainsKey(typeof(T)))
12642 {
12643 m_clientInterfaces.Add(typeof(T), iface);
12644 }
12645 }
12646 }
12647
12648 public bool TryGet<T>(out T iface)
12649 {
12650 if (m_clientInterfaces.ContainsKey(typeof(T)))
12651 {
12652 iface = (T)m_clientInterfaces[typeof(T)];
12653 return true;
12654 }
12655 iface = default(T);
12656 return false;
12657 }
12658
12659 public T Get<T>()
12660 {
12661 return (T)m_clientInterfaces[typeof(T)];
12662 }
12663
12664 public void Disconnect(string reason)
12665 {
12666 Kick(reason);
12667 Thread.Sleep(1000);
12668 Disconnect();
12669 }
12670
12671 public void Disconnect()
12672 {
12673 Close();
12674 }
12675
12676 #endregion
12677
12678 public void RefreshGroupMembership()
12679 {
12680 if (m_GroupsModule != null)
12681 {
12682 GroupMembershipData[] GroupMembership =
12683 m_GroupsModule.GetMembershipData(AgentId);
12684
12685 m_groupPowers.Clear();
12686
12687 if (GroupMembership != null)
12688 {
12689 for (int i = 0; i < GroupMembership.Length; i++)
12690 {
12691 m_groupPowers[GroupMembership[i].GroupID] = GroupMembership[i].GroupPowers;
12692 }
12693 }
12694 }
12695 }
12696
12697 public string Report()
12698 {
12699 return m_udpClient.GetStats();
12700 }
12701
12702 public string XReport(string uptime, string version)
12703 {
12704 return String.Empty;
12705 }
12706
12707 public OSDMap OReport(string uptime, string version)
12708 {
12709 return new OSDMap();
12710 }
12711
12712 /// <summary>
12713 /// Make an asset request to the asset service in response to a client request.
12714 /// </summary>
12715 /// <param name="transferRequest"></param>
12716 /// <param name="taskID"></param>
12717 protected void MakeAssetRequest(TransferRequestPacket transferRequest, UUID taskID)
12718 {
12719 UUID requestID = UUID.Zero;
12720 int sourceType = transferRequest.TransferInfo.SourceType;
12721
12722 if (sourceType == (int)SourceType.Asset)
12723 {
12724 requestID = new UUID(transferRequest.TransferInfo.Params, 0);
12725 }
12726 else if (sourceType == (int)SourceType.SimInventoryItem)
12727 {
12728 requestID = new UUID(transferRequest.TransferInfo.Params, 80);
12729 }
12730 else if (sourceType == (int)SourceType.SimEstate)
12731 {
12732 requestID = taskID;
12733 }
12734
12735// m_log.DebugFormat(
12736// "[LLCLIENTVIEW]: Received transfer request for {0} in {1} type {2} by {3}",
12737// requestID, taskID, (SourceType)sourceType, Name);
12738
12739 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived);
12740 }
12741
12742 /// <summary>
12743 /// When we get a reply back from the asset service in response to a client request, send back the data.
12744 /// </summary>
12745 /// <param name="id"></param>
12746 /// <param name="sender"></param>
12747 /// <param name="asset"></param>
12748 protected void AssetReceived(string id, Object sender, AssetBase asset)
12749 {
12750 TransferRequestPacket transferRequest = (TransferRequestPacket)sender;
12751
12752 UUID requestID = UUID.Zero;
12753 byte source = (byte)SourceType.Asset;
12754
12755 AssetRequestToClient req = new AssetRequestToClient();
12756
12757 if (asset == null)
12758 {
12759 // Try the user's asset server
12760 IInventoryAccessModule inventoryAccessModule = Scene.RequestModuleInterface<IInventoryAccessModule>();
12761
12762 string assetServerURL = string.Empty;
12763 if (inventoryAccessModule.IsForeignUser(AgentId, out assetServerURL) && !string.IsNullOrEmpty(assetServerURL))
12764 {
12765 if (!assetServerURL.EndsWith("/") && !assetServerURL.EndsWith("="))
12766 assetServerURL = assetServerURL + "/";
12767
12768 //m_log.DebugFormat("[LLCLIENTVIEW]: asset {0} not found in local storage. Trying user's storage.", assetServerURL + id);
12769 asset = m_scene.AssetService.Get(assetServerURL + id);
12770 }
12771
12772 if (asset == null)
12773 {
12774 req.AssetInf = null;
12775 req.AssetRequestSource = source;
12776 req.IsTextureRequest = false;
12777 req.NumPackets = 0;
12778 req.Params = transferRequest.TransferInfo.Params;
12779 req.RequestAssetID = requestID;
12780 req.TransferRequestID = transferRequest.TransferInfo.TransferID;
12781
12782 SendAssetNotFound(req);
12783 return;
12784 }
12785
12786 }
12787
12788 if (transferRequest.TransferInfo.SourceType == (int)SourceType.Asset)
12789 {
12790 requestID = new UUID(transferRequest.TransferInfo.Params, 0);
12791 }
12792 else if (transferRequest.TransferInfo.SourceType == (int)SourceType.SimInventoryItem)
12793 {
12794 requestID = new UUID(transferRequest.TransferInfo.Params, 80);
12795 source = (byte)SourceType.SimInventoryItem;
12796 //m_log.Debug("asset request " + requestID);
12797 }
12798
12799 // Scripts cannot be retrieved by direct request
12800 if (transferRequest.TransferInfo.SourceType == (int)SourceType.Asset && asset.Type == 10)
12801 return;
12802
12803 // The asset is known to exist and is in our cache, so add it to the AssetRequests list
12804 req.AssetInf = asset;
12805 req.AssetRequestSource = source;
12806 req.IsTextureRequest = false;
12807 req.NumPackets = CalculateNumPackets(asset.Data);
12808 req.Params = transferRequest.TransferInfo.Params;
12809 req.RequestAssetID = requestID;
12810 req.TransferRequestID = transferRequest.TransferInfo.TransferID;
12811
12812 SendAsset(req);
12813 }
12814
12815 /// <summary>
12816 /// Calculate the number of packets required to send the asset to the client.
12817 /// </summary>
12818 /// <param name="data"></param>
12819 /// <returns></returns>
12820 private static int CalculateNumPackets(byte[] data)
12821 {
12822 const uint m_maxPacketSize = 600;
12823 int numPackets = 1;
12824
12825 if (data == null)
12826 return 0;
12827
12828 if (data.LongLength > m_maxPacketSize)
12829 {
12830 // over max number of bytes so split up file
12831 long restData = data.LongLength - m_maxPacketSize;
12832 int restPackets = (int)((restData + m_maxPacketSize - 1) / m_maxPacketSize);
12833 numPackets += restPackets;
12834 }
12835
12836 return numPackets;
12837 }
12838
12839 public void SendRebakeAvatarTextures(UUID textureID)
12840 {
12841 RebakeAvatarTexturesPacket pack =
12842 (RebakeAvatarTexturesPacket)PacketPool.Instance.GetPacket(PacketType.RebakeAvatarTextures);
12843
12844 pack.TextureData = new RebakeAvatarTexturesPacket.TextureDataBlock();
12845 pack.TextureData.TextureID = textureID;
12846 OutPacket(pack, ThrottleOutPacketType.Task);
12847 }
12848
12849 public struct PacketProcessor
12850 {
12851 /// <summary>
12852 /// Packet handling method.
12853 /// </summary>
12854 public PacketMethod method { get; set; }
12855
12856 /// <summary>
12857 /// Should this packet be handled asynchronously?
12858 /// </summary>
12859 public bool Async { get; set; }
12860
12861 /// <summary>
12862 /// If async is true, should this packet be handled in the async engine or given directly to a threadpool
12863 /// thread?
12864 /// </summary>
12865 public bool InEngine { get; set; }
12866 }
12867
12868 public class AsyncPacketProcess
12869 {
12870 public bool result = false;
12871 public readonly LLClientView ClientView = null;
12872 public readonly Packet Pack = null;
12873 public readonly PacketMethod Method = null;
12874 public AsyncPacketProcess(LLClientView pClientview, PacketMethod pMethod, Packet pPack)
12875 {
12876 ClientView = pClientview;
12877 Method = pMethod;
12878 Pack = pPack;
12879 }
12880 }
12881
12882 public static OSD BuildEvent(string eventName, OSD eventBody)
12883 {
12884 OSDMap osdEvent = new OSDMap(2);
12885 osdEvent.Add("message", new OSDString(eventName));
12886 osdEvent.Add("body", eventBody);
12887
12888 return osdEvent;
12889 }
12890
12891 public void SendAvatarInterestsReply(UUID avatarID, uint wantMask, string wantText, uint skillsMask, string skillsText, string languages)
12892 {
12893 AvatarInterestsReplyPacket packet = (AvatarInterestsReplyPacket)PacketPool.Instance.GetPacket(PacketType.AvatarInterestsReply);
12894
12895 packet.AgentData = new AvatarInterestsReplyPacket.AgentDataBlock();
12896 packet.AgentData.AgentID = AgentId;
12897 packet.AgentData.AvatarID = avatarID;
12898
12899 packet.PropertiesData = new AvatarInterestsReplyPacket.PropertiesDataBlock();
12900 packet.PropertiesData.WantToMask = wantMask;
12901 packet.PropertiesData.WantToText = Utils.StringToBytes(wantText);
12902 packet.PropertiesData.SkillsMask = skillsMask;
12903 packet.PropertiesData.SkillsText = Utils.StringToBytes(skillsText);
12904 packet.PropertiesData.LanguagesText = Utils.StringToBytes(languages);
12905 OutPacket(packet, ThrottleOutPacketType.Task);
12906 }
12907
12908 public void SendChangeUserRights(UUID agentID, UUID friendID, int rights)
12909 {
12910 ChangeUserRightsPacket packet = (ChangeUserRightsPacket)PacketPool.Instance.GetPacket(PacketType.ChangeUserRights);
12911
12912 packet.AgentData = new ChangeUserRightsPacket.AgentDataBlock();
12913 packet.AgentData.AgentID = agentID;
12914
12915 packet.Rights = new ChangeUserRightsPacket.RightsBlock[1];
12916 packet.Rights[0] = new ChangeUserRightsPacket.RightsBlock();
12917 packet.Rights[0].AgentRelated = friendID;
12918 packet.Rights[0].RelatedRights = rights;
12919
12920 OutPacket(packet, ThrottleOutPacketType.Task);
12921 }
12922
12923 public void SendTextBoxRequest(string message, int chatChannel, string objectname, UUID ownerID, string ownerFirstName, string ownerLastName, UUID objectId)
12924 {
12925 ScriptDialogPacket dialog = (ScriptDialogPacket)PacketPool.Instance.GetPacket(PacketType.ScriptDialog);
12926 dialog.Data.ObjectID = objectId;
12927 dialog.Data.ChatChannel = chatChannel;
12928 dialog.Data.ImageID = UUID.Zero;
12929 dialog.Data.ObjectName = Util.StringToBytes256(objectname);
12930 // this is the username of the *owner*
12931 dialog.Data.FirstName = Util.StringToBytes256(ownerFirstName);
12932 dialog.Data.LastName = Util.StringToBytes256(ownerLastName);
12933 dialog.Data.Message = Util.StringToBytes256(message);
12934
12935 ScriptDialogPacket.ButtonsBlock[] buttons = new ScriptDialogPacket.ButtonsBlock[1];
12936 buttons[0] = new ScriptDialogPacket.ButtonsBlock();
12937 buttons[0].ButtonLabel = Util.StringToBytes256("!!llTextBox!!");
12938 dialog.Buttons = buttons;
12939
12940 dialog.OwnerData = new ScriptDialogPacket.OwnerDataBlock[1];
12941 dialog.OwnerData[0] = new ScriptDialogPacket.OwnerDataBlock();
12942 dialog.OwnerData[0].OwnerID = ownerID;
12943
12944 OutPacket(dialog, ThrottleOutPacketType.Task);
12945 }
12946
12947 public void SendAgentTerseUpdate(ISceneEntity p)
12948 {
12949 if (p is ScenePresence)
12950 {
12951// m_log.DebugFormat(
12952// "[LLCLIENTVIEW]: Immediately sending terse agent update for {0} to {1} in {2}",
12953// p.Name, Name, Scene.Name);
12954
12955 // It turns out to get the agent to stop flying, you have to feed it stop flying velocities
12956 // There's no explicit message to send the client to tell it to stop flying.. it relies on the
12957 // velocity, collision plane and avatar height
12958
12959 // Add 1/6 the avatar's height to it's position so it doesn't shoot into the air
12960 // when the avatar stands up
12961
12962 ImprovedTerseObjectUpdatePacket.ObjectDataBlock block =
12963 CreateImprovedTerseBlock(p, false);
12964
12965 const float TIME_DILATION = 1.0f;
12966 ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f);
12967
12968 ImprovedTerseObjectUpdatePacket packet
12969 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
12970 PacketType.ImprovedTerseObjectUpdate);
12971
12972 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
12973 packet.RegionData.TimeDilation = timeDilation;
12974 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1];
12975
12976 packet.ObjectData[0] = block;
12977
12978 OutPacket(packet, ThrottleOutPacketType.Task, true);
12979 }
12980
12981 //ControllingClient.SendAvatarTerseUpdate(new SendAvatarTerseData(m_rootRegionHandle, (ushort)(m_scene.TimeDilation * ushort.MaxValue), LocalId,
12982 // AbsolutePosition, Velocity, Vector3.Zero, m_bodyRot, new Vector4(0,0,1,AbsolutePosition.Z - 0.5f), m_uuid, null, GetUpdatePriority(ControllingClient)));
12983 }
12984
12985 public void SendPlacesReply(UUID queryID, UUID transactionID,
12986 PlacesReplyData[] data)
12987 {
12988 PlacesReplyPacket reply = null;
12989 PlacesReplyPacket.QueryDataBlock[] dataBlocks =
12990 new PlacesReplyPacket.QueryDataBlock[0];
12991
12992 for (int i = 0 ; i < data.Length ; i++)
12993 {
12994 PlacesReplyPacket.QueryDataBlock block =
12995 new PlacesReplyPacket.QueryDataBlock();
12996
12997 block.OwnerID = data[i].OwnerID;
12998 block.Name = Util.StringToBytes256(data[i].Name);
12999 block.Desc = Util.StringToBytes1024(data[i].Desc);
13000 block.ActualArea = data[i].ActualArea;
13001 block.BillableArea = data[i].BillableArea;
13002 block.Flags = data[i].Flags;
13003 block.GlobalX = data[i].GlobalX;
13004 block.GlobalY = data[i].GlobalY;
13005 block.GlobalZ = data[i].GlobalZ;
13006 block.SimName = Util.StringToBytes256(data[i].SimName);
13007 block.SnapshotID = data[i].SnapshotID;
13008 block.Dwell = data[i].Dwell;
13009 block.Price = data[i].Price;
13010
13011 if (reply != null && reply.Length + block.Length > 1400)
13012 {
13013 OutPacket(reply, ThrottleOutPacketType.Task);
13014
13015 reply = null;
13016 dataBlocks = new PlacesReplyPacket.QueryDataBlock[0];
13017 }
13018
13019 if (reply == null)
13020 {
13021 reply = (PlacesReplyPacket)PacketPool.Instance.GetPacket(PacketType.PlacesReply);
13022 reply.AgentData = new PlacesReplyPacket.AgentDataBlock();
13023 reply.AgentData.AgentID = AgentId;
13024 reply.AgentData.QueryID = queryID;
13025
13026 reply.TransactionData = new PlacesReplyPacket.TransactionDataBlock();
13027 reply.TransactionData.TransactionID = transactionID;
13028
13029 reply.QueryData = dataBlocks;
13030 }
13031
13032 Array.Resize(ref dataBlocks, dataBlocks.Length + 1);
13033 dataBlocks[dataBlocks.Length - 1] = block;
13034 reply.QueryData = dataBlocks;
13035 }
13036 if (reply != null)
13037 OutPacket(reply, ThrottleOutPacketType.Task);
13038 }
13039
13040 public void SendRemoveInventoryItems(UUID[] items)
13041 {
13042 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>();
13043
13044 if (eq == null)
13045 {
13046 m_log.DebugFormat("[LLCLIENT]: Null event queue");
13047 return;
13048 }
13049
13050 OSDMap llsd = new OSDMap(3);
13051
13052 OSDMap AgentDataMap = new OSDMap(1);
13053 AgentDataMap.Add("AgentID", OSD.FromUUID(AgentId));
13054 AgentDataMap.Add("SessionID", OSD.FromUUID(SessionId));
13055
13056 OSDArray AgentData = new OSDArray(1);
13057 AgentData.Add(AgentDataMap);
13058
13059 llsd.Add("AgentData", AgentData);
13060
13061 OSDArray ItemData = new OSDArray();
13062
13063 foreach (UUID item in items)
13064 {
13065 OSDMap ItemDataMap = new OSDMap(2);
13066 ItemDataMap.Add("ItemID", OSD.FromUUID(item));
13067 ItemDataMap.Add("AgentID", OSD.FromUUID(AgentId));
13068
13069 ItemData.Add(ItemDataMap);
13070 }
13071
13072 llsd.Add("InventoryData", ItemData);
13073
13074 eq.Enqueue(BuildEvent("RemoveInventoryItem",
13075 llsd), AgentId);
13076 }
13077
13078 public void SendRemoveInventoryFolders(UUID[] folders)
13079 {
13080 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>();
13081
13082 if (eq == null)
13083 {
13084 m_log.DebugFormat("[LLCLIENT]: Null event queue");
13085 return;
13086 }
13087
13088 OSDMap llsd = new OSDMap(3);
13089
13090 OSDMap AgentDataMap = new OSDMap(1);
13091 AgentDataMap.Add("AgentID", OSD.FromUUID(AgentId));
13092 AgentDataMap.Add("SessionID", OSD.FromUUID(SessionId));
13093
13094 OSDArray AgentData = new OSDArray(1);
13095 AgentData.Add(AgentDataMap);
13096
13097 llsd.Add("AgentData", AgentData);
13098
13099 OSDArray FolderData = new OSDArray();
13100
13101 foreach (UUID folder in folders)
13102 {
13103 OSDMap FolderDataMap = new OSDMap(2);
13104 FolderDataMap.Add("FolderID", OSD.FromUUID(folder));
13105 FolderDataMap.Add("AgentID", OSD.FromUUID(AgentId));
13106
13107 FolderData.Add(FolderDataMap);
13108 }
13109
13110 llsd.Add("FolderData", FolderData);
13111
13112 eq.Enqueue(BuildEvent("RemoveInventoryFolder",
13113 llsd), AgentId);
13114 }
13115
13116 private byte[] EncodeU32(uint val)
13117 {
13118 byte[] ret = BitConverter.GetBytes(val);
13119 if (BitConverter.IsLittleEndian)
13120 Array.Reverse(ret);
13121 return ret;
13122 }
13123
13124 public void SendBulkUpdateInventory(InventoryFolderBase[] folders, InventoryItemBase[] items)
13125 {
13126 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>();
13127
13128 if (eq == null)
13129 {
13130 m_log.DebugFormat("[LLCLIENT]: Null event queue");
13131 return;
13132 }
13133
13134 OSDMap llsd = new OSDMap(3);
13135
13136 OSDMap AgentDataMap = new OSDMap(1);
13137 AgentDataMap.Add("AgentID", OSD.FromUUID(AgentId));
13138 AgentDataMap.Add("SessionID", OSD.FromUUID(SessionId));
13139 AgentDataMap.Add("TransactionID", OSD.FromUUID(UUID.Random()));
13140
13141 OSDArray AgentData = new OSDArray(1);
13142 AgentData.Add(AgentDataMap);
13143
13144 llsd.Add("AgentData", AgentData);
13145
13146 OSDArray FolderData = new OSDArray();
13147
13148 foreach (InventoryFolderBase folder in folders)
13149 {
13150 OSDMap FolderDataMap = new OSDMap(5);
13151 FolderDataMap.Add("FolderID", OSD.FromUUID(folder.ID));
13152 FolderDataMap.Add("AgentID", OSD.FromUUID(AgentId));
13153 FolderDataMap.Add("ParentID", OSD.FromUUID(folder.ParentID));
13154 FolderDataMap.Add("Type", OSD.FromInteger(folder.Type));
13155 FolderDataMap.Add("Name", OSD.FromString(folder.Name));
13156
13157 FolderData.Add(FolderDataMap);
13158 }
13159
13160 llsd.Add("FolderData", FolderData);
13161
13162 OSDArray ItemData = new OSDArray();
13163
13164 foreach (InventoryItemBase item in items)
13165 {
13166 OSDMap ItemDataMap = new OSDMap();
13167
13168 ItemDataMap.Add("ItemID", OSD.FromUUID(item.ID));
13169 ItemDataMap.Add("FolderID", OSD.FromUUID(item.Folder));
13170
13171 ItemDataMap.Add("CreatorID", OSD.FromUUID(item.CreatorIdAsUuid));
13172 ItemDataMap.Add("OwnerID", OSD.FromUUID(item.Owner));
13173 ItemDataMap.Add("GroupID", OSD.FromUUID(item.GroupID));
13174 ItemDataMap.Add("BaseMask", OSD.FromBinary(EncodeU32((uint)item.BasePermissions)));
13175 ItemDataMap.Add("OwnerMask", OSD.FromBinary(EncodeU32((uint)item.CurrentPermissions)));
13176 ItemDataMap.Add("GroupMask", OSD.FromBinary(EncodeU32((uint)item.GroupPermissions)));
13177 ItemDataMap.Add("EveryoneMask", OSD.FromBinary(EncodeU32((uint)item.EveryOnePermissions)));
13178 ItemDataMap.Add("NextOwnerMask", OSD.FromBinary(EncodeU32((uint)item.NextPermissions)));
13179 ItemDataMap.Add("GroupOwned", OSD.FromBoolean(item.GroupOwned));
13180 ItemDataMap.Add("AssetID", OSD.FromUUID(item.AssetID));
13181 ItemDataMap.Add("Type", OSD.FromInteger(item.AssetType));
13182 ItemDataMap.Add("InvType", OSD.FromInteger(item.InvType));
13183 ItemDataMap.Add("Flags", OSD.FromBinary(EncodeU32((uint)item.Flags)));
13184 ItemDataMap.Add("SaleType", OSD.FromInteger((byte)item.SaleType));
13185 ItemDataMap.Add("SalePrice", OSD.FromInteger(item.SalePrice));
13186 ItemDataMap.Add("Name", OSD.FromString(item.Name));
13187 ItemDataMap.Add("Description", OSD.FromString(item.Description));
13188 ItemDataMap.Add("CreationDate", OSD.FromInteger(item.CreationDate));
13189
13190 ItemDataMap.Add("CRC", OSD.FromBinary(EncodeU32(
13191 Helpers.InventoryCRC(1000, 0, (sbyte)item.InvType,
13192 (sbyte)item.AssetType, item.AssetID,
13193 item.GroupID, 100,
13194 item.Owner, item.CreatorIdAsUuid,
13195 item.ID, item.Folder,
13196 (uint)PermissionMask.All, 1, (uint)PermissionMask.All, (uint)PermissionMask.All,
13197 (uint)PermissionMask.All)
13198 )));
13199 ItemDataMap.Add("CallbackID", 0);
13200
13201 ItemData.Add(ItemDataMap);
13202 }
13203
13204 llsd.Add("ItemData", ItemData);
13205
13206 eq.Enqueue(BuildEvent("BulkUpdateInventory",
13207 llsd), AgentId);
13208 }
13209
13210 private HashSet<string> m_outPacketsToDrop;
13211
13212 public bool AddOutPacketToDropSet(string packetName)
13213 {
13214 if (m_outPacketsToDrop == null)
13215 m_outPacketsToDrop = new HashSet<string>();
13216
13217 return m_outPacketsToDrop.Add(packetName);
13218 }
13219
13220 public bool RemoveOutPacketFromDropSet(string packetName)
13221 {
13222 if (m_outPacketsToDrop == null)
13223 return false;
13224
13225 return m_outPacketsToDrop.Remove(packetName);
13226 }
13227
13228 public HashSet<string> GetOutPacketDropSet()
13229 {
13230 return new HashSet<string>(m_outPacketsToDrop);
13231 }
13232
13233 private HashSet<string> m_inPacketsToDrop;
13234
13235 public bool AddInPacketToDropSet(string packetName)
13236 {
13237 if (m_inPacketsToDrop == null)
13238 m_inPacketsToDrop = new HashSet<string>();
13239
13240 return m_inPacketsToDrop.Add(packetName);
13241 }
13242
13243 public bool RemoveInPacketFromDropSet(string packetName)
13244 {
13245 if (m_inPacketsToDrop == null)
13246 return false;
13247
13248 return m_inPacketsToDrop.Remove(packetName);
13249 }
13250
13251 public HashSet<string> GetInPacketDropSet()
13252 {
13253 return new HashSet<string>(m_inPacketsToDrop);
13254 }
13255 }
13256}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs
new file mode 100644
index 0000000..41dd4d1
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs
@@ -0,0 +1,360 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Threading;
30using System.Collections;
31using System.Collections.Generic;
32using System.Reflection;
33using OpenMetaverse;
34using OpenMetaverse.Imaging;
35using OpenSim.Framework;
36using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Services.Interfaces;
38using log4net;
39
40namespace OpenSim.Region.ClientStack.LindenUDP
41{
42 /// <summary>
43 /// This class handles UDP texture requests.
44 /// </summary>
45 public class LLImageManager
46 {
47 private sealed class J2KImageComparer : IComparer<J2KImage>
48 {
49 public int Compare(J2KImage x, J2KImage y)
50 {
51 return x.Priority.CompareTo(y.Priority);
52 }
53 }
54
55 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
56 private bool m_shuttingdown;
57 private AssetBase m_missingImage;
58 private IAssetService m_assetCache;
59 private IJ2KDecoder m_j2kDecodeModule;
60
61 /// <summary>
62 /// Priority queue for determining which image to send first.
63 /// </summary>
64 private C5.IntervalHeap<J2KImage> m_priorityQueue = new C5.IntervalHeap<J2KImage>(10, new J2KImageComparer());
65
66 /// <summary>
67 /// Used to control thread access to the priority queue.
68 /// </summary>
69 private object m_syncRoot = new object();
70
71 /// <summary>
72 /// Client served by this image manager
73 /// </summary>
74 public IClientAPI Client { get; private set; }
75
76 public AssetBase MissingImage { get { return m_missingImage; } }
77
78 public LLImageManager(IClientAPI client, IAssetService pAssetCache, IJ2KDecoder pJ2kDecodeModule)
79 {
80 Client = client;
81 m_assetCache = pAssetCache;
82
83 if (pAssetCache != null)
84 m_missingImage = pAssetCache.Get("5748decc-f629-461c-9a36-a35a221fe21f");
85
86 if (m_missingImage == null)
87 m_log.Error("[ClientView] - Couldn't set missing image asset, falling back to missing image packet. This is known to crash the client");
88
89 m_j2kDecodeModule = pJ2kDecodeModule;
90 }
91
92 /// <summary>
93 /// Handles an incoming texture request or update to an existing texture request
94 /// </summary>
95 /// <param name="newRequest"></param>
96 public void EnqueueReq(TextureRequestArgs newRequest)
97 {
98 if (!m_shuttingdown)
99 {
100 J2KImage imgrequest;
101
102 // Do a linear search for this texture download
103 lock (m_syncRoot)
104 m_priorityQueue.Find(delegate(J2KImage img) { return img.TextureID == newRequest.RequestedAssetID; }, out imgrequest);
105
106 if (imgrequest != null)
107 {
108 if (newRequest.DiscardLevel == -1 && newRequest.Priority == 0f)
109 {
110 //m_log.Debug("[TEX]: (CAN) ID=" + newRequest.RequestedAssetID);
111
112 try
113 {
114 lock (m_syncRoot)
115 m_priorityQueue.Delete(imgrequest.PriorityQueueHandle);
116 }
117 catch (Exception) { }
118 }
119 else
120 {
121// m_log.DebugFormat(
122// "[LL IMAGE MANAGER]: Received duplicate of existing request for {0}, start packet {1} from {2}",
123// newRequest.RequestedAssetID, newRequest.PacketNumber, m_client.Name);
124
125// m_log.DebugFormat("[TEX]: (UPD) ID={0}: D={1}, S={2}, P={3}",
126// newRequest.RequestedAssetID, newRequest.DiscardLevel, newRequest.PacketNumber, newRequest.Priority);
127
128 //Check the packet sequence to make sure this isn't older than
129 //one we've already received
130 if (newRequest.requestSequence > imgrequest.LastSequence)
131 {
132 //Update the sequence number of the last RequestImage packet
133 imgrequest.LastSequence = newRequest.requestSequence;
134
135 //Update the requested discard level
136 imgrequest.DiscardLevel = newRequest.DiscardLevel;
137
138 //Update the requested packet number
139 imgrequest.StartPacket = Math.Max(1, newRequest.PacketNumber);
140
141 //Update the requested priority
142 imgrequest.Priority = newRequest.Priority;
143
144 UpdateImageInQueue(imgrequest);
145
146 imgrequest.RunUpdate();
147
148// J2KImage imgrequest2 = new J2KImage(this);
149// imgrequest2.J2KDecoder = m_j2kDecodeModule;
150// imgrequest2.AssetService = m_assetCache;
151// imgrequest2.AgentID = m_client.AgentId;
152// imgrequest2.InventoryAccessModule = m_client.Scene.RequestModuleInterface<IInventoryAccessModule>();
153// imgrequest2.DiscardLevel = newRequest.DiscardLevel;
154// imgrequest2.StartPacket = Math.Max(1, newRequest.PacketNumber);
155// imgrequest2.Priority = newRequest.Priority;
156// imgrequest2.TextureID = newRequest.RequestedAssetID;
157// imgrequest2.Priority = newRequest.Priority;
158//
159// //Add this download to the priority queue
160// AddImageToQueue(imgrequest2);
161//
162// imgrequest2.RunUpdate();
163
164 }
165// else
166// {
167// m_log.DebugFormat(
168// "[LL IMAGE MANAGER]: Ignoring duplicate of existing request for {0} (sequence {1}) from {2} as its request sequence {3} is not greater",
169// newRequest.RequestedAssetID, imgrequest.LastSequence, m_client.Name, newRequest.requestSequence);
170// }
171 }
172 }
173 else
174 {
175 if (newRequest.DiscardLevel == -1 && newRequest.Priority == 0f)
176 {
177 //m_log.DebugFormat("[TEX]: (IGN) ID={0}: D={1}, S={2}, P={3}",
178 // newRequest.RequestedAssetID, newRequest.DiscardLevel, newRequest.PacketNumber, newRequest.Priority);
179 }
180 else
181 {
182// m_log.DebugFormat(
183// "[LL IMAGE MANAGER]: Received request for {0}, start packet {1} from {2}",
184// newRequest.RequestedAssetID, newRequest.PacketNumber, m_client.Name);
185
186 //m_log.DebugFormat("[TEX]: (NEW) ID={0}: D={1}, S={2}, P={3}",
187 // newRequest.RequestedAssetID, newRequest.DiscardLevel, newRequest.PacketNumber, newRequest.Priority);
188
189 imgrequest = new J2KImage(this);
190 imgrequest.J2KDecoder = m_j2kDecodeModule;
191 imgrequest.AssetService = m_assetCache;
192 imgrequest.AgentID = Client.AgentId;
193 imgrequest.InventoryAccessModule = Client.Scene.RequestModuleInterface<IInventoryAccessModule>();
194 imgrequest.DiscardLevel = newRequest.DiscardLevel;
195 imgrequest.StartPacket = Math.Max(1, newRequest.PacketNumber);
196 imgrequest.Priority = newRequest.Priority;
197 imgrequest.TextureID = newRequest.RequestedAssetID;
198 imgrequest.Priority = newRequest.Priority;
199
200 //Add this download to the priority queue
201 AddImageToQueue(imgrequest);
202
203 imgrequest.RunUpdate();
204 }
205 }
206 }
207 }
208
209 public bool HasUpdates()
210 {
211 J2KImage image = GetHighestPriorityImage();
212
213 return image != null && image.IsDecoded;
214 }
215
216 public bool ProcessImageQueue(int packetsToSend)
217 {
218 int packetsSent = 0;
219
220 while (packetsSent < packetsToSend)
221 {
222 J2KImage image = GetHighestPriorityImage();
223
224 // If null was returned, the texture priority queue is currently empty
225 if (image == null)
226 break;
227
228 if (image.IsDecoded)
229 {
230 int sent;
231 bool imageDone = image.SendPackets(Client, packetsToSend - packetsSent, out sent);
232 packetsSent += sent;
233
234 // If the send is complete, destroy any knowledge of this transfer
235 if (imageDone)
236 RemoveImageFromQueue(image);
237 }
238 else
239 {
240 // TODO: This is a limitation of how LLImageManager is currently
241 // written. Undecoded textures should not be going into the priority
242 // queue, because a high priority undecoded texture will clog up the
243 // pipeline for a client
244// m_log.DebugFormat(
245// "[LL IMAGE MANAGER]: Exiting image queue processing early on encountering undecoded image {0}",
246// image.TextureID);
247
248 break;
249 }
250 }
251
252// if (packetsSent != 0)
253// m_log.DebugFormat("[LL IMAGE MANAGER]: Processed {0} packets from image queue", packetsSent);
254
255 return m_priorityQueue.Count > 0;
256 }
257
258 /// <summary>
259 /// Faux destructor
260 /// </summary>
261 public void Close()
262 {
263 m_shuttingdown = true;
264 }
265
266 /// <summary>
267 /// Clear the image queue.
268 /// </summary>
269 /// <returns>The number of requests cleared.</returns>
270 public int ClearImageQueue()
271 {
272 int requestsDeleted;
273
274 lock (m_priorityQueue)
275 {
276 requestsDeleted = m_priorityQueue.Count;
277
278 // Surprisingly, there doesn't seem to be a clear method at this time.
279 while (!m_priorityQueue.IsEmpty)
280 m_priorityQueue.DeleteMax();
281 }
282
283 return requestsDeleted;
284 }
285
286 /// <summary>
287 /// Returns an array containing all the images in the queue.
288 /// </summary>
289 /// <returns></returns>
290 public J2KImage[] GetImages()
291 {
292 lock (m_priorityQueue)
293 return m_priorityQueue.ToArray();
294 }
295
296 #region Priority Queue Helpers
297
298 private J2KImage GetHighestPriorityImage()
299 {
300 J2KImage image = null;
301
302 lock (m_syncRoot)
303 {
304 if (m_priorityQueue.Count > 0)
305 {
306 try
307 {
308 image = m_priorityQueue.FindMax();
309 }
310 catch (Exception) { }
311 }
312 }
313 return image;
314 }
315
316 private void AddImageToQueue(J2KImage image)
317 {
318 image.PriorityQueueHandle = null;
319
320 lock (m_syncRoot)
321 {
322 try
323 {
324 m_priorityQueue.Add(ref image.PriorityQueueHandle, image);
325 }
326 catch (Exception) { }
327 }
328 }
329
330 private void RemoveImageFromQueue(J2KImage image)
331 {
332 lock (m_syncRoot)
333 {
334 try
335 {
336 m_priorityQueue.Delete(image.PriorityQueueHandle);
337 }
338 catch (Exception) { }
339 }
340 }
341
342 private void UpdateImageInQueue(J2KImage image)
343 {
344 lock (m_syncRoot)
345 {
346 try
347 {
348 m_priorityQueue.Replace(image.PriorityQueueHandle, image);
349 }
350 catch (Exception)
351 {
352 image.PriorityQueueHandle = null;
353 m_priorityQueue.Add(ref image.PriorityQueueHandle, image);
354 }
355 }
356 }
357
358 #endregion Priority Queue Helpers
359 }
360} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
new file mode 100644
index 0000000..0394e54
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
@@ -0,0 +1,842 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Net;
31using System.Threading;
32using log4net;
33using OpenSim.Framework;
34using OpenSim.Framework.Monitoring;
35using OpenMetaverse;
36using OpenMetaverse.Packets;
37
38using TokenBucket = OpenSim.Region.ClientStack.LindenUDP.TokenBucket;
39
40namespace OpenSim.Region.ClientStack.LindenUDP
41{
42 #region Delegates
43
44 /// <summary>
45 /// Fired when updated networking stats are produced for this client
46 /// </summary>
47 /// <param name="inPackets">Number of incoming packets received since this
48 /// event was last fired</param>
49 /// <param name="outPackets">Number of outgoing packets sent since this
50 /// event was last fired</param>
51 /// <param name="unAckedBytes">Current total number of bytes in packets we
52 /// are waiting on ACKs for</param>
53 public delegate void PacketStats(int inPackets, int outPackets, int unAckedBytes);
54 /// <summary>
55 /// Fired when the queue for one or more packet categories is empty. This
56 /// event can be hooked to put more data on the empty queues
57 /// </summary>
58 /// <param name="category">Categories of the packet queues that are empty</param>
59 public delegate void QueueEmpty(ThrottleOutPacketTypeFlags categories);
60
61 #endregion Delegates
62
63 /// <summary>
64 /// Tracks state for a client UDP connection and provides client-specific methods
65 /// </summary>
66 public sealed class LLUDPClient
67 {
68 // TODO: Make this a config setting
69 /// <summary>Percentage of the task throttle category that is allocated to avatar and prim
70 /// state updates</summary>
71 const float STATE_TASK_PERCENTAGE = 0.8f;
72
73 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
74
75 /// <summary>The number of packet categories to throttle on. If a throttle category is added
76 /// or removed, this number must also change</summary>
77 const int THROTTLE_CATEGORY_COUNT = 8;
78
79 /// <summary>
80 /// Controls whether information is logged about each outbound packet immediately before it is sent. For debug purposes.
81 /// </summary>
82 /// <remarks>Any level above 0 will turn on logging.</remarks>
83 public int DebugDataOutLevel { get; set; }
84
85 /// <summary>
86 /// Controls whether information is logged about each outbound packet immediately before it is sent. For debug purposes.
87 /// </summary>
88 /// <remarks>Any level above 0 will turn on logging.</remarks>
89 public int ThrottleDebugLevel
90 {
91 get
92 {
93 return m_throttleDebugLevel;
94 }
95
96 set
97 {
98 m_throttleDebugLevel = value;
99 m_throttleClient.DebugLevel = m_throttleDebugLevel;
100 foreach (TokenBucket tb in m_throttleCategories)
101 tb.DebugLevel = m_throttleDebugLevel;
102 }
103 }
104 private int m_throttleDebugLevel;
105
106 /// <summary>Fired when updated networking stats are produced for this client</summary>
107 public event PacketStats OnPacketStats;
108 /// <summary>Fired when the queue for a packet category is empty. This event can be
109 /// hooked to put more data on the empty queue</summary>
110 public event QueueEmpty OnQueueEmpty;
111
112 public event Func<ThrottleOutPacketTypeFlags, bool> HasUpdates;
113
114 /// <summary>AgentID for this client</summary>
115 public readonly UUID AgentID;
116 /// <summary>The remote address of the connected client</summary>
117 public readonly IPEndPoint RemoteEndPoint;
118 /// <summary>Circuit code that this client is connected on</summary>
119 public readonly uint CircuitCode;
120 /// <summary>Sequence numbers of packets we've received (for duplicate checking)</summary>
121 public readonly IncomingPacketHistoryCollection PacketArchive = new IncomingPacketHistoryCollection(200);
122
123 /// <summary>
124 /// If true then we take action in response to unacked reliably sent packets such as resending the packet.
125 /// </summary>
126 public bool ProcessUnackedSends { get; set; }
127
128 /// <summary>Packets we have sent that need to be ACKed by the client</summary>
129 public readonly UnackedPacketCollection NeedAcks = new UnackedPacketCollection();
130
131 /// <summary>ACKs that are queued up, waiting to be sent to the client</summary>
132 public readonly OpenSim.Framework.LocklessQueue<uint> PendingAcks = new OpenSim.Framework.LocklessQueue<uint>();
133
134 /// <summary>Current packet sequence number</summary>
135 public int CurrentSequence;
136 /// <summary>Current ping sequence number</summary>
137 public byte CurrentPingSequence;
138 /// <summary>True when this connection is alive, otherwise false</summary>
139 public bool IsConnected = true;
140 /// <summary>True when this connection is paused, otherwise false</summary>
141 public bool IsPaused;
142 /// <summary>Environment.TickCount when the last packet was received for this client</summary>
143 public int TickLastPacketReceived;
144
145 /// <summary>Smoothed round-trip time. A smoothed average of the round-trip time for sending a
146 /// reliable packet to the client and receiving an ACK</summary>
147 public float SRTT;
148 /// <summary>Round-trip time variance. Measures the consistency of round-trip times</summary>
149 public float RTTVAR;
150 /// <summary>Retransmission timeout. Packets that have not been acknowledged in this number of
151 /// milliseconds or longer will be resent</summary>
152 /// <remarks>Calculated from <seealso cref="SRTT"/> and <seealso cref="RTTVAR"/> using the
153 /// guidelines in RFC 2988</remarks>
154 public int RTO;
155 /// <summary>Number of bytes received since the last acknowledgement was sent out. This is used
156 /// to loosely follow the TCP delayed ACK algorithm in RFC 1122 (4.2.3.2)</summary>
157 public int BytesSinceLastACK;
158 /// <summary>Number of packets received from this client</summary>
159 public int PacketsReceived;
160 /// <summary>Number of packets sent to this client</summary>
161 public int PacketsSent;
162 /// <summary>Number of packets resent to this client</summary>
163 public int PacketsResent;
164 /// <summary>Total byte count of unacked packets sent to this client</summary>
165 public int UnackedBytes;
166
167 /// <summary>Total number of received packets that we have reported to the OnPacketStats event(s)</summary>
168 private int m_packetsReceivedReported;
169 /// <summary>Total number of sent packets that we have reported to the OnPacketStats event(s)</summary>
170 private int m_packetsSentReported;
171 /// <summary>Holds the Environment.TickCount value of when the next OnQueueEmpty can be fired</summary>
172 private int m_nextOnQueueEmpty = 1;
173
174 /// <summary>Throttle bucket for this agent's connection</summary>
175 private readonly AdaptiveTokenBucket m_throttleClient;
176 public AdaptiveTokenBucket FlowThrottle
177 {
178 get { return m_throttleClient; }
179 }
180
181 /// <summary>Throttle buckets for each packet category</summary>
182 private readonly TokenBucket[] m_throttleCategories;
183 /// <summary>Outgoing queues for throttled packets</summary>
184 private readonly OpenSim.Framework.LocklessQueue<OutgoingPacket>[] m_packetOutboxes = new OpenSim.Framework.LocklessQueue<OutgoingPacket>[THROTTLE_CATEGORY_COUNT];
185 /// <summary>A container that can hold one packet for each outbox, used to store
186 /// dequeued packets that are being held for throttling</summary>
187 private readonly OutgoingPacket[] m_nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT];
188 /// <summary>A reference to the LLUDPServer that is managing this client</summary>
189 private readonly LLUDPServer m_udpServer;
190
191 /// <summary>Caches packed throttle information</summary>
192 private byte[] m_packedThrottles;
193
194 private int m_defaultRTO = 1000; // 1sec is the recommendation in the RFC
195 private int m_maxRTO = 60000;
196
197 /// <summary>
198 /// This is the percentage of the udp texture queue to add to the task queue since
199 /// textures are now generally handled through http.
200 /// </summary>
201 private double m_cannibalrate = 0.0;
202
203 private ClientInfo m_info = new ClientInfo();
204
205 /// <summary>
206 /// Default constructor
207 /// </summary>
208 /// <param name="server">Reference to the UDP server this client is connected to</param>
209 /// <param name="rates">Default throttling rates and maximum throttle limits</param>
210 /// <param name="parentThrottle">Parent HTB (hierarchical token bucket)
211 /// that the child throttles will be governed by</param>
212 /// <param name="circuitCode">Circuit code for this connection</param>
213 /// <param name="agentID">AgentID for the connected agent</param>
214 /// <param name="remoteEndPoint">Remote endpoint for this connection</param>
215 /// <param name="defaultRTO">
216 /// Default retransmission timeout for unacked packets. The RTO will never drop
217 /// beyond this number.
218 /// </param>
219 /// <param name="maxRTO">
220 /// The maximum retransmission timeout for unacked packets. The RTO will never exceed this number.
221 /// </param>
222 public LLUDPClient(
223 LLUDPServer server, ThrottleRates rates, TokenBucket parentThrottle, uint circuitCode, UUID agentID,
224 IPEndPoint remoteEndPoint, int defaultRTO, int maxRTO)
225 {
226 AgentID = agentID;
227 RemoteEndPoint = remoteEndPoint;
228 CircuitCode = circuitCode;
229 m_udpServer = server;
230 if (defaultRTO != 0)
231 m_defaultRTO = defaultRTO;
232 if (maxRTO != 0)
233 m_maxRTO = maxRTO;
234
235 ProcessUnackedSends = true;
236
237 // Create a token bucket throttle for this client that has the scene token bucket as a parent
238 m_throttleClient
239 = new AdaptiveTokenBucket(
240 string.Format("adaptive throttle for {0} in {1}", AgentID, server.Scene.Name),
241 parentThrottle, 0, rates.Total, rates.MinimumAdaptiveThrottleRate, rates.AdaptiveThrottlesEnabled);
242
243 // Create an array of token buckets for this clients different throttle categories
244 m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT];
245
246 m_cannibalrate = rates.CannibalizeTextureRate;
247
248 for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
249 {
250 ThrottleOutPacketType type = (ThrottleOutPacketType)i;
251
252 // Initialize the packet outboxes, where packets sit while they are waiting for tokens
253 m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>();
254
255 // Initialize the token buckets that control the throttling for each category
256 m_throttleCategories[i]
257 = new TokenBucket(
258 string.Format("{0} throttle for {1} in {2}", type, AgentID, server.Scene.Name),
259 m_throttleClient, rates.GetRate(type), 0);
260 }
261
262 // Default the retransmission timeout to one second
263 RTO = m_defaultRTO;
264
265 // Initialize this to a sane value to prevent early disconnects
266 TickLastPacketReceived = Environment.TickCount & Int32.MaxValue;
267 }
268
269 /// <summary>
270 /// Shuts down this client connection
271 /// </summary>
272 public void Shutdown()
273 {
274 IsConnected = false;
275 for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
276 {
277 m_packetOutboxes[i].Clear();
278 m_nextPackets[i] = null;
279 }
280
281 // pull the throttle out of the scene throttle
282 m_throttleClient.Parent.UnregisterRequest(m_throttleClient);
283 OnPacketStats = null;
284 OnQueueEmpty = null;
285 }
286
287 /// <summary>
288 /// Gets information about this client connection
289 /// </summary>
290 /// <returns>Information about the client connection</returns>
291 public ClientInfo GetClientInfo()
292 {
293 // TODO: This data structure is wrong in so many ways. Locking and copying the entire lists
294 // of pending and needed ACKs for every client every time some method wants information about
295 // this connection is a recipe for poor performance
296
297 m_info.resendThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate;
298 m_info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate;
299 m_info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate;
300 m_info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate;
301 m_info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate;
302 m_info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate;
303 m_info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate;
304 m_info.totalThrottle = (int)m_throttleClient.DripRate;
305 m_info.targetThrottle = (int)m_throttleClient.TargetDripRate;
306 m_info.maxThrottle = (int)m_throttleClient.MaxDripRate;
307
308 return m_info;
309 }
310
311 /// <summary>
312 /// Modifies the UDP throttles
313 /// </summary>
314 /// <param name="info">New throttling values</param>
315 public void SetClientInfo(ClientInfo info)
316 {
317 // TODO: Allowing throttles to be manually set from this function seems like a reasonable
318 // idea. On the other hand, letting external code manipulate our ACK accounting is not
319 // going to happen
320 throw new NotImplementedException();
321 }
322
323 /// <summary>
324 /// Get the total number of pakcets queued for this client.
325 /// </summary>
326 /// <returns></returns>
327 public int GetTotalPacketsQueuedCount()
328 {
329 int total = 0;
330
331 for (int i = 0; i <= (int)ThrottleOutPacketType.Asset; i++)
332 total += m_packetOutboxes[i].Count;
333
334 return total;
335 }
336
337 /// <summary>
338 /// Get the number of packets queued for the given throttle type.
339 /// </summary>
340 /// <returns></returns>
341 /// <param name="throttleType"></param>
342 public int GetPacketsQueuedCount(ThrottleOutPacketType throttleType)
343 {
344 if ((int)throttleType > 0)
345 return m_packetOutboxes[(int)throttleType].Count;
346 else
347 return 0;
348 }
349
350 /// <summary>
351 /// Return statistics information about client packet queues.
352 /// </summary>
353 /// <remarks>
354 /// FIXME: This should really be done in a more sensible manner rather than sending back a formatted string.
355 /// </remarks>
356 /// <returns></returns>
357 public string GetStats()
358 {
359 return string.Format(
360 "{0,7} {1,7} {2,7} {3,9} {4,7} {5,7} {6,7} {7,7} {8,7} {9,8} {10,7} {11,7}",
361 Util.EnvironmentTickCountSubtract(TickLastPacketReceived),
362 PacketsReceived,
363 PacketsSent,
364 PacketsResent,
365 UnackedBytes,
366 m_packetOutboxes[(int)ThrottleOutPacketType.Resend].Count,
367 m_packetOutboxes[(int)ThrottleOutPacketType.Land].Count,
368 m_packetOutboxes[(int)ThrottleOutPacketType.Wind].Count,
369 m_packetOutboxes[(int)ThrottleOutPacketType.Cloud].Count,
370 m_packetOutboxes[(int)ThrottleOutPacketType.Task].Count,
371 m_packetOutboxes[(int)ThrottleOutPacketType.Texture].Count,
372 m_packetOutboxes[(int)ThrottleOutPacketType.Asset].Count);
373 }
374
375 public void SendPacketStats()
376 {
377 PacketStats callback = OnPacketStats;
378 if (callback != null)
379 {
380 int newPacketsReceived = PacketsReceived - m_packetsReceivedReported;
381 int newPacketsSent = PacketsSent - m_packetsSentReported;
382
383 callback(newPacketsReceived, newPacketsSent, UnackedBytes);
384
385 m_packetsReceivedReported += newPacketsReceived;
386 m_packetsSentReported += newPacketsSent;
387 }
388 }
389
390 public void SetThrottles(byte[] throttleData)
391 {
392 byte[] adjData;
393 int pos = 0;
394
395 if (!BitConverter.IsLittleEndian)
396 {
397 byte[] newData = new byte[7 * 4];
398 Buffer.BlockCopy(throttleData, 0, newData, 0, 7 * 4);
399
400 for (int i = 0; i < 7; i++)
401 Array.Reverse(newData, i * 4, 4);
402
403 adjData = newData;
404 }
405 else
406 {
407 adjData = throttleData;
408 }
409
410 // 0.125f converts from bits to bytes
411 int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
412 int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
413 int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
414 int cloud = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
415 int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
416 int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
417 int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
418
419 if (ThrottleDebugLevel > 0)
420 {
421 long total = resend + land + wind + cloud + task + texture + asset;
422 m_log.DebugFormat(
423 "[LLUDPCLIENT]: {0} is setting throttles in {1} to Resend={2}, Land={3}, Wind={4}, Cloud={5}, Task={6}, Texture={7}, Asset={8}, TOTAL = {9}",
424 AgentID, m_udpServer.Scene.Name, resend, land, wind, cloud, task, texture, asset, total);
425 }
426
427 // Make sure none of the throttles are set below our packet MTU,
428 // otherwise a throttle could become permanently clogged
429 resend = Math.Max(resend, LLUDPServer.MTU);
430 land = Math.Max(land, LLUDPServer.MTU);
431 wind = Math.Max(wind, LLUDPServer.MTU);
432 cloud = Math.Max(cloud, LLUDPServer.MTU);
433 task = Math.Max(task, LLUDPServer.MTU);
434 texture = Math.Max(texture, LLUDPServer.MTU);
435 asset = Math.Max(asset, LLUDPServer.MTU);
436
437 // Since most textures are now delivered through http, make it possible
438 // to cannibalize some of the bw from the texture throttle to use for
439 // the task queue (e.g. object updates)
440 task = task + (int)(m_cannibalrate * texture);
441 texture = (int)((1 - m_cannibalrate) * texture);
442
443 //int total = resend + land + wind + cloud + task + texture + asset;
444
445 if (ThrottleDebugLevel > 0)
446 {
447 long total = resend + land + wind + cloud + task + texture + asset;
448 m_log.DebugFormat(
449 "[LLUDPCLIENT]: {0} is setting throttles in {1} to Resend={2}, Land={3}, Wind={4}, Cloud={5}, Task={6}, Texture={7}, Asset={8}, TOTAL = {9}",
450 AgentID, m_udpServer.Scene.Name, resend, land, wind, cloud, task, texture, asset, total);
451 }
452
453 // Update the token buckets with new throttle values
454 if (m_throttleClient.AdaptiveEnabled)
455 {
456 long total = resend + land + wind + cloud + task + texture + asset;
457 m_throttleClient.TargetDripRate = total;
458 }
459
460 TokenBucket bucket;
461
462 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend];
463 bucket.RequestedDripRate = resend;
464
465 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land];
466 bucket.RequestedDripRate = land;
467
468 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind];
469 bucket.RequestedDripRate = wind;
470
471 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud];
472 bucket.RequestedDripRate = cloud;
473
474 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset];
475 bucket.RequestedDripRate = asset;
476
477 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task];
478 bucket.RequestedDripRate = task;
479
480 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture];
481 bucket.RequestedDripRate = texture;
482
483 // Reset the packed throttles cached data
484 m_packedThrottles = null;
485 }
486
487 public byte[] GetThrottlesPacked(float multiplier)
488 {
489 byte[] data = m_packedThrottles;
490
491 if (data == null)
492 {
493 float rate;
494
495 data = new byte[7 * 4];
496 int i = 0;
497
498 // multiply by 8 to convert bytes back to bits
499 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].RequestedDripRate * 8 * multiplier;
500 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
501
502 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Land].RequestedDripRate * 8 * multiplier;
503 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
504
505 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].RequestedDripRate * 8 * multiplier;
506 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
507
508 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].RequestedDripRate * 8 * multiplier;
509 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
510
511 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Task].RequestedDripRate * 8 * multiplier;
512 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
513
514 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].RequestedDripRate * 8 * multiplier;
515 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
516
517 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].RequestedDripRate * 8 * multiplier;
518 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
519
520 m_packedThrottles = data;
521 }
522
523 return data;
524 }
525
526 /// <summary>
527 /// Queue an outgoing packet if appropriate.
528 /// </summary>
529 /// <param name="packet"></param>
530 /// <param name="forceQueue">Always queue the packet if at all possible.</param>
531 /// <returns>
532 /// true if the packet has been queued,
533 /// false if the packet has not been queued and should be sent immediately.
534 /// </returns>
535 public bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue)
536 {
537 int category = (int)packet.Category;
538
539 if (category >= 0 && category < m_packetOutboxes.Length)
540 {
541 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category];
542 TokenBucket bucket = m_throttleCategories[category];
543
544 // Don't send this packet if there is already a packet waiting in the queue
545 // even if we have the tokens to send it, tokens should go to the already
546 // queued packets
547 if (queue.Count > 0)
548 {
549 queue.Enqueue(packet);
550 return true;
551 }
552
553
554 if (!forceQueue && bucket.RemoveTokens(packet.Buffer.DataLength))
555 {
556 // Enough tokens were removed from the bucket, the packet will not be queued
557 return false;
558 }
559 else
560 {
561 // Force queue specified or not enough tokens in the bucket, queue this packet
562 queue.Enqueue(packet);
563 return true;
564 }
565 }
566 else
567 {
568 // We don't have a token bucket for this category, so it will not be queued
569 return false;
570 }
571 }
572
573 /// <summary>
574 /// Loops through all of the packet queues for this client and tries to send
575 /// an outgoing packet from each, obeying the throttling bucket limits
576 /// </summary>
577 ///
578 /// <remarks>
579 /// Packet queues are inspected in ascending numerical order starting from 0. Therefore, queues with a lower
580 /// ThrottleOutPacketType number will see their packet get sent first (e.g. if both Land and Wind queues have
581 /// packets, then the packet at the front of the Land queue will be sent before the packet at the front of the
582 /// wind queue).
583 ///
584 /// This function is only called from a synchronous loop in the
585 /// UDPServer so we don't need to bother making this thread safe
586 /// </remarks>
587 ///
588 /// <returns>True if any packets were sent, otherwise false</returns>
589 public bool DequeueOutgoing()
590 {
591 OutgoingPacket packet;
592 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue;
593 TokenBucket bucket;
594 bool packetSent = false;
595 ThrottleOutPacketTypeFlags emptyCategories = 0;
596
597 //string queueDebugOutput = String.Empty; // Serious debug business
598
599 for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
600 {
601 bucket = m_throttleCategories[i];
602 //queueDebugOutput += m_packetOutboxes[i].Count + " "; // Serious debug business
603
604 if (m_nextPackets[i] != null)
605 {
606 // This bucket was empty the last time we tried to send a packet,
607 // leaving a dequeued packet still waiting to be sent out. Try to
608 // send it again
609 OutgoingPacket nextPacket = m_nextPackets[i];
610 if (bucket.RemoveTokens(nextPacket.Buffer.DataLength))
611 {
612 // Send the packet
613 m_udpServer.SendPacketFinal(nextPacket);
614 m_nextPackets[i] = null;
615 packetSent = true;
616 }
617 }
618 else
619 {
620 // No dequeued packet waiting to be sent, try to pull one off
621 // this queue
622 queue = m_packetOutboxes[i];
623 if (queue.Dequeue(out packet))
624 {
625 // A packet was pulled off the queue. See if we have
626 // enough tokens in the bucket to send it out
627 if (bucket.RemoveTokens(packet.Buffer.DataLength))
628 {
629 // Send the packet
630 m_udpServer.SendPacketFinal(packet);
631 packetSent = true;
632 }
633 else
634 {
635 // Save the dequeued packet for the next iteration
636 m_nextPackets[i] = packet;
637 }
638
639 // If the queue is empty after this dequeue, fire the queue
640 // empty callback now so it has a chance to fill before we
641 // get back here
642 if (queue.Count == 0)
643 emptyCategories |= CategoryToFlag(i);
644 }
645 else
646 {
647 // No packets in this queue. Fire the queue empty callback
648 // if it has not been called recently
649 emptyCategories |= CategoryToFlag(i);
650 }
651 }
652 }
653
654 if (emptyCategories != 0)
655 BeginFireQueueEmpty(emptyCategories);
656
657 //m_log.Info("[LLUDPCLIENT]: Queues: " + queueDebugOutput); // Serious debug business
658 return packetSent;
659 }
660
661 /// <summary>
662 /// Called when an ACK packet is received and a round-trip time for a
663 /// packet is calculated. This is used to calculate the smoothed
664 /// round-trip time, round trip time variance, and finally the
665 /// retransmission timeout
666 /// </summary>
667 /// <param name="r">Round-trip time of a single packet and its
668 /// acknowledgement</param>
669 public void UpdateRoundTrip(float r)
670 {
671 const float ALPHA = 0.125f;
672 const float BETA = 0.25f;
673 const float K = 4.0f;
674
675 if (RTTVAR == 0.0f)
676 {
677 // First RTT measurement
678 SRTT = r;
679 RTTVAR = r * 0.5f;
680 }
681 else
682 {
683 // Subsequence RTT measurement
684 RTTVAR = (1.0f - BETA) * RTTVAR + BETA * Math.Abs(SRTT - r);
685 SRTT = (1.0f - ALPHA) * SRTT + ALPHA * r;
686 }
687
688 int rto = (int)(SRTT + Math.Max(m_udpServer.TickCountResolution, K * RTTVAR));
689
690 // Clamp the retransmission timeout to manageable values
691 rto = Utils.Clamp(rto, m_defaultRTO, m_maxRTO);
692
693 RTO = rto;
694
695 //if (RTO != rto)
696 // m_log.Debug("[LLUDPCLIENT]: Setting RTO to " + RTO + "ms from " + rto + "ms with an RTTVAR of " +
697 //RTTVAR + " based on new RTT of " + r + "ms");
698 }
699
700 /// <summary>
701 /// Exponential backoff of the retransmission timeout, per section 5.5
702 /// of RFC 2988
703 /// </summary>
704 public void BackoffRTO()
705 {
706 // Reset SRTT and RTTVAR, we assume they are bogus since things
707 // didn't work out and we're backing off the timeout
708 SRTT = 0.0f;
709 RTTVAR = 0.0f;
710
711 // Double the retransmission timeout
712 RTO = Math.Min(RTO * 2, m_maxRTO);
713 }
714
715 /// <summary>
716 /// Does an early check to see if this queue empty callback is already
717 /// running, then asynchronously firing the event
718 /// </summary>
719 /// <param name="categories">Throttle categories to fire the callback for</param>
720 private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories)
721 {
722// if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty)
723 if (!m_isQueueEmptyRunning && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty)
724 {
725 m_isQueueEmptyRunning = true;
726
727 int start = Environment.TickCount & Int32.MaxValue;
728 const int MIN_CALLBACK_MS = 30;
729
730 m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
731 if (m_nextOnQueueEmpty == 0)
732 m_nextOnQueueEmpty = 1;
733
734 // Use a value of 0 to signal that FireQueueEmpty is running
735// m_nextOnQueueEmpty = 0;
736
737 m_categories = categories;
738
739 if (HasUpdates(m_categories))
740 {
741 if (!m_udpServer.OqrEngine.IsRunning)
742 {
743 // Asynchronously run the callback
744 Util.FireAndForget(FireQueueEmpty, categories, "LLUDPClient.BeginFireQueueEmpty");
745 }
746 else
747 {
748 m_udpServer.OqrEngine.QueueJob(AgentID.ToString(), () => FireQueueEmpty(categories));
749 }
750 }
751 else
752 {
753 m_isQueueEmptyRunning = false;
754 }
755 }
756 }
757
758 private bool m_isQueueEmptyRunning;
759 private ThrottleOutPacketTypeFlags m_categories = 0;
760
761 /// <summary>
762 /// Fires the OnQueueEmpty callback and sets the minimum time that it
763 /// can be called again
764 /// </summary>
765 /// <param name="o">Throttle categories to fire the callback for,
766 /// stored as an object to match the WaitCallback delegate
767 /// signature</param>
768 public void FireQueueEmpty(object o)
769 {
770// m_log.DebugFormat("[LLUDPCLIENT]: FireQueueEmpty for {0} in {1}", AgentID, m_udpServer.Scene.Name);
771
772// int start = Environment.TickCount & Int32.MaxValue;
773// const int MIN_CALLBACK_MS = 30;
774
775// if (m_udpServer.IsRunningOutbound)
776// {
777 ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o;
778 QueueEmpty callback = OnQueueEmpty;
779
780 if (callback != null)
781 {
782// if (m_udpServer.IsRunningOutbound)
783// {
784 try { callback(categories); }
785 catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); }
786// }
787 }
788// }
789
790// m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
791// if (m_nextOnQueueEmpty == 0)
792// m_nextOnQueueEmpty = 1;
793
794// }
795
796 m_isQueueEmptyRunning = false;
797 }
798
799 /// <summary>
800 /// Converts a <seealso cref="ThrottleOutPacketType"/> integer to a
801 /// flag value
802 /// </summary>
803 /// <param name="i">Throttle category to convert</param>
804 /// <returns>Flag representation of the throttle category</returns>
805 private static ThrottleOutPacketTypeFlags CategoryToFlag(int i)
806 {
807 ThrottleOutPacketType category = (ThrottleOutPacketType)i;
808
809 /*
810 * Land = 1,
811 /// <summary>Wind data</summary>
812 Wind = 2,
813 /// <summary>Cloud data</summary>
814 Cloud = 3,
815 /// <summary>Any packets that do not fit into the other throttles</summary>
816 Task = 4,
817 /// <summary>Texture assets</summary>
818 Texture = 5,
819 /// <summary>Non-texture assets</summary>
820 Asset = 6,
821 */
822
823 switch (category)
824 {
825 case ThrottleOutPacketType.Land:
826 return ThrottleOutPacketTypeFlags.Land;
827 case ThrottleOutPacketType.Wind:
828 return ThrottleOutPacketTypeFlags.Wind;
829 case ThrottleOutPacketType.Cloud:
830 return ThrottleOutPacketTypeFlags.Cloud;
831 case ThrottleOutPacketType.Task:
832 return ThrottleOutPacketTypeFlags.Task;
833 case ThrottleOutPacketType.Texture:
834 return ThrottleOutPacketTypeFlags.Texture;
835 case ThrottleOutPacketType.Asset:
836 return ThrottleOutPacketTypeFlags.Asset;
837 default:
838 return 0;
839 }
840 }
841 }
842}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
new file mode 100644
index 0000000..76be91a
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -0,0 +1,2216 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Diagnostics;
31using System.IO;
32using System.Net;
33using System.Net.Sockets;
34using System.Reflection;
35using System.Threading;
36using log4net;
37using Nini.Config;
38using OpenMetaverse.Packets;
39using OpenSim.Framework;
40using OpenSim.Framework.Console;
41using OpenSim.Framework.Monitoring;
42using OpenSim.Region.Framework.Scenes;
43using OpenMetaverse;
44
45using TokenBucket = OpenSim.Region.ClientStack.LindenUDP.TokenBucket;
46
47namespace OpenSim.Region.ClientStack.LindenUDP
48{
49 /// <summary>
50 /// A shim around LLUDPServer that implements the IClientNetworkServer interface
51 /// </summary>
52 public sealed class LLUDPServerShim : IClientNetworkServer
53 {
54 LLUDPServer m_udpServer;
55
56 public LLUDPServerShim()
57 {
58 }
59
60 public void Initialise(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager)
61 {
62 m_udpServer = new LLUDPServer(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager);
63 }
64
65 public void AddScene(IScene scene)
66 {
67 m_udpServer.AddScene(scene);
68
69 StatsManager.RegisterStat(
70 new Stat(
71 "ClientLogoutsDueToNoReceives",
72 "Number of times a client has been logged out because no packets were received before the timeout.",
73 "",
74 "",
75 "clientstack",
76 scene.Name,
77 StatType.Pull,
78 MeasuresOfInterest.None,
79 stat => stat.Value = m_udpServer.ClientLogoutsDueToNoReceives,
80 StatVerbosity.Debug));
81
82 StatsManager.RegisterStat(
83 new Stat(
84 "IncomingUDPReceivesCount",
85 "Number of UDP receives performed",
86 "",
87 "",
88 "clientstack",
89 scene.Name,
90 StatType.Pull,
91 MeasuresOfInterest.AverageChangeOverTime,
92 stat => stat.Value = m_udpServer.UdpReceives,
93 StatVerbosity.Debug));
94
95 StatsManager.RegisterStat(
96 new Stat(
97 "IncomingPacketsProcessedCount",
98 "Number of inbound LL protocol packets processed",
99 "",
100 "",
101 "clientstack",
102 scene.Name,
103 StatType.Pull,
104 MeasuresOfInterest.AverageChangeOverTime,
105 stat => stat.Value = m_udpServer.IncomingPacketsProcessed,
106 StatVerbosity.Debug));
107
108 StatsManager.RegisterStat(
109 new Stat(
110 "IncomingPacketsMalformedCount",
111 "Number of inbound UDP packets that could not be recognized as LL protocol packets.",
112 "",
113 "",
114 "clientstack",
115 scene.Name,
116 StatType.Pull,
117 MeasuresOfInterest.AverageChangeOverTime,
118 stat => stat.Value = m_udpServer.IncomingMalformedPacketCount,
119 StatVerbosity.Info));
120
121 StatsManager.RegisterStat(
122 new Stat(
123 "IncomingPacketsOrphanedCount",
124 "Number of inbound packets that were not initial connections packets and could not be associated with a viewer.",
125 "",
126 "",
127 "clientstack",
128 scene.Name,
129 StatType.Pull,
130 MeasuresOfInterest.AverageChangeOverTime,
131 stat => stat.Value = m_udpServer.IncomingOrphanedPacketCount,
132 StatVerbosity.Info));
133
134 StatsManager.RegisterStat(
135 new Stat(
136 "IncomingPacketsResentCount",
137 "Number of inbound packets that clients indicate are resends.",
138 "",
139 "",
140 "clientstack",
141 scene.Name,
142 StatType.Pull,
143 MeasuresOfInterest.AverageChangeOverTime,
144 stat => stat.Value = m_udpServer.IncomingPacketsResentCount,
145 StatVerbosity.Debug));
146
147 StatsManager.RegisterStat(
148 new Stat(
149 "OutgoingUDPSendsCount",
150 "Number of UDP sends performed",
151 "",
152 "",
153 "clientstack",
154 scene.Name,
155 StatType.Pull,
156 MeasuresOfInterest.AverageChangeOverTime,
157 stat => stat.Value = m_udpServer.UdpSends,
158 StatVerbosity.Debug));
159
160 StatsManager.RegisterStat(
161 new Stat(
162 "OutgoingPacketsResentCount",
163 "Number of packets resent because a client did not acknowledge receipt",
164 "",
165 "",
166 "clientstack",
167 scene.Name,
168 StatType.Pull,
169 MeasuresOfInterest.AverageChangeOverTime,
170 stat => stat.Value = m_udpServer.PacketsResentCount,
171 StatVerbosity.Debug));
172
173 StatsManager.RegisterStat(
174 new Stat(
175 "AverageUDPProcessTime",
176 "Average number of milliseconds taken to process each incoming UDP packet in a sample.",
177 "This is for initial receive processing which is separate from the later client LL packet processing stage.",
178 "ms",
179 "clientstack",
180 scene.Name,
181 StatType.Pull,
182 MeasuresOfInterest.None,
183 stat => stat.Value = m_udpServer.AverageReceiveTicksForLastSamplePeriod,
184// stat =>
185// stat.Value = Math.Round(m_udpServer.AverageReceiveTicksForLastSamplePeriod, 7),
186 StatVerbosity.Debug));
187 }
188
189 public bool HandlesRegion(Location x)
190 {
191 return m_udpServer.HandlesRegion(x);
192 }
193
194 public void Start()
195 {
196 m_udpServer.Start();
197 }
198
199 public void Stop()
200 {
201 m_udpServer.Stop();
202 }
203 }
204
205 /// <summary>
206 /// The LLUDP server for a region. This handles incoming and outgoing
207 /// packets for all UDP connections to the region
208 /// </summary>
209 public class LLUDPServer : OpenSimUDPBase
210 {
211 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
212
213 /// <summary>Maximum transmission unit, or UDP packet size, for the LLUDP protocol</summary>
214 public const int MTU = 1400;
215
216 /// <summary>Number of forced client logouts due to no receipt of packets before timeout.</summary>
217 public int ClientLogoutsDueToNoReceives { get; private set; }
218
219 /// <summary>
220 /// Default packet debug level given to new clients
221 /// </summary>
222 public int DefaultClientPacketDebugLevel { get; set; }
223
224 /// <summary>
225 /// If set then all inbound agent updates are discarded. For debugging purposes.
226 /// discard agent update.
227 /// </summary>
228 public bool DiscardInboundAgentUpdates { get; set; }
229
230 /// <summary>The measured resolution of Environment.TickCount</summary>
231 public readonly float TickCountResolution;
232
233 /// <summary>Number of prim updates to put on the queue each time the
234 /// OnQueueEmpty event is triggered for updates</summary>
235 public readonly int PrimUpdatesPerCallback;
236
237 /// <summary>Number of texture packets to put on the queue each time the
238 /// OnQueueEmpty event is triggered for textures</summary>
239 public readonly int TextureSendLimit;
240
241 /// <summary>Handlers for incoming packets</summary>
242 //PacketEventDictionary packetEvents = new PacketEventDictionary();
243 /// <summary>Incoming packets that are awaiting handling</summary>
244 private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>();
245
246 /// <summary>Bandwidth throttle for this UDP server</summary>
247 public TokenBucket Throttle { get; private set; }
248
249 /// <summary>Per client throttle rates enforced by this server</summary>
250 /// <remarks>
251 /// If the total rate is non-zero, then this is the maximum total throttle setting that any client can ever have.
252 /// The other rates (resend, asset, etc.) are the defaults for a new client and can be changed (and usually
253 /// do get changed immediately). They do not need to sum to the total.
254 /// </remarks>
255 public ThrottleRates ThrottleRates { get; private set; }
256
257 /// <summary>Manages authentication for agent circuits</summary>
258 private AgentCircuitManager m_circuitManager;
259
260 /// <summary>Reference to the scene this UDP server is attached to</summary>
261 public Scene Scene { get; private set; }
262
263 /// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary>
264 private Location m_location;
265
266 /// <summary>The size of the receive buffer for the UDP socket. This value
267 /// is passed up to the operating system and used in the system networking
268 /// stack. Use zero to leave this value as the default</summary>
269 private int m_recvBufferSize;
270
271 /// <summary>Flag to process packets asynchronously or synchronously</summary>
272 private bool m_asyncPacketHandling;
273
274 /// <summary>Tracks whether or not a packet was sent each round so we know
275 /// whether or not to sleep</summary>
276 private bool m_packetSent;
277
278 /// <summary>Environment.TickCount of the last time that packet stats were reported to the scene</summary>
279 private int m_elapsedMSSinceLastStatReport = 0;
280
281 /// <summary>Environment.TickCount of the last time the outgoing packet handler executed</summary>
282 private int m_tickLastOutgoingPacketHandler;
283
284 /// <summary>Keeps track of the number of elapsed milliseconds since the last time the outgoing packet handler looped</summary>
285 private int m_elapsedMSOutgoingPacketHandler;
286
287 /// <summary>Keeps track of the number of 100 millisecond periods elapsed in the outgoing packet handler executed</summary>
288 private int m_elapsed100MSOutgoingPacketHandler;
289
290 /// <summary>Keeps track of the number of 500 millisecond periods elapsed in the outgoing packet handler executed</summary>
291 private int m_elapsed500MSOutgoingPacketHandler;
292
293 /// <summary>Flag to signal when clients should check for resends</summary>
294 protected bool m_resendUnacked;
295
296 /// <summary>Flag to signal when clients should send ACKs</summary>
297 protected bool m_sendAcks;
298
299 /// <summary>Flag to signal when clients should send pings</summary>
300 protected bool m_sendPing;
301
302 /// <summary>
303 /// Event used to signal when queued packets are available for sending.
304 /// </summary>
305 /// <remarks>
306 /// This allows the outbound loop to only operate when there is data to send rather than continuously polling.
307 /// Some data is sent immediately and not queued. That data would not trigger this event.
308 /// </remarks>
309 private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false);
310
311 private Pool<IncomingPacket> m_incomingPacketPool;
312
313 /// <summary>
314 /// Stat for number of packets in the main pool awaiting use.
315 /// </summary>
316 private Stat m_poolCountStat;
317
318 /// <summary>
319 /// Stat for number of packets in the inbound packet pool awaiting use.
320 /// </summary>
321 private Stat m_incomingPacketPoolStat;
322
323 private int m_defaultRTO = 0;
324 private int m_maxRTO = 0;
325 private int m_ackTimeout = 0;
326 private int m_pausedAckTimeout = 0;
327 private bool m_disableFacelights = false;
328
329 public Socket Server { get { return null; } }
330
331 /// <summary>
332 /// Record how many packets have been resent
333 /// </summary>
334 internal int PacketsResentCount { get; set; }
335
336 /// <summary>
337 /// Record how many packets have been sent
338 /// </summary>
339 internal int PacketsSentCount { get; set; }
340
341 /// <summary>
342 /// Record how many incoming packets are indicated as resends by clients.
343 /// </summary>
344 internal int IncomingPacketsResentCount { get; set; }
345
346 /// <summary>
347 /// Record how many inbound packets could not be recognized as LLUDP packets.
348 /// </summary>
349 public int IncomingMalformedPacketCount { get; private set; }
350
351 /// <summary>
352 /// Record how many inbound packets could not be associated with a simulator circuit.
353 /// </summary>
354 public int IncomingOrphanedPacketCount { get; private set; }
355
356 /// <summary>
357 /// Record current outgoing client for monitoring purposes.
358 /// </summary>
359 private IClientAPI m_currentOutgoingClient;
360
361 /// <summary>
362 /// Recording current incoming client for monitoring purposes.
363 /// </summary>
364 private IClientAPI m_currentIncomingClient;
365
366 /// <summary>
367 /// Queue some low priority but potentially high volume async requests so that they don't overwhelm available
368 /// threadpool threads.
369 /// </summary>
370 public JobEngine IpahEngine { get; private set; }
371
372 /// <summary>
373 /// Run queue empty processing within a single persistent thread.
374 /// </summary>
375 /// <remarks>
376 /// This is the alternative to having every
377 /// connection schedule its own job in the threadpool which causes performance problems when there are many
378 /// connections.
379 /// </remarks>
380 public JobEngine OqrEngine { get; private set; }
381
382 public LLUDPServer(
383 IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port,
384 IConfigSource configSource, AgentCircuitManager circuitManager)
385 : base(listenIP, (int)port)
386 {
387 #region Environment.TickCount Measurement
388
389 // Measure the resolution of Environment.TickCount
390 TickCountResolution = 0f;
391 for (int i = 0; i < 5; i++)
392 {
393 int start = Environment.TickCount;
394 int now = start;
395 while (now == start)
396 now = Environment.TickCount;
397 TickCountResolution += (float)(now - start) * 0.2f;
398 }
399 m_log.Info("[LLUDPSERVER]: Average Environment.TickCount resolution: " + TickCountResolution + "ms");
400 TickCountResolution = (float)Math.Ceiling(TickCountResolution);
401
402 #endregion Environment.TickCount Measurement
403
404 m_circuitManager = circuitManager;
405 int sceneThrottleBps = 0;
406 bool usePools = false;
407
408 IConfig config = configSource.Configs["ClientStack.LindenUDP"];
409 if (config != null)
410 {
411 m_asyncPacketHandling = config.GetBoolean("async_packet_handling", true);
412 m_recvBufferSize = config.GetInt("client_socket_rcvbuf_size", 0);
413 sceneThrottleBps = config.GetInt("scene_throttle_max_bps", 0);
414
415 PrimUpdatesPerCallback = config.GetInt("PrimUpdatesPerCallback", 100);
416 TextureSendLimit = config.GetInt("TextureSendLimit", 20);
417
418 m_defaultRTO = config.GetInt("DefaultRTO", 0);
419 m_maxRTO = config.GetInt("MaxRTO", 0);
420 m_disableFacelights = config.GetBoolean("DisableFacelights", false);
421 m_ackTimeout = 1000 * config.GetInt("AckTimeout", 60);
422 m_pausedAckTimeout = 1000 * config.GetInt("PausedAckTimeout", 300);
423 }
424 else
425 {
426 PrimUpdatesPerCallback = 100;
427 TextureSendLimit = 20;
428 m_ackTimeout = 1000 * 60; // 1 minute
429 m_pausedAckTimeout = 1000 * 300; // 5 minutes
430 }
431
432 // FIXME: This actually only needs to be done once since the PacketPool is shared across all servers.
433 // However, there is no harm in temporarily doing it multiple times.
434 IConfig packetConfig = configSource.Configs["PacketPool"];
435 if (packetConfig != null)
436 {
437 PacketPool.Instance.RecyclePackets = packetConfig.GetBoolean("RecyclePackets", true);
438 PacketPool.Instance.RecycleDataBlocks = packetConfig.GetBoolean("RecycleDataBlocks", true);
439 usePools = packetConfig.GetBoolean("RecycleBaseUDPPackets", usePools);
440 }
441
442 #region BinaryStats
443 config = configSource.Configs["Statistics.Binary"];
444 m_shouldCollectStats = false;
445 if (config != null)
446 {
447 m_shouldCollectStats = config.GetBoolean("Enabled", false);
448 binStatsMaxFilesize = TimeSpan.FromSeconds(config.GetInt("packet_headers_period_seconds", 300));
449 binStatsDir = config.GetString("stats_dir", ".");
450 m_aggregatedBWStats = config.GetBoolean("aggregatedBWStats", false);
451 }
452 #endregion BinaryStats
453
454 // FIXME: Can't add info here because don't know scene yet.
455// m_throttle
456// = new TokenBucket(
457// string.Format("server throttle bucket for {0}", Scene.Name), null, sceneThrottleBps);
458
459 Throttle = new TokenBucket("server throttle bucket", null, 0, sceneThrottleBps);
460
461 ThrottleRates = new ThrottleRates(configSource);
462
463 if (usePools)
464 EnablePools();
465 }
466
467 public void Start()
468 {
469 StartInbound();
470 StartOutbound();
471 IpahEngine.Start();
472 OqrEngine.Start();
473
474 m_elapsedMSSinceLastStatReport = Environment.TickCount;
475 }
476
477 public void StartInbound()
478 {
479 m_log.InfoFormat(
480 "[LLUDPSERVER]: Starting inbound packet processing for the LLUDP server in {0} mode with UsePools = {1}",
481 m_asyncPacketHandling ? "asynchronous" : "synchronous", UsePools);
482
483 base.StartInbound(m_recvBufferSize, m_asyncPacketHandling);
484
485 // This thread will process the packets received that are placed on the packetInbox
486 WorkManager.StartThread(
487 IncomingPacketHandler,
488 string.Format("Incoming Packets ({0})", Scene.Name),
489 ThreadPriority.Normal,
490 false,
491 true,
492 GetWatchdogIncomingAlarmData,
493 Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS);
494 }
495
496 public override void StartOutbound()
497 {
498 m_log.Info("[LLUDPSERVER]: Starting outbound packet processing for the LLUDP server");
499
500 base.StartOutbound();
501
502 WorkManager.StartThread(
503 OutgoingPacketHandler,
504 string.Format("Outgoing Packets ({0})", Scene.Name),
505 ThreadPriority.Normal,
506 false,
507 true,
508 GetWatchdogOutgoingAlarmData,
509 Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS);
510 }
511
512 public void Stop()
513 {
514 m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + Scene.Name);
515 base.StopOutbound();
516 base.StopInbound();
517 IpahEngine.Stop();
518 OqrEngine.Stop();
519 }
520
521 public override bool EnablePools()
522 {
523 if (!UsePools)
524 {
525 base.EnablePools();
526
527 m_incomingPacketPool = new Pool<IncomingPacket>(() => new IncomingPacket(), 500);
528
529 return true;
530 }
531
532 return false;
533 }
534
535 public override bool DisablePools()
536 {
537 if (UsePools)
538 {
539 base.DisablePools();
540
541 StatsManager.DeregisterStat(m_incomingPacketPoolStat);
542
543 // We won't null out the pool to avoid a race condition with code that may be in the middle of using it.
544
545 return true;
546 }
547
548 return false;
549 }
550
551 /// <summary>
552 /// This is a seperate method so that it can be called once we have an m_scene to distinguish different scene
553 /// stats.
554 /// </summary>
555 protected internal void EnablePoolStats()
556 {
557 m_poolCountStat
558 = new Stat(
559 "UDPPacketBufferPoolCount",
560 "Objects within the UDPPacketBuffer pool",
561 "The number of objects currently stored within the UDPPacketBuffer pool",
562 "",
563 "clientstack",
564 Scene.Name,
565 StatType.Pull,
566 stat => stat.Value = Pool.Count,
567 StatVerbosity.Debug);
568
569 StatsManager.RegisterStat(m_poolCountStat);
570
571 m_incomingPacketPoolStat
572 = new Stat(
573 "IncomingPacketPoolCount",
574 "Objects within incoming packet pool",
575 "The number of objects currently stored within the incoming packet pool",
576 "",
577 "clientstack",
578 Scene.Name,
579 StatType.Pull,
580 stat => stat.Value = m_incomingPacketPool.Count,
581 StatVerbosity.Debug);
582
583 StatsManager.RegisterStat(m_incomingPacketPoolStat);
584 }
585
586 /// <summary>
587 /// Disables pool stats.
588 /// </summary>
589 protected internal void DisablePoolStats()
590 {
591 StatsManager.DeregisterStat(m_poolCountStat);
592 m_poolCountStat = null;
593
594 StatsManager.DeregisterStat(m_incomingPacketPoolStat);
595 m_incomingPacketPoolStat = null;
596 }
597
598 /// <summary>
599 /// If the outgoing UDP thread times out, then return client that was being processed to help with debugging.
600 /// </summary>
601 /// <returns></returns>
602 private string GetWatchdogIncomingAlarmData()
603 {
604 return string.Format(
605 "Client is {0}",
606 m_currentIncomingClient != null ? m_currentIncomingClient.Name : "none");
607 }
608
609 /// <summary>
610 /// If the outgoing UDP thread times out, then return client that was being processed to help with debugging.
611 /// </summary>
612 /// <returns></returns>
613 private string GetWatchdogOutgoingAlarmData()
614 {
615 return string.Format(
616 "Client is {0}",
617 m_currentOutgoingClient != null ? m_currentOutgoingClient.Name : "none");
618 }
619
620 public void AddScene(IScene scene)
621 {
622 if (Scene != null)
623 {
624 m_log.Error("[LLUDPSERVER]: AddScene() called on an LLUDPServer that already has a scene");
625 return;
626 }
627
628 if (!(scene is Scene))
629 {
630 m_log.Error("[LLUDPSERVER]: AddScene() called with an unrecognized scene type " + scene.GetType());
631 return;
632 }
633
634 Scene = (Scene)scene;
635 m_location = new Location(Scene.RegionInfo.RegionHandle);
636
637 IpahEngine
638 = new JobEngine(
639 string.Format("Incoming Packet Async Handling Engine ({0})", Scene.Name),
640 "INCOMING PACKET ASYNC HANDLING ENGINE");
641
642 OqrEngine
643 = new JobEngine(
644 string.Format("Outgoing Queue Refill Engine ({0})", Scene.Name),
645 "OUTGOING QUEUE REFILL ENGINE");
646
647 StatsManager.RegisterStat(
648 new Stat(
649 "InboxPacketsCount",
650 "Number of LL protocol packets waiting for the second stage of processing after initial receive.",
651 "Number of LL protocol packets waiting for the second stage of processing after initial receive.",
652 "",
653 "clientstack",
654 scene.Name,
655 StatType.Pull,
656 MeasuresOfInterest.AverageChangeOverTime,
657 stat => stat.Value = packetInbox.Count,
658 StatVerbosity.Debug));
659
660 // XXX: These stats are also pool stats but we register them separately since they are currently not
661 // turned on and off by EnablePools()/DisablePools()
662 StatsManager.RegisterStat(
663 new PercentageStat(
664 "PacketsReused",
665 "Packets reused",
666 "Number of packets reused out of all requests to the packet pool",
667 "clientstack",
668 Scene.Name,
669 StatType.Pull,
670 stat =>
671 { PercentageStat pstat = (PercentageStat)stat;
672 pstat.Consequent = PacketPool.Instance.PacketsRequested;
673 pstat.Antecedent = PacketPool.Instance.PacketsReused; },
674 StatVerbosity.Debug));
675
676 StatsManager.RegisterStat(
677 new PercentageStat(
678 "PacketDataBlocksReused",
679 "Packet data blocks reused",
680 "Number of data blocks reused out of all requests to the packet pool",
681 "clientstack",
682 Scene.Name,
683 StatType.Pull,
684 stat =>
685 { PercentageStat pstat = (PercentageStat)stat;
686 pstat.Consequent = PacketPool.Instance.BlocksRequested;
687 pstat.Antecedent = PacketPool.Instance.BlocksReused; },
688 StatVerbosity.Debug));
689
690 StatsManager.RegisterStat(
691 new Stat(
692 "PacketsPoolCount",
693 "Objects within the packet pool",
694 "The number of objects currently stored within the packet pool",
695 "",
696 "clientstack",
697 Scene.Name,
698 StatType.Pull,
699 stat => stat.Value = PacketPool.Instance.PacketsPooled,
700 StatVerbosity.Debug));
701
702 StatsManager.RegisterStat(
703 new Stat(
704 "PacketDataBlocksPoolCount",
705 "Objects within the packet data block pool",
706 "The number of objects currently stored within the packet data block pool",
707 "",
708 "clientstack",
709 Scene.Name,
710 StatType.Pull,
711 stat => stat.Value = PacketPool.Instance.BlocksPooled,
712 StatVerbosity.Debug));
713
714 StatsManager.RegisterStat(
715 new Stat(
716 "OutgoingPacketsQueuedCount",
717 "Packets queued for outgoing send",
718 "Number of queued outgoing packets across all connections",
719 "",
720 "clientstack",
721 Scene.Name,
722 StatType.Pull,
723 MeasuresOfInterest.AverageChangeOverTime,
724 stat => stat.Value = GetTotalQueuedOutgoingPackets(),
725 StatVerbosity.Info));
726
727 StatsManager.RegisterStat(
728 new Stat(
729 "IncomingPacketAsyncRequestsWaiting",
730 "Number of incoming packets waiting for async processing in engine.",
731 "",
732 "",
733 "clientstack",
734 Scene.Name,
735 StatType.Pull,
736 MeasuresOfInterest.None,
737 stat => stat.Value = IpahEngine.JobsWaiting,
738 StatVerbosity.Debug));
739
740 StatsManager.RegisterStat(
741 new Stat(
742 "OQRERequestsWaiting",
743 "Number of outgong queue refill requests waiting for processing.",
744 "",
745 "",
746 "clientstack",
747 Scene.Name,
748 StatType.Pull,
749 MeasuresOfInterest.None,
750 stat => stat.Value = OqrEngine.JobsWaiting,
751 StatVerbosity.Debug));
752
753 // We delay enabling pool stats to AddScene() instead of Initialize() so that we can distinguish pool stats by
754 // scene name
755 if (UsePools)
756 EnablePoolStats();
757
758 LLUDPServerCommands commands = new LLUDPServerCommands(MainConsole.Instance, this);
759 commands.Register();
760 }
761
762 public bool HandlesRegion(Location x)
763 {
764 return x == m_location;
765 }
766
767 public int GetTotalQueuedOutgoingPackets()
768 {
769 int total = 0;
770
771 foreach (ScenePresence sp in Scene.GetScenePresences())
772 {
773 // XXX: Need a better way to determine which IClientAPIs have UDPClients (NPCs do not, for instance).
774 if (sp.ControllingClient is LLClientView)
775 {
776 LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
777 total += udpClient.GetTotalPacketsQueuedCount();
778 }
779 }
780
781 return total;
782 }
783
784// public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting)
785// {
786// // CoarseLocationUpdate and AvatarGroupsReply packets cannot be split in an automated way
787// if ((packet.Type == PacketType.CoarseLocationUpdate || packet.Type == PacketType.AvatarGroupsReply) && allowSplitting)
788// allowSplitting = false;
789//
790// if (allowSplitting && packet.HasVariableBlocks)
791// {
792// byte[][] datas = packet.ToBytesMultiple();
793// int packetCount = datas.Length;
794//
795// if (packetCount < 1)
796// m_log.Error("[LLUDPSERVER]: Failed to split " + packet.Type + " with estimated length " + packet.Length);
797//
798// for (int i = 0; i < packetCount; i++)
799// {
800// byte[] data = datas[i];
801// m_scene.ForEachClient(
802// delegate(IClientAPI client)
803// {
804// if (client is LLClientView)
805// SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null);
806// }
807// );
808// }
809// }
810// else
811// {
812// byte[] data = packet.ToBytes();
813// m_scene.ForEachClient(
814// delegate(IClientAPI client)
815// {
816// if (client is LLClientView)
817// SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null);
818// }
819// );
820// }
821// }
822
823 /// <summary>
824 /// Start the process of sending a packet to the client.
825 /// </summary>
826 /// <param name="udpClient"></param>
827 /// <param name="packet"></param>
828 /// <param name="category"></param>
829 /// <param name="allowSplitting"></param>
830 /// <param name="method">
831 /// The method to call if the packet is not acked by the client. If null, then a standard
832 /// resend of the packet is done.
833 /// </param>
834 public virtual void SendPacket(
835 LLUDPClient udpClient, Packet packet, ThrottleOutPacketType category, bool allowSplitting, UnackedPacketMethod method)
836 {
837 // CoarseLocationUpdate packets cannot be split in an automated way
838 if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting)
839 allowSplitting = false;
840
841 bool packetQueued = false;
842
843 if (allowSplitting && packet.HasVariableBlocks)
844 {
845 byte[][] datas = packet.ToBytesMultiple();
846 int packetCount = datas.Length;
847
848 if (packetCount < 1)
849 m_log.Error("[LLUDPSERVER]: Failed to split " + packet.Type + " with estimated length " + packet.Length);
850
851 for (int i = 0; i < packetCount; i++)
852 {
853 byte[] data = datas[i];
854 if (!SendPacketData(udpClient, data, packet.Type, category, method))
855 packetQueued = true;
856 }
857 }
858 else
859 {
860 byte[] data = packet.ToBytes();
861 if (!SendPacketData(udpClient, data, packet.Type, category, method))
862 packetQueued = true;
863 }
864
865 PacketPool.Instance.ReturnPacket(packet);
866
867 if (packetQueued)
868 m_dataPresentEvent.Set();
869 }
870
871 /// <summary>
872 /// Start the process of sending a packet to the client.
873 /// </summary>
874 /// <param name="udpClient"></param>
875 /// <param name="data"></param>
876 /// <param name="type"></param>
877 /// <param name="category"></param>
878 /// <param name="method">
879 /// The method to call if the packet is not acked by the client. If null, then a standard
880 /// resend of the packet is done.
881 /// </param>
882 /// <returns>true if the data was sent immediately, false if it was queued for sending</returns>
883 public bool SendPacketData(
884 LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category, UnackedPacketMethod method)
885 {
886 int dataLength = data.Length;
887 bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0;
888 bool doCopy = true;
889
890 // Frequency analysis of outgoing packet sizes shows a large clump of packets at each end of the spectrum.
891 // The vast majority of packets are less than 200 bytes, although due to asset transfers and packet splitting
892 // there are a decent number of packets in the 1000-1140 byte range. We allocate one of two sizes of data here
893 // to accomodate for both common scenarios and provide ample room for ACK appending in both
894 int bufferSize = (dataLength > 180) ? LLUDPServer.MTU : 200;
895
896 UDPPacketBuffer buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize);
897
898 // Zerocode if needed
899 if (doZerocode)
900 {
901 try
902 {
903 dataLength = Helpers.ZeroEncode(data, dataLength, buffer.Data);
904 doCopy = false;
905 }
906 catch (IndexOutOfRangeException)
907 {
908 // The packet grew larger than the bufferSize while zerocoding.
909 // Remove the MSG_ZEROCODED flag and send the unencoded data
910 // instead
911 m_log.Debug("[LLUDPSERVER]: Packet exceeded buffer size during zerocoding for " + type + ". DataLength=" + dataLength +
912 " and BufferLength=" + buffer.Data.Length + ". Removing MSG_ZEROCODED flag");
913 data[0] = (byte)(data[0] & ~Helpers.MSG_ZEROCODED);
914 }
915 }
916
917 // If the packet data wasn't already copied during zerocoding, copy it now
918 if (doCopy)
919 {
920 if (dataLength <= buffer.Data.Length)
921 {
922 Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength);
923 }
924 else
925 {
926 bufferSize = dataLength;
927 buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize);
928
929 // m_log.Error("[LLUDPSERVER]: Packet exceeded buffer size! This could be an indication of packet assembly not obeying the MTU. Type=" +
930 // type + ", DataLength=" + dataLength + ", BufferLength=" + buffer.Data.Length + ". Dropping packet");
931 Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength);
932 }
933 }
934
935 buffer.DataLength = dataLength;
936
937 #region Queue or Send
938
939 OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null);
940
941 // If we were not provided a method for handling unacked, use the UDPServer default method
942 if ((outgoingPacket.Buffer.Data[0] & Helpers.MSG_RELIABLE) != 0)
943 outgoingPacket.UnackedMethod = ((method == null) ? delegate(OutgoingPacket oPacket) { ResendUnacked(oPacket); } : method);
944
945 // If a Linden Lab 1.23.5 client receives an update packet after a kill packet for an object, it will
946 // continue to display the deleted object until relog. Therefore, we need to always queue a kill object
947 // packet so that it isn't sent before a queued update packet.
948 bool forceQueue = (type == PacketType.KillObject);
949
950// if (type == PacketType.ImprovedTerseObjectUpdate)
951// {
952// m_log.DebugFormat("Direct send ITOU to {0} in {1}", udpClient.AgentID, Scene.Name);
953// SendPacketFinal(outgoingPacket);
954// return false;
955// }
956// else
957// {
958 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, forceQueue))
959 {
960 SendPacketFinal(outgoingPacket);
961 return true;
962 }
963 else
964 {
965 return false;
966 }
967// }
968
969 #endregion Queue or Send
970 }
971
972 public void SendAcks(LLUDPClient udpClient)
973 {
974 uint ack;
975
976 if (udpClient.PendingAcks.Dequeue(out ack))
977 {
978 List<PacketAckPacket.PacketsBlock> blocks = new List<PacketAckPacket.PacketsBlock>();
979 PacketAckPacket.PacketsBlock block = new PacketAckPacket.PacketsBlock();
980 block.ID = ack;
981 blocks.Add(block);
982
983 while (udpClient.PendingAcks.Dequeue(out ack))
984 {
985 block = new PacketAckPacket.PacketsBlock();
986 block.ID = ack;
987 blocks.Add(block);
988 }
989
990 PacketAckPacket packet = new PacketAckPacket();
991 packet.Header.Reliable = false;
992 packet.Packets = blocks.ToArray();
993
994 SendPacket(udpClient, packet, ThrottleOutPacketType.Unknown, true, null);
995 }
996 }
997
998 public void SendPing(LLUDPClient udpClient)
999 {
1000 StartPingCheckPacket pc = (StartPingCheckPacket)PacketPool.Instance.GetPacket(PacketType.StartPingCheck);
1001 pc.Header.Reliable = false;
1002
1003 pc.PingID.PingID = (byte)udpClient.CurrentPingSequence++;
1004 // We *could* get OldestUnacked, but it would hurt performance and not provide any benefit
1005 pc.PingID.OldestUnacked = 0;
1006
1007 SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false, null);
1008 }
1009
1010 public void CompletePing(LLUDPClient udpClient, byte pingID)
1011 {
1012 CompletePingCheckPacket completePing = new CompletePingCheckPacket();
1013 completePing.PingID.PingID = pingID;
1014 SendPacket(udpClient, completePing, ThrottleOutPacketType.Unknown, false, null);
1015 }
1016
1017 public void HandleUnacked(LLClientView client)
1018 {
1019 LLUDPClient udpClient = client.UDPClient;
1020
1021 if (!udpClient.IsConnected)
1022 return;
1023
1024 // Disconnect an agent if no packets are received for some time
1025 int timeoutTicks = m_ackTimeout;
1026
1027 // Allow more slack if the client is "paused" eg file upload dialogue is open
1028 // Some sort of limit is needed in case the client crashes, loses its network connection
1029 // or some other disaster prevents it from sendung the AgentResume
1030 if (udpClient.IsPaused)
1031 timeoutTicks = m_pausedAckTimeout;
1032
1033 if (client.IsActive &&
1034 (Environment.TickCount & Int32.MaxValue) - udpClient.TickLastPacketReceived > timeoutTicks)
1035 {
1036 // We must set IsActive synchronously so that we can stop the packet loop reinvoking this method, even
1037 // though it's set later on by LLClientView.Close()
1038 client.IsActive = false;
1039
1040 // Fire this out on a different thread so that we don't hold up outgoing packet processing for
1041 // everybody else if this is being called due to an ack timeout.
1042 // This is the same as processing as the async process of a logout request.
1043 Util.FireAndForget(
1044 o => DeactivateClientDueToTimeout(client, timeoutTicks), null, "LLUDPServer.DeactivateClientDueToTimeout");
1045
1046 return;
1047 }
1048
1049 // Get a list of all of the packets that have been sitting unacked longer than udpClient.RTO
1050 List<OutgoingPacket> expiredPackets = udpClient.NeedAcks.GetExpiredPackets(udpClient.RTO);
1051
1052 if (expiredPackets != null)
1053 {
1054 //m_log.Debug("[LLUDPSERVER]: Handling " + expiredPackets.Count + " packets to " + udpClient.AgentID + ", RTO=" + udpClient.RTO);
1055 // Exponential backoff of the retransmission timeout
1056 udpClient.BackoffRTO();
1057 for (int i = 0; i < expiredPackets.Count; ++i)
1058 expiredPackets[i].UnackedMethod(expiredPackets[i]);
1059 }
1060 }
1061
1062 public void ResendUnacked(OutgoingPacket outgoingPacket)
1063 {
1064 //m_log.DebugFormat("[LLUDPSERVER]: Resending packet #{0} (attempt {1}), {2}ms have passed",
1065 // outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount);
1066
1067 // Set the resent flag
1068 outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT);
1069 outgoingPacket.Category = ThrottleOutPacketType.Resend;
1070
1071 // Bump up the resend count on this packet
1072 Interlocked.Increment(ref outgoingPacket.ResendCount);
1073
1074 // Requeue or resend the packet
1075 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, false))
1076 SendPacketFinal(outgoingPacket);
1077 }
1078
1079 public void Flush(LLUDPClient udpClient)
1080 {
1081 // FIXME: Implement?
1082 }
1083
1084 /// <summary>
1085 /// Actually send a packet to a client.
1086 /// </summary>
1087 /// <param name="outgoingPacket"></param>
1088 internal void SendPacketFinal(OutgoingPacket outgoingPacket)
1089 {
1090 UDPPacketBuffer buffer = outgoingPacket.Buffer;
1091 byte flags = buffer.Data[0];
1092 bool isResend = (flags & Helpers.MSG_RESENT) != 0;
1093 bool isReliable = (flags & Helpers.MSG_RELIABLE) != 0;
1094 bool isZerocoded = (flags & Helpers.MSG_ZEROCODED) != 0;
1095 LLUDPClient udpClient = outgoingPacket.Client;
1096
1097 if (!udpClient.IsConnected)
1098 return;
1099
1100 #region ACK Appending
1101
1102 int dataLength = buffer.DataLength;
1103
1104 // NOTE: I'm seeing problems with some viewers when ACKs are appended to zerocoded packets so I've disabled that here
1105 if (!isZerocoded)
1106 {
1107 // Keep appending ACKs until there is no room left in the buffer or there are
1108 // no more ACKs to append
1109 uint ackCount = 0;
1110 uint ack;
1111 while (dataLength + 5 < buffer.Data.Length && udpClient.PendingAcks.Dequeue(out ack))
1112 {
1113 Utils.UIntToBytesBig(ack, buffer.Data, dataLength);
1114 dataLength += 4;
1115 ++ackCount;
1116 }
1117
1118 if (ackCount > 0)
1119 {
1120 // Set the last byte of the packet equal to the number of appended ACKs
1121 buffer.Data[dataLength++] = (byte)ackCount;
1122 // Set the appended ACKs flag on this packet
1123 buffer.Data[0] = (byte)(buffer.Data[0] | Helpers.MSG_APPENDED_ACKS);
1124 }
1125 }
1126
1127 buffer.DataLength = dataLength;
1128
1129 #endregion ACK Appending
1130
1131 #region Sequence Number Assignment
1132
1133 if (!isResend)
1134 {
1135 // Not a resend, assign a new sequence number
1136 uint sequenceNumber = (uint)Interlocked.Increment(ref udpClient.CurrentSequence);
1137 Utils.UIntToBytesBig(sequenceNumber, buffer.Data, 1);
1138 outgoingPacket.SequenceNumber = sequenceNumber;
1139
1140 if (udpClient.ProcessUnackedSends && isReliable)
1141 {
1142 // Add this packet to the list of ACK responses we are waiting on from the server
1143 udpClient.NeedAcks.Add(outgoingPacket);
1144 }
1145 }
1146 else
1147 {
1148 Interlocked.Increment(ref udpClient.PacketsResent);
1149
1150 // We're not going to worry about interlock yet since its not currently critical that this total count
1151 // is 100% correct
1152 PacketsResentCount++;
1153 }
1154
1155 #endregion Sequence Number Assignment
1156
1157 // Stats tracking
1158 Interlocked.Increment(ref udpClient.PacketsSent);
1159
1160 // We're not going to worry about interlock yet since its not currently critical that this total count
1161 // is 100% correct
1162 PacketsSentCount++;
1163
1164 if (udpClient.DebugDataOutLevel > 0)
1165 m_log.DebugFormat(
1166 "[LLUDPSERVER]: Sending packet #{0} (rel: {1}, res: {2}) to {3} from {4}",
1167 outgoingPacket.SequenceNumber, isReliable, isResend, udpClient.AgentID, Scene.Name);
1168
1169 // Put the UDP payload on the wire
1170 AsyncBeginSend(buffer);
1171
1172 // Keep track of when this packet was sent out (right now)
1173 outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue;
1174 }
1175
1176 private void RecordMalformedInboundPacket(IPEndPoint endPoint)
1177 {
1178// if (m_malformedCount < 100)
1179// m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString());
1180
1181 IncomingMalformedPacketCount++;
1182
1183 if ((IncomingMalformedPacketCount % 10000) == 0)
1184 m_log.WarnFormat(
1185 "[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack. Last was from {1}",
1186 IncomingMalformedPacketCount, endPoint);
1187 }
1188
1189 public override void PacketReceived(UDPPacketBuffer buffer)
1190 {
1191 // Debugging/Profiling
1192 //try { Thread.CurrentThread.Name = "PacketReceived (" + m_scene.RegionInfo.RegionName + ")"; }
1193 //catch (Exception) { }
1194// m_log.DebugFormat(
1195// "[LLUDPSERVER]: Packet received from {0} in {1}", buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
1196
1197 LLUDPClient udpClient = null;
1198 Packet packet = null;
1199 int packetEnd = buffer.DataLength - 1;
1200 IPEndPoint endPoint = (IPEndPoint)buffer.RemoteEndPoint;
1201
1202 #region Decoding
1203
1204 if (buffer.DataLength < 7)
1205 {
1206// m_log.WarnFormat(
1207// "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}",
1208// buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
1209
1210 RecordMalformedInboundPacket(endPoint);
1211
1212 return; // Drop undersized packet
1213 }
1214
1215 int headerLen = 7;
1216 if (buffer.Data[6] == 0xFF)
1217 {
1218 if (buffer.Data[7] == 0xFF)
1219 headerLen = 10;
1220 else
1221 headerLen = 8;
1222 }
1223
1224 if (buffer.DataLength < headerLen)
1225 {
1226// m_log.WarnFormat(
1227// "[LLUDPSERVER]: Dropping packet with malformed header received from {0} in {1}",
1228// buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
1229
1230 RecordMalformedInboundPacket(endPoint);
1231
1232 return; // Malformed header
1233 }
1234
1235 try
1236 {
1237// packet = Packet.BuildPacket(buffer.Data, ref packetEnd,
1238// // Only allocate a buffer for zerodecoding if the packet is zerocoded
1239// ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
1240 // If OpenSimUDPBase.UsePool == true (which is currently separate from the PacketPool) then we
1241 // assume that packet construction does not retain a reference to byte[] buffer.Data (instead, all
1242 // bytes are copied out).
1243 packet = PacketPool.Instance.GetPacket(buffer.Data, ref packetEnd,
1244 // Only allocate a buffer for zerodecoding if the packet is zerocoded
1245 ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
1246 }
1247 catch (Exception e)
1248 {
1249 if (IncomingMalformedPacketCount < 100)
1250 m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString());
1251 }
1252
1253 // Fail-safe check
1254 if (packet == null)
1255 {
1256 if (IncomingMalformedPacketCount < 100)
1257 {
1258 m_log.WarnFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}, data {2}:",
1259 buffer.DataLength, buffer.RemoteEndPoint, Utils.BytesToHexString(buffer.Data, buffer.DataLength, null));
1260 }
1261
1262 RecordMalformedInboundPacket(endPoint);
1263
1264 return;
1265 }
1266
1267 #endregion Decoding
1268
1269 #region Packet to Client Mapping
1270
1271 // UseCircuitCode handling
1272 if (packet.Type == PacketType.UseCircuitCode)
1273 {
1274 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the
1275 // buffer.
1276 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
1277
1278 Util.FireAndForget(HandleUseCircuitCode, array, "LLUDPServer.HandleUseCircuitCode");
1279
1280 return;
1281 }
1282 else if (packet.Type == PacketType.CompleteAgentMovement)
1283 {
1284 // Send ack straight away to let the viewer know that we got it.
1285 SendAckImmediate(endPoint, packet.Header.Sequence);
1286
1287 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the
1288 // buffer.
1289 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
1290
1291 Util.FireAndForget(
1292 HandleCompleteMovementIntoRegion, array, "LLUDPServer.HandleCompleteMovementIntoRegion");
1293
1294 return;
1295 }
1296
1297 // Determine which agent this packet came from
1298 IClientAPI client;
1299 if (!Scene.TryGetClient(endPoint, out client) || !(client is LLClientView))
1300 {
1301 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName);
1302
1303 IncomingOrphanedPacketCount++;
1304
1305 if ((IncomingOrphanedPacketCount % 10000) == 0)
1306 m_log.WarnFormat(
1307 "[LLUDPSERVER]: Received {0} orphaned packets so far. Last was from {1}",
1308 IncomingOrphanedPacketCount, endPoint);
1309
1310 return;
1311 }
1312
1313 udpClient = ((LLClientView)client).UDPClient;
1314
1315 if (!udpClient.IsConnected)
1316 return;
1317
1318 #endregion Packet to Client Mapping
1319
1320 // Stats tracking
1321 Interlocked.Increment(ref udpClient.PacketsReceived);
1322
1323 int now = Environment.TickCount & Int32.MaxValue;
1324 udpClient.TickLastPacketReceived = now;
1325
1326 #region ACK Receiving
1327
1328 if (udpClient.ProcessUnackedSends)
1329 {
1330 // Handle appended ACKs
1331 if (packet.Header.AppendedAcks && packet.Header.AckList != null)
1332 {
1333 // m_log.DebugFormat(
1334 // "[LLUDPSERVER]: Handling {0} appended acks from {1} in {2}",
1335 // packet.Header.AckList.Length, client.Name, m_scene.Name);
1336
1337 for (int i = 0; i < packet.Header.AckList.Length; i++)
1338 udpClient.NeedAcks.Acknowledge(packet.Header.AckList[i], now, packet.Header.Resent);
1339 }
1340
1341 // Handle PacketAck packets
1342 if (packet.Type == PacketType.PacketAck)
1343 {
1344 PacketAckPacket ackPacket = (PacketAckPacket)packet;
1345
1346 // m_log.DebugFormat(
1347 // "[LLUDPSERVER]: Handling {0} packet acks for {1} in {2}",
1348 // ackPacket.Packets.Length, client.Name, m_scene.Name);
1349
1350 for (int i = 0; i < ackPacket.Packets.Length; i++)
1351 udpClient.NeedAcks.Acknowledge(ackPacket.Packets[i].ID, now, packet.Header.Resent);
1352
1353 // We don't need to do anything else with PacketAck packets
1354 return;
1355 }
1356 }
1357 else if (packet.Type == PacketType.PacketAck)
1358 {
1359 return;
1360 }
1361
1362 #endregion ACK Receiving
1363
1364 #region ACK Sending
1365
1366 if (packet.Header.Reliable)
1367 {
1368// m_log.DebugFormat(
1369// "[LLUDPSERVER]: Adding ack request for {0} {1} from {2} in {3}",
1370// packet.Type, packet.Header.Sequence, client.Name, m_scene.Name);
1371
1372 udpClient.PendingAcks.Enqueue(packet.Header.Sequence);
1373
1374 // This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out,
1375 // add the current received bytes to it, test if 2*MTU bytes have been sent, if so remove
1376 // 2*MTU bytes from the value and send ACKs, and finally add the local value back to
1377 // client.BytesSinceLastACK. Lockless thread safety
1378 int bytesSinceLastACK = Interlocked.Exchange(ref udpClient.BytesSinceLastACK, 0);
1379 bytesSinceLastACK += buffer.DataLength;
1380 if (bytesSinceLastACK > LLUDPServer.MTU * 2)
1381 {
1382 bytesSinceLastACK -= LLUDPServer.MTU * 2;
1383 SendAcks(udpClient);
1384 }
1385 Interlocked.Add(ref udpClient.BytesSinceLastACK, bytesSinceLastACK);
1386 }
1387
1388 #endregion ACK Sending
1389
1390 #region Incoming Packet Accounting
1391
1392 // We're not going to worry about interlock yet since its not currently critical that this total count
1393 // is 100% correct
1394 if (packet.Header.Resent)
1395 IncomingPacketsResentCount++;
1396
1397 // Check the archive of received reliable packet IDs to see whether we already received this packet
1398 if (packet.Header.Reliable && !udpClient.PacketArchive.TryEnqueue(packet.Header.Sequence))
1399 {
1400 if (packet.Header.Resent)
1401 m_log.DebugFormat(
1402 "[LLUDPSERVER]: Received a resend of already processed packet #{0}, type {1} from {2}",
1403 packet.Header.Sequence, packet.Type, client.Name);
1404 else
1405 m_log.WarnFormat(
1406 "[LLUDPSERVER]: Received a duplicate (not marked as resend) of packet #{0}, type {1} from {2}",
1407 packet.Header.Sequence, packet.Type, client.Name);
1408
1409 // Avoid firing a callback twice for the same packet
1410 return;
1411 }
1412
1413 #endregion Incoming Packet Accounting
1414
1415 #region BinaryStats
1416 LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length);
1417 #endregion BinaryStats
1418
1419 if (packet.Type == PacketType.AgentUpdate)
1420 {
1421 if (DiscardInboundAgentUpdates)
1422 return;
1423
1424 ((LLClientView)client).TotalAgentUpdates++;
1425
1426 AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
1427
1428 LLClientView llClient = client as LLClientView;
1429 if (agentUpdate.AgentData.SessionID != client.SessionId
1430 || agentUpdate.AgentData.AgentID != client.AgentId
1431 || !(llClient == null || llClient.CheckAgentUpdateSignificance(agentUpdate.AgentData)) )
1432 {
1433 PacketPool.Instance.ReturnPacket(packet);
1434 return;
1435 }
1436 }
1437
1438 #region Ping Check Handling
1439
1440 if (packet.Type == PacketType.StartPingCheck)
1441 {
1442// m_log.DebugFormat("[LLUDPSERVER]: Handling ping from {0} in {1}", client.Name, m_scene.Name);
1443
1444 // We don't need to do anything else with ping checks
1445 StartPingCheckPacket startPing = (StartPingCheckPacket)packet;
1446 CompletePing(udpClient, startPing.PingID.PingID);
1447
1448 if ((Environment.TickCount - m_elapsedMSSinceLastStatReport) >= 3000)
1449 {
1450 udpClient.SendPacketStats();
1451 m_elapsedMSSinceLastStatReport = Environment.TickCount;
1452 }
1453 return;
1454 }
1455 else if (packet.Type == PacketType.CompletePingCheck)
1456 {
1457 // We don't currently track client ping times
1458 return;
1459 }
1460
1461 #endregion Ping Check Handling
1462
1463 IncomingPacket incomingPacket;
1464
1465 // Inbox insertion
1466 if (UsePools)
1467 {
1468 incomingPacket = m_incomingPacketPool.GetObject();
1469 incomingPacket.Client = (LLClientView)client;
1470 incomingPacket.Packet = packet;
1471 }
1472 else
1473 {
1474 incomingPacket = new IncomingPacket((LLClientView)client, packet);
1475 }
1476
1477 packetInbox.Enqueue(incomingPacket);
1478 }
1479
1480 #region BinaryStats
1481
1482 public class PacketLogger
1483 {
1484 public DateTime StartTime;
1485 public string Path = null;
1486 public System.IO.BinaryWriter Log = null;
1487 }
1488
1489 public static PacketLogger PacketLog;
1490
1491 protected static bool m_shouldCollectStats = false;
1492 // Number of seconds to log for
1493 static TimeSpan binStatsMaxFilesize = TimeSpan.FromSeconds(300);
1494 static object binStatsLogLock = new object();
1495 static string binStatsDir = "";
1496
1497 //for Aggregated In/Out BW logging
1498 static bool m_aggregatedBWStats = false;
1499 static long m_aggregatedBytesIn = 0;
1500 static long m_aggregatedByestOut = 0;
1501 static object aggBWStatsLock = new object();
1502
1503 public static long AggregatedLLUDPBytesIn
1504 {
1505 get { return m_aggregatedBytesIn; }
1506 }
1507 public static long AggregatedLLUDPBytesOut
1508 {
1509 get {return m_aggregatedByestOut;}
1510 }
1511
1512 public static void LogPacketHeader(bool incoming, uint circuit, byte flags, PacketType packetType, ushort size)
1513 {
1514 if (m_aggregatedBWStats)
1515 {
1516 lock (aggBWStatsLock)
1517 {
1518 if (incoming)
1519 m_aggregatedBytesIn += size;
1520 else
1521 m_aggregatedByestOut += size;
1522 }
1523 }
1524
1525 if (!m_shouldCollectStats) return;
1526
1527 // Binary logging format is TTTTTTTTCCCCFPPPSS, T=Time, C=Circuit, F=Flags, P=PacketType, S=size
1528
1529 // Put the incoming bit into the least significant bit of the flags byte
1530 if (incoming)
1531 flags |= 0x01;
1532 else
1533 flags &= 0xFE;
1534
1535 // Put the flags byte into the most significant bits of the type integer
1536 uint type = (uint)packetType;
1537 type |= (uint)flags << 24;
1538
1539 // m_log.Debug("1 LogPacketHeader(): Outside lock");
1540 lock (binStatsLogLock)
1541 {
1542 DateTime now = DateTime.Now;
1543
1544 // m_log.Debug("2 LogPacketHeader(): Inside lock. now is " + now.Ticks);
1545 try
1546 {
1547 if (PacketLog == null || (now > PacketLog.StartTime + binStatsMaxFilesize))
1548 {
1549 if (PacketLog != null && PacketLog.Log != null)
1550 {
1551 PacketLog.Log.Close();
1552 }
1553
1554 // First log file or time has expired, start writing to a new log file
1555 PacketLog = new PacketLogger();
1556 PacketLog.StartTime = now;
1557 PacketLog.Path = (binStatsDir.Length > 0 ? binStatsDir + System.IO.Path.DirectorySeparatorChar.ToString() : "")
1558 + String.Format("packets-{0}.log", now.ToString("yyyyMMddHHmmss"));
1559 PacketLog.Log = new BinaryWriter(File.Open(PacketLog.Path, FileMode.Append, FileAccess.Write));
1560 }
1561
1562 // Serialize the data
1563 byte[] output = new byte[18];
1564 Buffer.BlockCopy(BitConverter.GetBytes(now.Ticks), 0, output, 0, 8);
1565 Buffer.BlockCopy(BitConverter.GetBytes(circuit), 0, output, 8, 4);
1566 Buffer.BlockCopy(BitConverter.GetBytes(type), 0, output, 12, 4);
1567 Buffer.BlockCopy(BitConverter.GetBytes(size), 0, output, 16, 2);
1568
1569 // Write the serialized data to disk
1570 if (PacketLog != null && PacketLog.Log != null)
1571 PacketLog.Log.Write(output);
1572 }
1573 catch (Exception ex)
1574 {
1575 m_log.Error("Packet statistics gathering failed: " + ex.Message, ex);
1576 if (PacketLog.Log != null)
1577 {
1578 PacketLog.Log.Close();
1579 }
1580 PacketLog = null;
1581 }
1582 }
1583 }
1584
1585 #endregion BinaryStats
1586
1587 private void HandleUseCircuitCode(object o)
1588 {
1589 IPEndPoint endPoint = null;
1590 IClientAPI client = null;
1591
1592 try
1593 {
1594 // DateTime startTime = DateTime.Now;
1595 object[] array = (object[])o;
1596 endPoint = (IPEndPoint)array[0];
1597 UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1];
1598
1599 m_log.DebugFormat(
1600 "[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} to {1} from IP {2}",
1601 uccp.CircuitCode.Code, Scene.RegionInfo.RegionName, endPoint);
1602
1603 AuthenticateResponse sessionInfo;
1604 if (IsClientAuthorized(uccp, out sessionInfo))
1605 {
1606 // Begin the process of adding the client to the simulator
1607 client
1608 = AddClient(
1609 uccp.CircuitCode.Code,
1610 uccp.CircuitCode.ID,
1611 uccp.CircuitCode.SessionID,
1612 endPoint,
1613 sessionInfo);
1614
1615 // Send ack straight away to let the viewer know that the connection is active.
1616 // The client will be null if it already exists (e.g. if on a region crossing the client sends a use
1617 // circuit code to the existing child agent. This is not particularly obvious.
1618 SendAckImmediate(endPoint, uccp.Header.Sequence);
1619
1620 // We only want to send initial data to new clients, not ones which are being converted from child to root.
1621 if (client != null)
1622 {
1623 AgentCircuitData aCircuit = Scene.AuthenticateHandler.GetAgentCircuitData(uccp.CircuitCode.Code);
1624 bool tp = (aCircuit.teleportFlags > 0);
1625 // Let's delay this for TP agents, otherwise the viewer doesn't know where to get resources from
1626 if (!tp && !client.SceneAgent.SentInitialDataToClient)
1627 client.SceneAgent.SendInitialDataToClient();
1628 }
1629 }
1630 else
1631 {
1632 // Don't create clients for unauthorized requesters.
1633 m_log.WarnFormat(
1634 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}",
1635 uccp.CircuitCode.ID, Scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint);
1636 }
1637
1638 // m_log.DebugFormat(
1639 // "[LLUDPSERVER]: Handling UseCircuitCode request from {0} took {1}ms",
1640 // buffer.RemoteEndPoint, (DateTime.Now - startTime).Milliseconds);
1641
1642 }
1643 catch (Exception e)
1644 {
1645 m_log.ErrorFormat(
1646 "[LLUDPSERVER]: UseCircuitCode handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}",
1647 endPoint != null ? endPoint.ToString() : "n/a",
1648 client != null ? client.Name : "unknown",
1649 client != null ? client.AgentId.ToString() : "unknown",
1650 e.Message,
1651 e.StackTrace);
1652 }
1653 }
1654
1655 private void HandleCompleteMovementIntoRegion(object o)
1656 {
1657 IPEndPoint endPoint = null;
1658 IClientAPI client = null;
1659
1660 try
1661 {
1662 object[] array = (object[])o;
1663 endPoint = (IPEndPoint)array[0];
1664 CompleteAgentMovementPacket packet = (CompleteAgentMovementPacket)array[1];
1665
1666 m_log.DebugFormat(
1667 "[LLUDPSERVER]: Handling CompleteAgentMovement request from {0} in {1}", endPoint, Scene.Name);
1668
1669 // Determine which agent this packet came from
1670 // We need to wait here because in when using the OpenSimulator V2 teleport protocol to travel to a destination
1671 // simulator with no existing child presence, the viewer (at least LL 3.3.4) will send UseCircuitCode
1672 // and then CompleteAgentMovement immediately without waiting for an ack. As we are now handling these
1673 // packets asynchronously, we need to account for this thread proceeding more quickly than the
1674 // UseCircuitCode thread.
1675 int count = 40;
1676 while (count-- > 0)
1677 {
1678 if (Scene.TryGetClient(endPoint, out client))
1679 {
1680 if (!client.IsActive)
1681 {
1682 // This check exists to catch a condition where the client has been closed by another thread
1683 // but has not yet been removed from the client manager (and possibly a new connection has
1684 // not yet been established).
1685 m_log.DebugFormat(
1686 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client is not active yet. Waiting.",
1687 endPoint, client.Name, Scene.Name);
1688 }
1689 else if (client.SceneAgent == null)
1690 {
1691 // This check exists to catch a condition where the new client has been added to the client
1692 // manager but the SceneAgent has not yet been set in Scene.AddNewAgent(). If we are too
1693 // eager, then the new ScenePresence may not have registered a listener for this messsage
1694 // before we try to process it.
1695 // XXX: A better long term fix may be to add the SceneAgent before the client is added to
1696 // the client manager
1697 m_log.DebugFormat(
1698 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client SceneAgent not set yet. Waiting.",
1699 endPoint, client.Name, Scene.Name);
1700 }
1701 else
1702 {
1703 break;
1704 }
1705 }
1706 else
1707 {
1708 m_log.DebugFormat(
1709 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} in {1} but no client exists yet. Waiting.",
1710 endPoint, Scene.Name);
1711 }
1712
1713 Thread.Sleep(200);
1714 }
1715
1716 if (client == null)
1717 {
1718 m_log.DebugFormat(
1719 "[LLUDPSERVER]: No client found for CompleteAgentMovement from {0} in {1} after wait. Dropping.",
1720 endPoint, Scene.Name);
1721
1722 return;
1723 }
1724 else if (!client.IsActive || client.SceneAgent == null)
1725 {
1726 // This check exists to catch a condition where the client has been closed by another thread
1727 // but has not yet been removed from the client manager.
1728 // The packet could be simply ignored but it is useful to know if this condition occurred for other debugging
1729 // purposes.
1730 m_log.DebugFormat(
1731 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client is not active after wait. Dropping.",
1732 endPoint, client.Name, Scene.Name);
1733
1734 return;
1735 }
1736
1737 IncomingPacket incomingPacket1;
1738
1739 // Inbox insertion
1740 if (UsePools)
1741 {
1742 incomingPacket1 = m_incomingPacketPool.GetObject();
1743 incomingPacket1.Client = (LLClientView)client;
1744 incomingPacket1.Packet = packet;
1745 }
1746 else
1747 {
1748 incomingPacket1 = new IncomingPacket((LLClientView)client, packet);
1749 }
1750
1751 packetInbox.Enqueue(incomingPacket1);
1752 }
1753 catch (Exception e)
1754 {
1755 m_log.ErrorFormat(
1756 "[LLUDPSERVER]: CompleteAgentMovement handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}",
1757 endPoint != null ? endPoint.ToString() : "n/a",
1758 client != null ? client.Name : "unknown",
1759 client != null ? client.AgentId.ToString() : "unknown",
1760 e.Message,
1761 e.StackTrace);
1762 }
1763 }
1764
1765 /// <summary>
1766 /// Send an ack immediately to the given endpoint.
1767 /// </summary>
1768 /// <remarks>
1769 /// FIXME: Might be possible to use SendPacketData() like everything else, but this will require refactoring so
1770 /// that we can obtain the UDPClient easily at this point.
1771 /// </remarks>
1772 /// <param name="remoteEndpoint"></param>
1773 /// <param name="sequenceNumber"></param>
1774 private void SendAckImmediate(IPEndPoint remoteEndpoint, uint sequenceNumber)
1775 {
1776 PacketAckPacket ack = new PacketAckPacket();
1777 ack.Header.Reliable = false;
1778 ack.Packets = new PacketAckPacket.PacketsBlock[1];
1779 ack.Packets[0] = new PacketAckPacket.PacketsBlock();
1780 ack.Packets[0].ID = sequenceNumber;
1781
1782 SendAckImmediate(remoteEndpoint, ack);
1783 }
1784
1785 public virtual void SendAckImmediate(IPEndPoint remoteEndpoint, PacketAckPacket ack)
1786 {
1787 byte[] packetData = ack.ToBytes();
1788 int length = packetData.Length;
1789
1790 UDPPacketBuffer buffer = new UDPPacketBuffer(remoteEndpoint, length);
1791 buffer.DataLength = length;
1792
1793 Buffer.BlockCopy(packetData, 0, buffer.Data, 0, length);
1794
1795 AsyncBeginSend(buffer);
1796 }
1797
1798 private bool IsClientAuthorized(UseCircuitCodePacket useCircuitCode, out AuthenticateResponse sessionInfo)
1799 {
1800 UUID agentID = useCircuitCode.CircuitCode.ID;
1801 UUID sessionID = useCircuitCode.CircuitCode.SessionID;
1802 uint circuitCode = useCircuitCode.CircuitCode.Code;
1803
1804 sessionInfo = m_circuitManager.AuthenticateSession(sessionID, agentID, circuitCode);
1805 return sessionInfo.Authorised;
1806 }
1807
1808 /// <summary>
1809 /// Add a client.
1810 /// </summary>
1811 /// <param name="circuitCode"></param>
1812 /// <param name="agentID"></param>
1813 /// <param name="sessionID"></param>
1814 /// <param name="remoteEndPoint"></param>
1815 /// <param name="sessionInfo"></param>
1816 /// <returns>The client if it was added. Null if the client already existed.</returns>
1817 protected virtual IClientAPI AddClient(
1818 uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo)
1819 {
1820 IClientAPI client = null;
1821
1822 // We currently synchronize this code across the whole scene to avoid issues such as
1823 // http://opensimulator.org/mantis/view.php?id=5365 However, once locking per agent circuit can be done
1824 // consistently, this lock could probably be removed.
1825 lock (this)
1826 {
1827 if (!Scene.TryGetClient(agentID, out client))
1828 {
1829 LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, Throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO);
1830
1831 client = new LLClientView(Scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
1832 client.OnLogout += LogoutHandler;
1833 client.DebugPacketLevel = DefaultClientPacketDebugLevel;
1834
1835 ((LLClientView)client).DisableFacelights = m_disableFacelights;
1836
1837 client.Start();
1838 }
1839 }
1840
1841 return client;
1842 }
1843
1844 /// <summary>
1845 /// Deactivates the client if we don't receive any packets within a certain amount of time (default 60 seconds).
1846 /// </summary>
1847 /// <remarks>
1848 /// If a connection is active then we will always receive packets even if nothing else is happening, due to
1849 /// regular client pings.
1850 /// </remarks>
1851 /// <param name='client'></param>
1852 /// <param name='timeoutTicks'></param>
1853 private void DeactivateClientDueToTimeout(LLClientView client, int timeoutTicks)
1854 {
1855 lock (client.CloseSyncLock)
1856 {
1857 ClientLogoutsDueToNoReceives++;
1858
1859 m_log.WarnFormat(
1860 "[LLUDPSERVER]: No packets received from {0} agent of {1} for {2}ms in {3}. Disconnecting.",
1861 client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, timeoutTicks, Scene.Name);
1862
1863 if (!client.SceneAgent.IsChildAgent)
1864 client.Kick("Simulator logged you out due to connection timeout.");
1865 }
1866
1867 Scene.CloseAgent(client.AgentId, true);
1868 }
1869
1870 private void IncomingPacketHandler()
1871 {
1872 Thread.CurrentThread.Priority = ThreadPriority.Highest;
1873
1874 // Set this culture for the thread that incoming packets are received
1875 // on to en-US to avoid number parsing issues
1876 Culture.SetCurrentCulture();
1877
1878 while (IsRunningInbound)
1879 {
1880 try
1881 {
1882 IncomingPacket incomingPacket = null;
1883
1884 /*
1885 // HACK: This is a test to try and rate limit packet handling on Mono.
1886 // If it works, a more elegant solution can be devised
1887 if (Util.FireAndForgetCount() < 2)
1888 {
1889 //m_log.Debug("[LLUDPSERVER]: Incoming packet handler is sleeping");
1890 Thread.Sleep(30);
1891 }
1892 */
1893
1894 if (packetInbox.Dequeue(100, ref incomingPacket))
1895 {
1896 ProcessInPacket(incomingPacket);//, incomingPacket); Util.FireAndForget(ProcessInPacket, incomingPacket);
1897
1898 if (UsePools)
1899 m_incomingPacketPool.ReturnObject(incomingPacket);
1900 }
1901 }
1902 catch (Exception ex)
1903 {
1904 m_log.Error("[LLUDPSERVER]: Error in the incoming packet handler loop: " + ex.Message, ex);
1905 }
1906
1907 Watchdog.UpdateThread();
1908 }
1909
1910 if (packetInbox.Count > 0)
1911 m_log.Warn("[LLUDPSERVER]: IncomingPacketHandler is shutting down, dropping " + packetInbox.Count + " packets");
1912 packetInbox.Clear();
1913
1914 Watchdog.RemoveThread();
1915 }
1916
1917 private void OutgoingPacketHandler()
1918 {
1919 Thread.CurrentThread.Priority = ThreadPriority.Highest;
1920
1921 // Set this culture for the thread that outgoing packets are sent
1922 // on to en-US to avoid number parsing issues
1923 Culture.SetCurrentCulture();
1924
1925 // Typecast the function to an Action<IClientAPI> once here to avoid allocating a new
1926 // Action generic every round
1927 Action<IClientAPI> clientPacketHandler = ClientOutgoingPacketHandler;
1928
1929 while (base.IsRunningOutbound)
1930 {
1931 try
1932 {
1933 m_packetSent = false;
1934
1935 #region Update Timers
1936
1937 m_resendUnacked = false;
1938 m_sendAcks = false;
1939 m_sendPing = false;
1940
1941 // Update elapsed time
1942 int thisTick = Environment.TickCount & Int32.MaxValue;
1943 if (m_tickLastOutgoingPacketHandler > thisTick)
1944 m_elapsedMSOutgoingPacketHandler += ((Int32.MaxValue - m_tickLastOutgoingPacketHandler) + thisTick);
1945 else
1946 m_elapsedMSOutgoingPacketHandler += (thisTick - m_tickLastOutgoingPacketHandler);
1947
1948 m_tickLastOutgoingPacketHandler = thisTick;
1949
1950 // Check for pending outgoing resends every 100ms
1951 if (m_elapsedMSOutgoingPacketHandler >= 100)
1952 {
1953 m_resendUnacked = true;
1954 m_elapsedMSOutgoingPacketHandler = 0;
1955 m_elapsed100MSOutgoingPacketHandler += 1;
1956 }
1957
1958 // Check for pending outgoing ACKs every 500ms
1959 if (m_elapsed100MSOutgoingPacketHandler >= 5)
1960 {
1961 m_sendAcks = true;
1962 m_elapsed100MSOutgoingPacketHandler = 0;
1963 m_elapsed500MSOutgoingPacketHandler += 1;
1964 }
1965
1966 // Send pings to clients every 5000ms
1967 if (m_elapsed500MSOutgoingPacketHandler >= 10)
1968 {
1969 m_sendPing = true;
1970 m_elapsed500MSOutgoingPacketHandler = 0;
1971 }
1972
1973 #endregion Update Timers
1974
1975 // Use this for emergency monitoring -- bug hunting
1976 //if (m_scene.EmergencyMonitoring)
1977 // clientPacketHandler = MonitoredClientOutgoingPacketHandler;
1978 //else
1979 // clientPacketHandler = ClientOutgoingPacketHandler;
1980
1981 // Handle outgoing packets, resends, acknowledgements, and pings for each
1982 // client. m_packetSent will be set to true if a packet is sent
1983 Scene.ForEachClient(clientPacketHandler);
1984
1985 m_currentOutgoingClient = null;
1986
1987 // If nothing was sent, sleep for the minimum amount of time before a
1988 // token bucket could get more tokens
1989 //if (!m_packetSent)
1990 // Thread.Sleep((int)TickCountResolution);
1991 //
1992 // Instead, now wait for data present to be explicitly signalled. Evidence so far is that with
1993 // modern mono it reduces CPU base load since there is no more continuous polling.
1994 if (!m_packetSent)
1995 m_dataPresentEvent.WaitOne(100);
1996
1997 Watchdog.UpdateThread();
1998 }
1999 catch (Exception ex)
2000 {
2001 m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler loop threw an exception: " + ex.Message, ex);
2002 }
2003 }
2004
2005 Watchdog.RemoveThread();
2006 }
2007
2008 protected void ClientOutgoingPacketHandler(IClientAPI client)
2009 {
2010 m_currentOutgoingClient = client;
2011
2012 try
2013 {
2014 if (client is LLClientView)
2015 {
2016 LLClientView llClient = (LLClientView)client;
2017 LLUDPClient udpClient = llClient.UDPClient;
2018
2019 if (udpClient.IsConnected)
2020 {
2021 if (udpClient.ProcessUnackedSends && m_resendUnacked)
2022 HandleUnacked(llClient);
2023
2024 if (m_sendAcks)
2025 SendAcks(udpClient);
2026
2027 if (m_sendPing)
2028 SendPing(udpClient);
2029
2030 // Dequeue any outgoing packets that are within the throttle limits
2031 if (udpClient.DequeueOutgoing())
2032 m_packetSent = true;
2033 }
2034 }
2035 }
2036 catch (Exception ex)
2037 {
2038 m_log.Error(
2039 string.Format("[LLUDPSERVER]: OutgoingPacketHandler iteration for {0} threw ", client.Name), ex);
2040 }
2041 }
2042
2043 #region Emergency Monitoring
2044 // Alternative packet handler fuull of instrumentation
2045 // Handy for hunting bugs
2046 private Stopwatch watch1 = new Stopwatch();
2047 private Stopwatch watch2 = new Stopwatch();
2048
2049 private float avgProcessingTicks = 0;
2050 private float avgResendUnackedTicks = 0;
2051 private float avgSendAcksTicks = 0;
2052 private float avgSendPingTicks = 0;
2053 private float avgDequeueTicks = 0;
2054 private long nticks = 0;
2055 private long nticksUnack = 0;
2056 private long nticksAck = 0;
2057 private long nticksPing = 0;
2058 private int npacksSent = 0;
2059 private int npackNotSent = 0;
2060
2061 /// <summary>
2062 /// Number of inbound packets processed since startup.
2063 /// </summary>
2064 public long IncomingPacketsProcessed { get; private set; }
2065
2066 private void MonitoredClientOutgoingPacketHandler(IClientAPI client)
2067 {
2068 nticks++;
2069 watch1.Start();
2070 m_currentOutgoingClient = client;
2071
2072 try
2073 {
2074 if (client is LLClientView)
2075 {
2076 LLClientView llClient = (LLClientView)client;
2077 LLUDPClient udpClient = llClient.UDPClient;
2078
2079 if (udpClient.IsConnected)
2080 {
2081 if (m_resendUnacked)
2082 {
2083 nticksUnack++;
2084 watch2.Start();
2085
2086 HandleUnacked(llClient);
2087
2088 watch2.Stop();
2089 avgResendUnackedTicks = (nticksUnack - 1)/(float)nticksUnack * avgResendUnackedTicks + (watch2.ElapsedTicks / (float)nticksUnack);
2090 watch2.Reset();
2091 }
2092
2093 if (m_sendAcks)
2094 {
2095 nticksAck++;
2096 watch2.Start();
2097
2098 SendAcks(udpClient);
2099
2100 watch2.Stop();
2101 avgSendAcksTicks = (nticksAck - 1) / (float)nticksAck * avgSendAcksTicks + (watch2.ElapsedTicks / (float)nticksAck);
2102 watch2.Reset();
2103 }
2104
2105 if (m_sendPing)
2106 {
2107 nticksPing++;
2108 watch2.Start();
2109
2110 SendPing(udpClient);
2111
2112 watch2.Stop();
2113 avgSendPingTicks = (nticksPing - 1) / (float)nticksPing * avgSendPingTicks + (watch2.ElapsedTicks / (float)nticksPing);
2114 watch2.Reset();
2115 }
2116
2117 watch2.Start();
2118 // Dequeue any outgoing packets that are within the throttle limits
2119 if (udpClient.DequeueOutgoing())
2120 {
2121 m_packetSent = true;
2122 npacksSent++;
2123 }
2124 else
2125 {
2126 npackNotSent++;
2127 }
2128
2129 watch2.Stop();
2130 avgDequeueTicks = (nticks - 1) / (float)nticks * avgDequeueTicks + (watch2.ElapsedTicks / (float)nticks);
2131 watch2.Reset();
2132
2133 }
2134 else
2135 {
2136 m_log.WarnFormat("[LLUDPSERVER]: Client is not connected");
2137 }
2138 }
2139 }
2140 catch (Exception ex)
2141 {
2142 m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler iteration for " + client.Name +
2143 " threw an exception: " + ex.Message, ex);
2144 }
2145 watch1.Stop();
2146 avgProcessingTicks = (nticks - 1) / (float)nticks * avgProcessingTicks + (watch1.ElapsedTicks / (float)nticks);
2147 watch1.Reset();
2148
2149 // reuse this -- it's every ~100ms
2150 if (Scene.EmergencyMonitoring && nticks % 100 == 0)
2151 {
2152 m_log.InfoFormat("[LLUDPSERVER]: avg processing ticks: {0} avg unacked: {1} avg acks: {2} avg ping: {3} avg dequeue: {4} (TickCountRes: {5} sent: {6} notsent: {7})",
2153 avgProcessingTicks, avgResendUnackedTicks, avgSendAcksTicks, avgSendPingTicks, avgDequeueTicks, TickCountResolution, npacksSent, npackNotSent);
2154 npackNotSent = npacksSent = 0;
2155 }
2156
2157 }
2158
2159 #endregion
2160
2161 private void ProcessInPacket(IncomingPacket incomingPacket)
2162 {
2163 Packet packet = incomingPacket.Packet;
2164 LLClientView client = incomingPacket.Client;
2165
2166 if (client.IsActive)
2167 {
2168 m_currentIncomingClient = client;
2169
2170 try
2171 {
2172 // Process this packet
2173 client.ProcessInPacket(packet);
2174 }
2175 catch (ThreadAbortException)
2176 {
2177 // If something is trying to abort the packet processing thread, take that as a hint that it's time to shut down
2178 m_log.Info("[LLUDPSERVER]: Caught a thread abort, shutting down the LLUDP server");
2179 Stop();
2180 }
2181 catch (Exception e)
2182 {
2183 // Don't let a failure in an individual client thread crash the whole sim.
2184 m_log.Error(
2185 string.Format(
2186 "[LLUDPSERVER]: Client packet handler for {0} for packet {1} threw ",
2187 client.Name, packet.Type),
2188 e);
2189 }
2190 finally
2191 {
2192 m_currentIncomingClient = null;
2193 }
2194 }
2195 else
2196 {
2197 m_log.DebugFormat(
2198 "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}",
2199 packet.Type, client.Name, Scene.RegionInfo.RegionName);
2200 }
2201
2202 IncomingPacketsProcessed++;
2203 }
2204
2205 protected void LogoutHandler(IClientAPI client)
2206 {
2207 client.SendLogoutPacket();
2208
2209 if (!client.IsLoggingOut)
2210 {
2211 client.IsLoggingOut = true;
2212 Scene.CloseAgent(client.AgentId, false);
2213 }
2214 }
2215 }
2216}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs
new file mode 100644
index 0000000..ac6c0b4
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs
@@ -0,0 +1,901 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Text;
31using NDesk.Options;
32using OpenSim.Framework;
33using OpenSim.Framework.Console;
34using OpenSim.Region.Framework.Scenes;
35
36namespace OpenSim.Region.ClientStack.LindenUDP
37{
38 public class LLUDPServerCommands
39 {
40 private ICommandConsole m_console;
41 private LLUDPServer m_udpServer;
42
43 public LLUDPServerCommands(ICommandConsole console, LLUDPServer udpServer)
44 {
45 m_console = console;
46 m_udpServer = udpServer;
47 }
48
49 public void Register()
50 {
51 m_console.Commands.AddCommand(
52 "Comms", false, "show server throttles",
53 "show server throttles",
54 "Show information about server throttles",
55 HandleShowServerThrottlesCommand);
56
57 m_console.Commands.AddCommand(
58 "Debug", false, "debug lludp packet",
59 "debug lludp packet [--default | --all] <level> [<avatar-first-name> <avatar-last-name>]",
60 "Turn on packet debugging. This logs information when the client stack hands a processed packet off to downstream code or when upstream code first requests that a certain packet be sent.",
61 "If level > 255 then all incoming and outgoing packets are logged.\n"
62 + "If level <= 255 then incoming AgentUpdate and outgoing SimStats and SimulatorViewerTimeMessage packets are not logged.\n"
63 + "If level <= 200 then incoming RequestImage and outgoing ImagePacket, ImageData, LayerData and CoarseLocationUpdate packets are not logged.\n"
64 + "If level <= 100 then incoming ViewerEffect and AgentAnimation and outgoing ViewerEffect and AvatarAnimation packets are not logged.\n"
65 + "If level <= 50 then outgoing ImprovedTerseObjectUpdate packets are not logged.\n"
66 + "If level <= 0 then no packets are logged.\n"
67 + "If --default is specified then the level becomes the default logging level for all subsequent agents.\n"
68 + "If --all is specified then the level becomes the default logging level for all current and subsequent agents.\n"
69 + "In these cases, you cannot also specify an avatar name.\n"
70 + "If an avatar name is given then only packets from that avatar are logged.",
71 HandlePacketCommand);
72
73 m_console.Commands.AddCommand(
74 "Debug", false, "debug lludp data out",
75 "debug lludp data out <level> <avatar-first-name> <avatar-last-name>\"",
76 "Turn on debugging for final outgoing data to the given user's client.",
77 "This operates at a much lower level than the packet command and prints out available details when the data is actually sent.\n"
78 + "If level > 0 then information about all outgoing UDP data for this avatar is logged.\n"
79 + "If level <= 0 then no information about outgoing UDP data for this avatar is logged.",
80 HandleDataCommand);
81
82 m_console.Commands.AddCommand(
83 "Debug", false, "debug lludp drop",
84 "debug lludp drop <in|out> <add|remove> <packet-name>",
85 "Drop all in or outbound packets that match the given name",
86 "For test purposes.",
87 HandleDropCommand);
88
89 m_console.Commands.AddCommand(
90 "Debug",
91 false,
92 "debug lludp start",
93 "debug lludp start <in|out|all>",
94 "Control LLUDP packet processing.",
95 "No effect if packet processing has already started.\n"
96 + "in - start inbound processing.\n"
97 + "out - start outbound processing.\n"
98 + "all - start in and outbound processing.\n",
99 HandleStartCommand);
100
101 m_console.Commands.AddCommand(
102 "Debug",
103 false,
104 "debug lludp stop",
105 "debug lludp stop <in|out|all>",
106 "Stop LLUDP packet processing.",
107 "No effect if packet processing has already stopped.\n"
108 + "in - stop inbound processing.\n"
109 + "out - stop outbound processing.\n"
110 + "all - stop in and outbound processing.\n",
111 HandleStopCommand);
112
113 m_console.Commands.AddCommand(
114 "Debug",
115 false,
116 "debug lludp pool",
117 "debug lludp pool <on|off>",
118 "Turn object pooling within the lludp component on or off.",
119 HandlePoolCommand);
120
121 m_console.Commands.AddCommand(
122 "Debug",
123 false,
124 "debug lludp status",
125 "debug lludp status",
126 "Return status of LLUDP packet processing.",
127 HandleStatusCommand);
128
129 m_console.Commands.AddCommand(
130 "Debug",
131 false,
132 "debug lludp throttles log",
133 "debug lludp throttles log <level> [<avatar-first-name> <avatar-last-name>]",
134 "Change debug logging level for throttles.",
135 "If level >= 0 then throttle debug logging is performed.\n"
136 + "If level <= 0 then no throttle debug logging is performed.",
137 HandleThrottleCommand);
138
139 m_console.Commands.AddCommand(
140 "Debug",
141 false,
142 "debug lludp throttles get",
143 "debug lludp throttles get [<avatar-first-name> <avatar-last-name>]",
144 "Return debug settings for throttles.",
145 "adaptive - true/false, controls adaptive throttle setting.\n"
146 + "request - request drip rate in kbps.\n"
147 + "max - the max kbps throttle allowed for the specified existing clients. Use 'debug lludp get new-client-throttle-max' to see the setting for new clients.\n",
148 HandleThrottleGetCommand);
149
150 m_console.Commands.AddCommand(
151 "Debug",
152 false,
153 "debug lludp throttles set",
154 "debug lludp throttles set <param> <value> [<avatar-first-name> <avatar-last-name>]",
155 "Set a throttle parameter for the given client.",
156 "adaptive - true/false, controls adaptive throttle setting.\n"
157 + "current - current drip rate in kbps.\n"
158 + "request - requested drip rate in kbps.\n"
159 + "max - the max kbps throttle allowed for the specified existing clients. Use 'debug lludp set new-client-throttle-max' to change the settings for new clients.\n",
160 HandleThrottleSetCommand);
161
162 m_console.Commands.AddCommand(
163 "Debug",
164 false,
165 "debug lludp get",
166 "debug lludp get",
167 "Get debug parameters for the server.",
168 "max-scene-throttle - the current max cumulative kbps provided for this scene to clients.\n"
169 + "max-new-client-throttle - the max kbps throttle allowed to new clients. Use 'debug lludp throttles get max' to see the settings for existing clients.",
170 HandleGetCommand);
171
172 m_console.Commands.AddCommand(
173 "Debug",
174 false,
175 "debug lludp set",
176 "debug lludp set <param> <value>",
177 "Set a parameter for the server.",
178 "max-scene-throttle - the current max cumulative kbps provided for this scene to clients.\n"
179 + "max-new-client-throttle - the max kbps throttle allowed to each new client. Use 'debug lludp throttles set max' to set for existing clients.",
180 HandleSetCommand);
181
182 m_console.Commands.AddCommand(
183 "Debug",
184 false,
185 "debug lludp toggle agentupdate",
186 "debug lludp toggle agentupdate",
187 "Toggle whether agentupdate packets are processed or simply discarded.",
188 HandleAgentUpdateCommand);
189
190 MainConsole.Instance.Commands.AddCommand(
191 "Debug",
192 false,
193 "debug lludp oqre",
194 "debug lludp oqre <start|stop|status>",
195 "Start, stop or get status of OutgoingQueueRefillEngine.",
196 "If stopped then refill requests are processed directly via the threadpool.",
197 HandleOqreCommand);
198
199 m_console.Commands.AddCommand(
200 "Debug",
201 false,
202 "debug lludp client get",
203 "debug lludp client get [<avatar-first-name> <avatar-last-name>]",
204 "Get debug parameters for the client. If no name is given then all client information is returned.",
205 "process-unacked-sends - Do we take action if a sent reliable packet has not been acked.",
206 HandleClientGetCommand);
207
208 m_console.Commands.AddCommand(
209 "Debug",
210 false,
211 "debug lludp client set",
212 "debug lludp client set <param> <value> [<avatar-first-name> <avatar-last-name>]",
213 "Set a debug parameter for a particular client. If no name is given then the value is set on all clients.",
214 "process-unacked-sends - Do we take action if a sent reliable packet has not been acked.",
215 HandleClientSetCommand);
216 }
217
218 private void HandleShowServerThrottlesCommand(string module, string[] args)
219 {
220 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
221 return;
222
223 m_console.OutputFormat("Throttles for {0}", m_udpServer.Scene.Name);
224 ConsoleDisplayList cdl = new ConsoleDisplayList();
225 cdl.AddRow("Adaptive throttles", m_udpServer.ThrottleRates.AdaptiveThrottlesEnabled);
226
227 long maxSceneDripRate = m_udpServer.Throttle.MaxDripRate;
228 cdl.AddRow(
229 "Max scene throttle",
230 maxSceneDripRate != 0 ? string.Format("{0} kbps", maxSceneDripRate * 8 / 1000) : "unset");
231
232 int maxClientDripRate = m_udpServer.ThrottleRates.Total;
233 cdl.AddRow(
234 "Max new client throttle",
235 maxClientDripRate != 0 ? string.Format("{0} kbps", maxClientDripRate * 8 / 1000) : "unset");
236
237 m_console.Output(cdl.ToString());
238
239 m_console.OutputFormat("{0}\n", GetServerThrottlesReport(m_udpServer));
240 }
241
242 private string GetServerThrottlesReport(LLUDPServer udpServer)
243 {
244 StringBuilder report = new StringBuilder();
245
246 report.AppendFormat(
247 "{0,7} {1,8} {2,7} {3,7} {4,7} {5,7} {6,9} {7,7}\n",
248 "Total",
249 "Resend",
250 "Land",
251 "Wind",
252 "Cloud",
253 "Task",
254 "Texture",
255 "Asset");
256
257 report.AppendFormat(
258 "{0,7} {1,8} {2,7} {3,7} {4,7} {5,7} {6,9} {7,7}\n",
259 "kb/s",
260 "kb/s",
261 "kb/s",
262 "kb/s",
263 "kb/s",
264 "kb/s",
265 "kb/s",
266 "kb/s");
267
268 ThrottleRates throttleRates = udpServer.ThrottleRates;
269 report.AppendFormat(
270 "{0,7} {1,8} {2,7} {3,7} {4,7} {5,7} {6,9} {7,7}",
271 (throttleRates.Total * 8) / 1000,
272 (throttleRates.Resend * 8) / 1000,
273 (throttleRates.Land * 8) / 1000,
274 (throttleRates.Wind * 8) / 1000,
275 (throttleRates.Cloud * 8) / 1000,
276 (throttleRates.Task * 8) / 1000,
277 (throttleRates.Texture * 8) / 1000,
278 (throttleRates.Asset * 8) / 1000);
279
280 return report.ToString();
281 }
282
283 protected string GetColumnEntry(string entry, int maxLength, int columnPadding)
284 {
285 return string.Format(
286 "{0,-" + maxLength + "}{1,-" + columnPadding + "}",
287 entry.Length > maxLength ? entry.Substring(0, maxLength) : entry,
288 "");
289 }
290
291 private void HandleDataCommand(string module, string[] args)
292 {
293 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
294 return;
295
296 if (args.Length != 7)
297 {
298 MainConsole.Instance.OutputFormat("Usage: debug lludp data out <true|false> <avatar-first-name> <avatar-last-name>");
299 return;
300 }
301
302 int level;
303 if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[4], out level))
304 return;
305
306 string firstName = args[5];
307 string lastName = args[6];
308
309 m_udpServer.Scene.ForEachScenePresence(sp =>
310 {
311 if (sp.Firstname == firstName && sp.Lastname == lastName)
312 {
313 MainConsole.Instance.OutputFormat(
314 "Data debug for {0} ({1}) set to {2} in {3}",
315 sp.Name, sp.IsChildAgent ? "child" : "root", level, m_udpServer.Scene.Name);
316
317 ((LLClientView)sp.ControllingClient).UDPClient.DebugDataOutLevel = level;
318 }
319 });
320 }
321
322 private void HandleThrottleCommand(string module, string[] args)
323 {
324 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
325 return;
326
327 bool all = args.Length == 5;
328 bool one = args.Length == 7;
329
330 if (!all && !one)
331 {
332 MainConsole.Instance.OutputFormat(
333 "Usage: debug lludp throttles log <level> [<avatar-first-name> <avatar-last-name>]");
334 return;
335 }
336
337 int level;
338 if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[4], out level))
339 return;
340
341 string firstName = null;
342 string lastName = null;
343
344 if (one)
345 {
346 firstName = args[5];
347 lastName = args[6];
348 }
349
350 m_udpServer.Scene.ForEachScenePresence(sp =>
351 {
352 if (all || (sp.Firstname == firstName && sp.Lastname == lastName))
353 {
354 MainConsole.Instance.OutputFormat(
355 "Throttle log level for {0} ({1}) set to {2} in {3}",
356 sp.Name, sp.IsChildAgent ? "child" : "root", level, m_udpServer.Scene.Name);
357
358 ((LLClientView)sp.ControllingClient).UDPClient.ThrottleDebugLevel = level;
359 }
360 });
361 }
362
363 private void HandleThrottleSetCommand(string module, string[] args)
364 {
365 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
366 return;
367
368 bool all = args.Length == 6;
369 bool one = args.Length == 8;
370
371 if (!all && !one)
372 {
373 MainConsole.Instance.OutputFormat(
374 "Usage: debug lludp throttles set <param> <value> [<avatar-first-name> <avatar-last-name>]");
375 return;
376 }
377
378 string param = args[4];
379 string rawValue = args[5];
380
381 string firstName = null;
382 string lastName = null;
383
384 if (one)
385 {
386 firstName = args[6];
387 lastName = args[7];
388 }
389
390 if (param == "adaptive")
391 {
392 bool newValue;
393 if (!ConsoleUtil.TryParseConsoleBool(MainConsole.Instance, rawValue, out newValue))
394 return;
395
396 m_udpServer.Scene.ForEachScenePresence(sp =>
397 {
398 if (all || (sp.Firstname == firstName && sp.Lastname == lastName))
399 {
400 MainConsole.Instance.OutputFormat(
401 "Setting param {0} to {1} for {2} ({3}) in {4}",
402 param, newValue, sp.Name, sp.IsChildAgent ? "child" : "root", m_udpServer.Scene.Name);
403
404 LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
405 udpClient.FlowThrottle.AdaptiveEnabled = newValue;
406 // udpClient.FlowThrottle.MaxDripRate = 0;
407 // udpClient.FlowThrottle.AdjustedDripRate = 0;
408 }
409 });
410 }
411 else if (param == "request")
412 {
413 int newValue;
414 if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, rawValue, out newValue))
415 return;
416
417 int newCurrentThrottleKbps = newValue * 1000 / 8;
418
419 m_udpServer.Scene.ForEachScenePresence(sp =>
420 {
421 if (all || (sp.Firstname == firstName && sp.Lastname == lastName))
422 {
423 MainConsole.Instance.OutputFormat(
424 "Setting param {0} to {1} for {2} ({3}) in {4}",
425 param, newValue, sp.Name, sp.IsChildAgent ? "child" : "root", m_udpServer.Scene.Name);
426
427 LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
428 udpClient.FlowThrottle.RequestedDripRate = newCurrentThrottleKbps;
429 }
430 });
431 }
432 else if (param == "max")
433 {
434 int newValue;
435 if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, rawValue, out newValue))
436 return;
437
438 int newThrottleMaxKbps = newValue * 1000 / 8;
439
440 m_udpServer.Scene.ForEachScenePresence(sp =>
441 {
442 if (all || (sp.Firstname == firstName && sp.Lastname == lastName))
443 {
444 MainConsole.Instance.OutputFormat(
445 "Setting param {0} to {1} for {2} ({3}) in {4}",
446 param, newValue, sp.Name, sp.IsChildAgent ? "child" : "root", m_udpServer.Scene.Name);
447
448 LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
449 udpClient.FlowThrottle.MaxDripRate = newThrottleMaxKbps;
450 }
451 });
452 }
453 }
454
455 private void HandleThrottleGetCommand(string module, string[] args)
456 {
457 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
458 return;
459
460 bool all = args.Length == 4;
461 bool one = args.Length == 6;
462
463 if (!all && !one)
464 {
465 MainConsole.Instance.OutputFormat(
466 "Usage: debug lludp throttles get [<avatar-first-name> <avatar-last-name>]");
467 return;
468 }
469
470 string firstName = null;
471 string lastName = null;
472
473 if (one)
474 {
475 firstName = args[4];
476 lastName = args[5];
477 }
478
479 m_udpServer.Scene.ForEachScenePresence(sp =>
480 {
481 if (all || (sp.Firstname == firstName && sp.Lastname == lastName))
482 {
483 m_console.OutputFormat(
484 "Status for {0} ({1}) in {2}",
485 sp.Name, sp.IsChildAgent ? "child" : "root", m_udpServer.Scene.Name);
486
487 LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
488
489 ConsoleDisplayList cdl = new ConsoleDisplayList();
490 cdl.AddRow("adaptive", udpClient.FlowThrottle.AdaptiveEnabled);
491 cdl.AddRow("current", string.Format("{0} kbps", udpClient.FlowThrottle.DripRate * 8 / 1000));
492 cdl.AddRow("request", string.Format("{0} kbps", udpClient.FlowThrottle.RequestedDripRate * 8 / 1000));
493 cdl.AddRow("max", string.Format("{0} kbps", udpClient.FlowThrottle.MaxDripRate * 8 / 1000));
494
495 m_console.Output(cdl.ToString());
496 }
497 });
498 }
499
500 private void HandleGetCommand(string module, string[] args)
501 {
502 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
503 return;
504
505 m_console.OutputFormat("Debug settings for {0}", m_udpServer.Scene.Name);
506 ConsoleDisplayList cdl = new ConsoleDisplayList();
507
508 long maxSceneDripRate = m_udpServer.Throttle.MaxDripRate;
509 cdl.AddRow(
510 "max-scene-throttle",
511 maxSceneDripRate != 0 ? string.Format("{0} kbps", maxSceneDripRate * 8 / 1000) : "unset");
512
513 int maxClientDripRate = m_udpServer.ThrottleRates.Total;
514 cdl.AddRow(
515 "max-new-client-throttle",
516 maxClientDripRate != 0 ? string.Format("{0} kbps", maxClientDripRate * 8 / 1000) : "unset");
517
518 m_console.Output(cdl.ToString());
519 }
520
521 private void HandleSetCommand(string module, string[] args)
522 {
523 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
524 return;
525
526 if (args.Length != 5)
527 {
528 MainConsole.Instance.OutputFormat("Usage: debug lludp set <param> <value>");
529 return;
530 }
531
532 string param = args[3];
533 string rawValue = args[4];
534
535 int newValue;
536
537 if (param == "max-scene-throttle")
538 {
539 if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, rawValue, out newValue))
540 return;
541
542 m_udpServer.Throttle.MaxDripRate = newValue * 1000 / 8;
543 }
544 else if (param == "max-new-client-throttle")
545 {
546 if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, rawValue, out newValue))
547 return;
548
549 m_udpServer.ThrottleRates.Total = newValue * 1000 / 8;
550 }
551 else
552 {
553 return;
554 }
555
556 m_console.OutputFormat("{0} set to {1} in {2}", param, rawValue, m_udpServer.Scene.Name);
557 }
558
559 private void HandleClientGetCommand(string module, string[] args)
560 {
561 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
562 return;
563
564 if (args.Length != 4 && args.Length != 6)
565 {
566 MainConsole.Instance.OutputFormat("Usage: debug lludp client get [<avatar-first-name> <avatar-last-name>]");
567 return;
568 }
569
570 string name = null;
571
572 if (args.Length == 6)
573 name = string.Format("{0} {1}", args[4], args[5]);
574
575 m_udpServer.Scene.ForEachScenePresence(
576 sp =>
577 {
578 if ((name == null || sp.Name == name) && sp.ControllingClient is LLClientView)
579 {
580 LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
581
582 m_console.OutputFormat(
583 "Client debug parameters for {0} ({1}) in {2}",
584 sp.Name, sp.IsChildAgent ? "child" : "root", m_udpServer.Scene.Name);
585
586 ConsoleDisplayList cdl = new ConsoleDisplayList();
587 cdl.AddRow("process-unacked-sends", udpClient.ProcessUnackedSends);
588
589 m_console.Output(cdl.ToString());
590 }
591 });
592 }
593
594 private void HandleClientSetCommand(string module, string[] args)
595 {
596 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
597 return;
598
599 if (args.Length != 6 && args.Length != 8)
600 {
601 MainConsole.Instance.OutputFormat("Usage: debug lludp client set <param> <value> [<avatar-first-name> <avatar-last-name>]");
602 return;
603 }
604
605 string param = args[4];
606 string rawValue = args[5];
607
608 string name = null;
609
610 if (args.Length == 8)
611 name = string.Format("{0} {1}", args[6], args[7]);
612
613 if (param == "process-unacked-sends")
614 {
615 bool newValue;
616
617 if (!ConsoleUtil.TryParseConsoleBool(MainConsole.Instance, rawValue, out newValue))
618 return;
619
620 m_udpServer.Scene.ForEachScenePresence(
621 sp =>
622 {
623 if ((name == null || sp.Name == name) && sp.ControllingClient is LLClientView)
624 {
625 LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
626 udpClient.ProcessUnackedSends = newValue;
627
628 m_console.OutputFormat("{0} set to {1} for {2} in {3}", param, newValue, sp.Name, m_udpServer.Scene.Name);
629 }
630 });
631 }
632 }
633
634 private void HandlePacketCommand(string module, string[] args)
635 {
636 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
637 return;
638
639 bool setAsDefaultLevel = false;
640 bool setAll = false;
641 OptionSet optionSet = new OptionSet()
642 .Add("default", o => setAsDefaultLevel = (o != null))
643 .Add("all", o => setAll = (o != null));
644 List<string> filteredArgs = optionSet.Parse(args);
645
646 string name = null;
647
648 if (filteredArgs.Count == 6)
649 {
650 if (!(setAsDefaultLevel || setAll))
651 {
652 name = string.Format("{0} {1}", filteredArgs[4], filteredArgs[5]);
653 }
654 else
655 {
656 MainConsole.Instance.OutputFormat("ERROR: Cannot specify a user name when setting default/all logging level");
657 return;
658 }
659 }
660
661 if (filteredArgs.Count > 3)
662 {
663 int newDebug;
664 if (int.TryParse(filteredArgs[3], out newDebug))
665 {
666 if (setAsDefaultLevel || setAll)
667 {
668 m_udpServer.DefaultClientPacketDebugLevel = newDebug;
669
670 MainConsole.Instance.OutputFormat(
671 "Packet debug for {0} clients set to {1} in {2}",
672 (setAll ? "all" : "future"), m_udpServer.DefaultClientPacketDebugLevel, m_udpServer.Scene.Name);
673
674 if (setAll)
675 {
676 m_udpServer.Scene.ForEachScenePresence(sp =>
677 {
678 MainConsole.Instance.OutputFormat(
679 "Packet debug for {0} ({1}) set to {2} in {3}",
680 sp.Name, sp.IsChildAgent ? "child" : "root", newDebug, m_udpServer.Scene.Name);
681
682 sp.ControllingClient.DebugPacketLevel = newDebug;
683 });
684 }
685 }
686 else
687 {
688 m_udpServer.Scene.ForEachScenePresence(sp =>
689 {
690 if (name == null || sp.Name == name)
691 {
692 MainConsole.Instance.OutputFormat(
693 "Packet debug for {0} ({1}) set to {2} in {3}",
694 sp.Name, sp.IsChildAgent ? "child" : "root", newDebug, m_udpServer.Scene.Name);
695
696 sp.ControllingClient.DebugPacketLevel = newDebug;
697 }
698 });
699 }
700 }
701 else
702 {
703 MainConsole.Instance.Output("Usage: debug lludp packet [--default | --all] 0..255 [<first-name> <last-name>]");
704 }
705 }
706 }
707
708 private void HandleDropCommand(string module, string[] args)
709 {
710 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
711 return;
712
713 if (args.Length != 6)
714 {
715 MainConsole.Instance.Output("Usage: debug lludp drop <in|out> <add|remove> <packet-name>");
716 return;
717 }
718
719 string direction = args[3];
720 string subCommand = args[4];
721 string packetName = args[5];
722
723 if (subCommand == "add")
724 {
725 MainConsole.Instance.OutputFormat(
726 "Adding packet {0} to {1} drop list for all connections in {2}",
727 direction, packetName, m_udpServer.Scene.Name);
728
729 m_udpServer.Scene.ForEachScenePresence(
730 sp =>
731 {
732 LLClientView llcv = (LLClientView)sp.ControllingClient;
733
734 if (direction == "in")
735 llcv.AddInPacketToDropSet(packetName);
736 else if (direction == "out")
737 llcv.AddOutPacketToDropSet(packetName);
738 }
739 );
740 }
741 else if (subCommand == "remove")
742 {
743 MainConsole.Instance.OutputFormat(
744 "Removing packet {0} from {1} drop list for all connections in {2}",
745 direction, packetName, m_udpServer.Scene.Name);
746
747 m_udpServer.Scene.ForEachScenePresence(
748 sp =>
749 {
750 LLClientView llcv = (LLClientView)sp.ControllingClient;
751
752 if (direction == "in")
753 llcv.RemoveInPacketFromDropSet(packetName);
754 else if (direction == "out")
755 llcv.RemoveOutPacketFromDropSet(packetName);
756 }
757 );
758 }
759 }
760
761 private void HandleStartCommand(string module, string[] args)
762 {
763 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
764 return;
765
766 if (args.Length != 4)
767 {
768 MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>");
769 return;
770 }
771
772 string subCommand = args[3];
773
774 if (subCommand == "in" || subCommand == "all")
775 m_udpServer.StartInbound();
776
777 if (subCommand == "out" || subCommand == "all")
778 m_udpServer.StartOutbound();
779 }
780
781 private void HandleStopCommand(string module, string[] args)
782 {
783 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
784 return;
785
786 if (args.Length != 4)
787 {
788 MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>");
789 return;
790 }
791
792 string subCommand = args[3];
793
794 if (subCommand == "in" || subCommand == "all")
795 m_udpServer.StopInbound();
796
797 if (subCommand == "out" || subCommand == "all")
798 m_udpServer.StopOutbound();
799 }
800
801 private void HandlePoolCommand(string module, string[] args)
802 {
803 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
804 return;
805
806 if (args.Length != 4)
807 {
808 MainConsole.Instance.Output("Usage: debug lludp pool <on|off>");
809 return;
810 }
811
812 string enabled = args[3];
813
814 if (enabled == "on")
815 {
816 if (m_udpServer.EnablePools())
817 {
818 m_udpServer.EnablePoolStats();
819 MainConsole.Instance.OutputFormat("Packet pools enabled on {0}", m_udpServer.Scene.Name);
820 }
821 }
822 else if (enabled == "off")
823 {
824 if (m_udpServer.DisablePools())
825 {
826 m_udpServer.DisablePoolStats();
827 MainConsole.Instance.OutputFormat("Packet pools disabled on {0}", m_udpServer.Scene.Name);
828 }
829 }
830 else
831 {
832 MainConsole.Instance.Output("Usage: debug lludp pool <on|off>");
833 }
834 }
835
836 private void HandleAgentUpdateCommand(string module, string[] args)
837 {
838 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
839 return;
840
841 m_udpServer.DiscardInboundAgentUpdates = !m_udpServer.DiscardInboundAgentUpdates;
842
843 MainConsole.Instance.OutputFormat(
844 "Discard AgentUpdates now {0} for {1}", m_udpServer.DiscardInboundAgentUpdates, m_udpServer.Scene.Name);
845 }
846
847 private void HandleStatusCommand(string module, string[] args)
848 {
849 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
850 return;
851
852 MainConsole.Instance.OutputFormat(
853 "IN LLUDP packet processing for {0} is {1}", m_udpServer.Scene.Name, m_udpServer.IsRunningInbound ? "enabled" : "disabled");
854
855 MainConsole.Instance.OutputFormat(
856 "OUT LLUDP packet processing for {0} is {1}", m_udpServer.Scene.Name, m_udpServer.IsRunningOutbound ? "enabled" : "disabled");
857
858 MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_udpServer.Scene.Name, m_udpServer.UsePools ? "on" : "off");
859
860 MainConsole.Instance.OutputFormat(
861 "Packet debug level for new clients is {0}", m_udpServer.DefaultClientPacketDebugLevel);
862 }
863
864 private void HandleOqreCommand(string module, string[] args)
865 {
866 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
867 return;
868
869 if (args.Length != 4)
870 {
871 MainConsole.Instance.Output("Usage: debug lludp oqre <stop|start|status>");
872 return;
873 }
874
875 string subCommand = args[3];
876
877 if (subCommand == "stop")
878 {
879 m_udpServer.OqrEngine.Stop();
880 MainConsole.Instance.OutputFormat("Stopped OQRE for {0}", m_udpServer.Scene.Name);
881 }
882 else if (subCommand == "start")
883 {
884 m_udpServer.OqrEngine.Start();
885 MainConsole.Instance.OutputFormat("Started OQRE for {0}", m_udpServer.Scene.Name);
886 }
887 else if (subCommand == "status")
888 {
889 MainConsole.Instance.OutputFormat("OQRE in {0}", m_udpServer.Scene.Name);
890 MainConsole.Instance.OutputFormat("Running: {0}", m_udpServer.OqrEngine.IsRunning);
891 MainConsole.Instance.OutputFormat(
892 "Requests waiting: {0}",
893 m_udpServer.OqrEngine.IsRunning ? m_udpServer.OqrEngine.JobsWaiting.ToString() : "n/a");
894 }
895 else
896 {
897 MainConsole.Instance.OutputFormat("Unrecognized OQRE subcommand {0}", subCommand);
898 }
899 }
900 }
901} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
new file mode 100644
index 0000000..f62dc15
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
@@ -0,0 +1,504 @@
1/*
2 * Copyright (c) 2006, Clutch, Inc.
3 * Original Author: Jeff Cesnik
4 * All rights reserved.
5 *
6 * - Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * - Redistributions of source code must retain the above copyright notice, this
10 * list of conditions and the following disclaimer.
11 * - Neither the name of the openmetaverse.org nor the names
12 * of its contributors may be used to endorse or promote products derived from
13 * this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Net;
30using System.Net.Sockets;
31using System.Threading;
32using log4net;
33using OpenSim.Framework;
34using OpenSim.Framework.Monitoring;
35
36namespace OpenMetaverse
37{
38 /// <summary>
39 /// Base UDP server
40 /// </summary>
41 public abstract class OpenSimUDPBase
42 {
43 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
44
45 /// <summary>
46 /// This method is called when an incoming packet is received
47 /// </summary>
48 /// <param name="buffer">Incoming packet buffer</param>
49 public abstract void PacketReceived(UDPPacketBuffer buffer);
50
51 /// <summary>UDP port to bind to in server mode</summary>
52 protected int m_udpPort;
53
54 /// <summary>Local IP address to bind to in server mode</summary>
55 protected IPAddress m_localBindAddress;
56
57 /// <summary>UDP socket, used in either client or server mode</summary>
58 private Socket m_udpSocket;
59
60 /// <summary>Flag to process packets asynchronously or synchronously</summary>
61 private bool m_asyncPacketHandling;
62
63 /// <summary>
64 /// Are we to use object pool(s) to reduce memory churn when receiving data?
65 /// </summary>
66 public bool UsePools { get; protected set; }
67
68 /// <summary>
69 /// Pool to use for handling data. May be null if UsePools = false;
70 /// </summary>
71 protected OpenSim.Framework.Pool<UDPPacketBuffer> Pool { get; private set; }
72
73 /// <summary>Returns true if the server is currently listening for inbound packets, otherwise false</summary>
74 public bool IsRunningInbound { get; private set; }
75
76 /// <summary>Returns true if the server is currently sending outbound packets, otherwise false</summary>
77 /// <remarks>If IsRunningOut = false, then any request to send a packet is simply dropped.</remarks>
78 public bool IsRunningOutbound { get; private set; }
79
80 /// <summary>
81 /// Number of UDP receives.
82 /// </summary>
83 public int UdpReceives { get; private set; }
84
85 /// <summary>
86 /// Number of UDP sends
87 /// </summary>
88 public int UdpSends { get; private set; }
89
90 /// <summary>
91 /// Number of receives over which to establish a receive time average.
92 /// </summary>
93 private readonly static int s_receiveTimeSamples = 500;
94
95 /// <summary>
96 /// Current number of samples taken to establish a receive time average.
97 /// </summary>
98 private int m_currentReceiveTimeSamples;
99
100 /// <summary>
101 /// Cumulative receive time for the sample so far.
102 /// </summary>
103 private int m_receiveTicksInCurrentSamplePeriod;
104
105 /// <summary>
106 /// The average time taken for each require receive in the last sample.
107 /// </summary>
108 public float AverageReceiveTicksForLastSamplePeriod { get; private set; }
109
110 #region PacketDropDebugging
111 /// <summary>
112 /// For debugging purposes only... random number generator for dropping
113 /// outbound packets.
114 /// </summary>
115 private Random m_dropRandomGenerator = new Random();
116
117 /// <summary>
118 /// For debugging purposes only... parameters for a simplified
119 /// model of packet loss with bursts, overall drop rate should
120 /// be roughly 1 - m_dropLengthProbability / (m_dropProbabiliy + m_dropLengthProbability)
121 /// which is about 1% for parameters 0.0015 and 0.15
122 /// </summary>
123 private double m_dropProbability = 0.0030;
124 private double m_dropLengthProbability = 0.15;
125 private bool m_dropState = false;
126
127 /// <summary>
128 /// For debugging purposes only... parameters to control the time
129 /// duration over which packet loss bursts can occur, if no packets
130 /// have been sent for m_dropResetTicks milliseconds, then reset the
131 /// state of the packet dropper to its default.
132 /// </summary>
133 private int m_dropLastTick = 0;
134 private int m_dropResetTicks = 500;
135
136 /// <summary>
137 /// Debugging code used to simulate dropped packets with bursts
138 /// </summary>
139 private bool DropOutgoingPacket()
140 {
141 double rnum = m_dropRandomGenerator.NextDouble();
142
143 // if the connection has been idle for awhile (more than m_dropResetTicks) then
144 // reset the state to the default state, don't continue a burst
145 int curtick = Util.EnvironmentTickCount();
146 if (Util.EnvironmentTickCountSubtract(curtick, m_dropLastTick) > m_dropResetTicks)
147 m_dropState = false;
148
149 m_dropLastTick = curtick;
150
151 // if we are dropping packets, then the probability of dropping
152 // this packet is the probability that we stay in the burst
153 if (m_dropState)
154 {
155 m_dropState = (rnum < (1.0 - m_dropLengthProbability)) ? true : false;
156 }
157 else
158 {
159 m_dropState = (rnum < m_dropProbability) ? true : false;
160 }
161
162 return m_dropState;
163 }
164 #endregion PacketDropDebugging
165
166 /// <summary>
167 /// Default constructor
168 /// </summary>
169 /// <param name="bindAddress">Local IP address to bind the server to</param>
170 /// <param name="port">Port to listening for incoming UDP packets on</param>
171 /// /// <param name="usePool">Are we to use an object pool to get objects for handing inbound data?</param>
172 public OpenSimUDPBase(IPAddress bindAddress, int port)
173 {
174 m_localBindAddress = bindAddress;
175 m_udpPort = port;
176
177 // for debugging purposes only, initializes the random number generator
178 // used for simulating packet loss
179 // m_dropRandomGenerator = new Random();
180 }
181
182 /// <summary>
183 /// Start inbound UDP packet handling.
184 /// </summary>
185 /// <param name="recvBufferSize">The size of the receive buffer for
186 /// the UDP socket. This value is passed up to the operating system
187 /// and used in the system networking stack. Use zero to leave this
188 /// value as the default</param>
189 /// <param name="asyncPacketHandling">Set this to true to start
190 /// receiving more packets while current packet handler callbacks are
191 /// still running. Setting this to false will complete each packet
192 /// callback before the next packet is processed</param>
193 /// <remarks>This method will attempt to set the SIO_UDP_CONNRESET flag
194 /// on the socket to get newer versions of Windows to behave in a sane
195 /// manner (not throwing an exception when the remote side resets the
196 /// connection). This call is ignored on Mono where the flag is not
197 /// necessary</remarks>
198 public virtual void StartInbound(int recvBufferSize, bool asyncPacketHandling)
199 {
200 m_asyncPacketHandling = asyncPacketHandling;
201
202 if (!IsRunningInbound)
203 {
204 m_log.DebugFormat("[UDPBASE]: Starting inbound UDP loop");
205
206 const int SIO_UDP_CONNRESET = -1744830452;
207
208 IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort);
209
210 m_log.DebugFormat(
211 "[UDPBASE]: Binding UDP listener using internal IP address config {0}:{1}",
212 ipep.Address, ipep.Port);
213
214 m_udpSocket = new Socket(
215 AddressFamily.InterNetwork,
216 SocketType.Dgram,
217 ProtocolType.Udp);
218
219 try
220 {
221 if (m_udpSocket.Ttl < 128)
222 {
223 m_udpSocket.Ttl = 128;
224 }
225 }
226 catch (SocketException)
227 {
228 m_log.Debug("[UDPBASE]: Failed to increase default TTL");
229 }
230 try
231 {
232 // This udp socket flag is not supported under mono,
233 // so we'll catch the exception and continue
234 m_udpSocket.IOControl(SIO_UDP_CONNRESET, new byte[] { 0 }, null);
235 m_log.Debug("[UDPBASE]: SIO_UDP_CONNRESET flag set");
236 }
237 catch (SocketException)
238 {
239 m_log.Debug("[UDPBASE]: SIO_UDP_CONNRESET flag not supported on this platform, ignoring");
240 }
241
242 // On at least Mono 3.2.8, multiple UDP sockets can bind to the same port by default. At the moment
243 // we never want two regions to listen on the same port as they cannot demultiplex each other's messages,
244 // leading to a confusing bug.
245 // By default, Windows does not allow two sockets to bind to the same port.
246 m_udpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false);
247
248 if (recvBufferSize != 0)
249 m_udpSocket.ReceiveBufferSize = recvBufferSize;
250
251 m_udpSocket.Bind(ipep);
252
253 IsRunningInbound = true;
254
255 // kick off an async receive. The Start() method will return, the
256 // actual receives will occur asynchronously and will be caught in
257 // AsyncEndRecieve().
258 AsyncBeginReceive();
259 }
260 }
261
262 /// <summary>
263 /// Start outbound UDP packet handling.
264 /// </summary>
265 public virtual void StartOutbound()
266 {
267 m_log.DebugFormat("[UDPBASE]: Starting outbound UDP loop");
268
269 IsRunningOutbound = true;
270 }
271
272 public virtual void StopInbound()
273 {
274 if (IsRunningInbound)
275 {
276 m_log.DebugFormat("[UDPBASE]: Stopping inbound UDP loop");
277
278 IsRunningInbound = false;
279 m_udpSocket.Close();
280 }
281 }
282
283 public virtual void StopOutbound()
284 {
285 m_log.DebugFormat("[UDPBASE]: Stopping outbound UDP loop");
286
287 IsRunningOutbound = false;
288 }
289
290 public virtual bool EnablePools()
291 {
292 if (!UsePools)
293 {
294 Pool = new Pool<UDPPacketBuffer>(() => new UDPPacketBuffer(), 500);
295
296 UsePools = true;
297
298 return true;
299 }
300
301 return false;
302 }
303
304 public virtual bool DisablePools()
305 {
306 if (UsePools)
307 {
308 UsePools = false;
309
310 // We won't null out the pool to avoid a race condition with code that may be in the middle of using it.
311
312 return true;
313 }
314
315 return false;
316 }
317
318 private void AsyncBeginReceive()
319 {
320 UDPPacketBuffer buf;
321
322 // FIXME: Disabled for now as this causes issues with reused packet objects interfering with each other
323 // on Windows with m_asyncPacketHandling = true, though this has not been seen on Linux.
324 // Possibly some unexpected issue with fetching UDP data concurrently with multiple threads. Requires more investigation.
325// if (UsePools)
326// buf = Pool.GetObject();
327// else
328 buf = new UDPPacketBuffer();
329
330 if (IsRunningInbound)
331 {
332 try
333 {
334 // kick off an async read
335 m_udpSocket.BeginReceiveFrom(
336 //wrappedBuffer.Instance.Data,
337 buf.Data,
338 0,
339 UDPPacketBuffer.BUFFER_SIZE,
340 SocketFlags.None,
341 ref buf.RemoteEndPoint,
342 AsyncEndReceive,
343 //wrappedBuffer);
344 buf);
345 }
346 catch (SocketException e)
347 {
348 if (e.SocketErrorCode == SocketError.ConnectionReset)
349 {
350 m_log.Warn("[UDPBASE]: SIO_UDP_CONNRESET was ignored, attempting to salvage the UDP listener on port " + m_udpPort);
351 bool salvaged = false;
352 while (!salvaged)
353 {
354 try
355 {
356 m_udpSocket.BeginReceiveFrom(
357 //wrappedBuffer.Instance.Data,
358 buf.Data,
359 0,
360 UDPPacketBuffer.BUFFER_SIZE,
361 SocketFlags.None,
362 ref buf.RemoteEndPoint,
363 AsyncEndReceive,
364 //wrappedBuffer);
365 buf);
366 salvaged = true;
367 }
368 catch (SocketException) { }
369 catch (ObjectDisposedException) { return; }
370 }
371
372 m_log.Warn("[UDPBASE]: Salvaged the UDP listener on port " + m_udpPort);
373 }
374 }
375 catch (ObjectDisposedException e)
376 {
377 m_log.Error(
378 string.Format("[UDPBASE]: Error processing UDP begin receive {0}. Exception ", UdpReceives), e);
379 }
380 catch (Exception e)
381 {
382 m_log.Error(
383 string.Format("[UDPBASE]: Error processing UDP begin receive {0}. Exception ", UdpReceives), e);
384 }
385 }
386 }
387
388 private void AsyncEndReceive(IAsyncResult iar)
389 {
390 // Asynchronous receive operations will complete here through the call
391 // to AsyncBeginReceive
392 if (IsRunningInbound)
393 {
394 UdpReceives++;
395
396 // Asynchronous mode will start another receive before the
397 // callback for this packet is even fired. Very parallel :-)
398 if (m_asyncPacketHandling)
399 AsyncBeginReceive();
400
401 try
402 {
403 // get the buffer that was created in AsyncBeginReceive
404 // this is the received data
405 UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState;
406
407 int startTick = Util.EnvironmentTickCount();
408
409 // get the length of data actually read from the socket, store it with the
410 // buffer
411 buffer.DataLength = m_udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint);
412
413 // call the abstract method PacketReceived(), passing the buffer that
414 // has just been filled from the socket read.
415 PacketReceived(buffer);
416
417 // If more than one thread can be calling AsyncEndReceive() at once (e.g. if m_asyncPacketHandler)
418 // then a particular stat may be inaccurate due to a race condition. We won't worry about this
419 // since this should be rare and won't cause a runtime problem.
420 if (m_currentReceiveTimeSamples >= s_receiveTimeSamples)
421 {
422 AverageReceiveTicksForLastSamplePeriod
423 = (float)m_receiveTicksInCurrentSamplePeriod / s_receiveTimeSamples;
424
425 m_receiveTicksInCurrentSamplePeriod = 0;
426 m_currentReceiveTimeSamples = 0;
427 }
428 else
429 {
430 m_receiveTicksInCurrentSamplePeriod += Util.EnvironmentTickCountSubtract(startTick);
431 m_currentReceiveTimeSamples++;
432 }
433 }
434 catch (SocketException se)
435 {
436 m_log.Error(
437 string.Format(
438 "[UDPBASE]: Error processing UDP end receive {0}, socket error code {1}. Exception ",
439 UdpReceives, se.ErrorCode),
440 se);
441 }
442 catch (ObjectDisposedException e)
443 {
444 m_log.Error(
445 string.Format("[UDPBASE]: Error processing UDP end receive {0}. Exception ", UdpReceives), e);
446 }
447 catch (Exception e)
448 {
449 m_log.Error(
450 string.Format("[UDPBASE]: Error processing UDP end receive {0}. Exception ", UdpReceives), e);
451 }
452 finally
453 {
454// if (UsePools)
455// Pool.ReturnObject(buffer);
456
457 // Synchronous mode waits until the packet callback completes
458 // before starting the receive to fetch another packet
459 if (!m_asyncPacketHandling)
460 AsyncBeginReceive();
461 }
462 }
463 }
464
465 public void AsyncBeginSend(UDPPacketBuffer buf)
466 {
467// if (IsRunningOutbound)
468// {
469
470 // This is strictly for debugging purposes to simulate dropped
471 // packets when testing throttles & retransmission code
472 // if (DropOutgoingPacket())
473 // return;
474
475 try
476 {
477 m_udpSocket.BeginSendTo(
478 buf.Data,
479 0,
480 buf.DataLength,
481 SocketFlags.None,
482 buf.RemoteEndPoint,
483 AsyncEndSend,
484 buf);
485 }
486 catch (SocketException) { }
487 catch (ObjectDisposedException) { }
488// }
489 }
490
491 void AsyncEndSend(IAsyncResult result)
492 {
493 try
494 {
495// UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState;
496 m_udpSocket.EndSendTo(result);
497
498 UdpSends++;
499 }
500 catch (SocketException) { }
501 catch (ObjectDisposedException) { }
502 }
503 }
504} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OutgoingPacket.cs b/OpenSim/Region/ClientStack/Linden/UDP/OutgoingPacket.cs
new file mode 100644
index 0000000..76c6c14
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/OutgoingPacket.cs
@@ -0,0 +1,75 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using OpenSim.Framework;
30using OpenMetaverse;
31
32namespace OpenSim.Region.ClientStack.LindenUDP
33{
34
35 public delegate void UnackedPacketMethod(OutgoingPacket oPacket);
36 /// <summary>
37 /// Holds a reference to the <seealso cref="LLUDPClient"/> this packet is
38 /// destined for, along with the serialized packet data, sequence number
39 /// (if this is a resend), number of times this packet has been resent,
40 /// the time of the last resend, and the throttling category for this
41 /// packet
42 /// </summary>
43 public sealed class OutgoingPacket
44 {
45 /// <summary>Client this packet is destined for</summary>
46 public LLUDPClient Client;
47 /// <summary>Packet data to send</summary>
48 public UDPPacketBuffer Buffer;
49 /// <summary>Sequence number of the wrapped packet</summary>
50 public uint SequenceNumber;
51 /// <summary>Number of times this packet has been resent</summary>
52 public int ResendCount;
53 /// <summary>Environment.TickCount when this packet was last sent over the wire</summary>
54 public int TickCount;
55 /// <summary>Category this packet belongs to</summary>
56 public ThrottleOutPacketType Category;
57 /// <summary>The delegate to be called if this packet is determined to be unacknowledged</summary>
58 public UnackedPacketMethod UnackedMethod;
59
60 /// <summary>
61 /// Default constructor
62 /// </summary>
63 /// <param name="client">Reference to the client this packet is destined for</param>
64 /// <param name="buffer">Serialized packet data. If the flags or sequence number
65 /// need to be updated, they will be injected directly into this binary buffer</param>
66 /// <param name="category">Throttling category for this packet</param>
67 public OutgoingPacket(LLUDPClient client, UDPPacketBuffer buffer, ThrottleOutPacketType category, UnackedPacketMethod method)
68 {
69 Client = client;
70 Buffer = buffer;
71 Category = category;
72 UnackedMethod = method;
73 }
74 }
75}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
new file mode 100644
index 0000000..5a2bcee
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
@@ -0,0 +1,299 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using OpenMetaverse;
32using OpenMetaverse.Packets;
33using log4net;
34using OpenSim.Framework.Monitoring;
35
36namespace OpenSim.Region.ClientStack.LindenUDP
37{
38 public sealed class PacketPool
39 {
40 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
41
42 private static readonly PacketPool instance = new PacketPool();
43
44 /// <summary>
45 /// Pool of packets available for reuse.
46 /// </summary>
47 private readonly Dictionary<PacketType, Stack<Packet>> pool = new Dictionary<PacketType, Stack<Packet>>();
48
49 private static Dictionary<Type, Stack<Object>> DataBlocks = new Dictionary<Type, Stack<Object>>();
50
51 public static PacketPool Instance
52 {
53 get { return instance; }
54 }
55
56 public bool RecyclePackets { get; set; }
57
58 public bool RecycleDataBlocks { get; set; }
59
60 /// <summary>
61 /// The number of packets pooled
62 /// </summary>
63 public int PacketsPooled
64 {
65 get
66 {
67 lock (pool)
68 return pool.Count;
69 }
70 }
71
72 /// <summary>
73 /// The number of blocks pooled.
74 /// </summary>
75 public int BlocksPooled
76 {
77 get
78 {
79 lock (DataBlocks)
80 return DataBlocks.Count;
81 }
82 }
83
84 /// <summary>
85 /// Number of packets requested.
86 /// </summary>
87 public long PacketsRequested { get; private set; }
88
89 /// <summary>
90 /// Number of packets reused.
91 /// </summary>
92 public long PacketsReused { get; private set; }
93
94 /// <summary>
95 /// Number of packet blocks requested.
96 /// </summary>
97 public long BlocksRequested { get; private set; }
98
99 /// <summary>
100 /// Number of packet blocks reused.
101 /// </summary>
102 public long BlocksReused { get; private set; }
103
104 private PacketPool()
105 {
106 // defaults
107 RecyclePackets = true;
108 RecycleDataBlocks = true;
109 }
110
111 /// <summary>
112 /// Gets a packet of the given type.
113 /// </summary>
114 /// <param name='type'></param>
115 /// <returns>Guaranteed to always return a packet, whether from the pool or newly constructed.</returns>
116 public Packet GetPacket(PacketType type)
117 {
118 PacketsRequested++;
119
120 Packet packet;
121
122 if (!RecyclePackets)
123 return Packet.BuildPacket(type);
124
125 lock (pool)
126 {
127 if (!pool.ContainsKey(type) || pool[type] == null || (pool[type]).Count == 0)
128 {
129// m_log.DebugFormat("[PACKETPOOL]: Building {0} packet", type);
130
131 // Creating a new packet if we cannot reuse an old package
132 packet = Packet.BuildPacket(type);
133 }
134 else
135 {
136// m_log.DebugFormat("[PACKETPOOL]: Pulling {0} packet", type);
137
138 // Recycle old packages
139 PacketsReused++;
140
141 packet = pool[type].Pop();
142 }
143 }
144
145 return packet;
146 }
147
148 private static PacketType GetType(byte[] bytes)
149 {
150 ushort id;
151 PacketFrequency freq;
152 bool isZeroCoded = (bytes[0] & Helpers.MSG_ZEROCODED) != 0;
153
154 if (bytes[6] == 0xFF)
155 {
156 if (bytes[7] == 0xFF)
157 {
158 freq = PacketFrequency.Low;
159 if (isZeroCoded && bytes[8] == 0)
160 id = bytes[10];
161 else
162 id = (ushort)((bytes[8] << 8) + bytes[9]);
163 }
164 else
165 {
166 freq = PacketFrequency.Medium;
167 id = bytes[7];
168 }
169 }
170 else
171 {
172 freq = PacketFrequency.High;
173 id = bytes[6];
174 }
175
176 return Packet.GetType(id, freq);
177 }
178
179 public Packet GetPacket(byte[] bytes, ref int packetEnd, byte[] zeroBuffer)
180 {
181 PacketType type = GetType(bytes);
182
183// Array.Clear(zeroBuffer, 0, zeroBuffer.Length);
184
185 int i = 0;
186 Packet packet = GetPacket(type);
187 if (packet == null)
188 m_log.WarnFormat("[PACKETPOOL]: Failed to get packet of type {0}", type);
189 else
190 packet.FromBytes(bytes, ref i, ref packetEnd, zeroBuffer);
191
192 return packet;
193 }
194
195 /// <summary>
196 /// Return a packet to the packet pool
197 /// </summary>
198 /// <param name="packet"></param>
199 public void ReturnPacket(Packet packet)
200 {
201 if (RecycleDataBlocks)
202 {
203 switch (packet.Type)
204 {
205 case PacketType.ObjectUpdate:
206 ObjectUpdatePacket oup = (ObjectUpdatePacket)packet;
207
208 foreach (ObjectUpdatePacket.ObjectDataBlock oupod in oup.ObjectData)
209 ReturnDataBlock<ObjectUpdatePacket.ObjectDataBlock>(oupod);
210
211 oup.ObjectData = null;
212 break;
213
214 case PacketType.ImprovedTerseObjectUpdate:
215 ImprovedTerseObjectUpdatePacket itoup = (ImprovedTerseObjectUpdatePacket)packet;
216
217 foreach (ImprovedTerseObjectUpdatePacket.ObjectDataBlock itoupod in itoup.ObjectData)
218 ReturnDataBlock<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>(itoupod);
219
220 itoup.ObjectData = null;
221 break;
222 }
223 }
224
225 if (RecyclePackets)
226 {
227 switch (packet.Type)
228 {
229 // List pooling packets here
230 case PacketType.AgentUpdate:
231 case PacketType.PacketAck:
232 case PacketType.ObjectUpdate:
233 case PacketType.ImprovedTerseObjectUpdate:
234 lock (pool)
235 {
236 PacketType type = packet.Type;
237
238 if (!pool.ContainsKey(type))
239 {
240 pool[type] = new Stack<Packet>();
241 }
242
243 if ((pool[type]).Count < 50)
244 {
245// m_log.DebugFormat("[PACKETPOOL]: Pushing {0} packet", type);
246
247 pool[type].Push(packet);
248 }
249 }
250 break;
251
252 // Other packets wont pool
253 default:
254 return;
255 }
256 }
257 }
258
259 public T GetDataBlock<T>() where T: new()
260 {
261 lock (DataBlocks)
262 {
263 BlocksRequested++;
264
265 Stack<Object> s;
266
267 if (DataBlocks.TryGetValue(typeof(T), out s))
268 {
269 if (s.Count > 0)
270 {
271 BlocksReused++;
272 return (T)s.Pop();
273 }
274 }
275 else
276 {
277 DataBlocks[typeof(T)] = new Stack<Object>();
278 }
279
280 return new T();
281 }
282 }
283
284 public void ReturnDataBlock<T>(T block) where T: new()
285 {
286 if (block == null)
287 return;
288
289 lock (DataBlocks)
290 {
291 if (!DataBlocks.ContainsKey(typeof(T)))
292 DataBlocks[typeof(T)] = new Stack<Object>();
293
294 if (DataBlocks[typeof(T)].Count < 50)
295 DataBlocks[typeof(T)].Push(block);
296 }
297 }
298 }
299} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs b/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..8795c0c
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs
@@ -0,0 +1,33 @@
1using System.Reflection;
2using System.Runtime.CompilerServices;
3using System.Runtime.InteropServices;
4
5// General Information about an assembly is controlled through the following
6// set of attributes. Change these attribute values to modify the information
7// associated with an assembly.
8[assembly: AssemblyTitle("OpenSim.Region.ClientStack.LindenUDP")]
9[assembly: AssemblyDescription("")]
10[assembly: AssemblyConfiguration("")]
11[assembly: AssemblyCompany("http://opensimulator.org")]
12[assembly: AssemblyProduct("OpenSim")]
13[assembly: AssemblyCopyright("OpenSimulator developers")]
14[assembly: AssemblyTrademark("")]
15[assembly: AssemblyCulture("")]
16
17// Setting ComVisible to false makes the types in this assembly not visible
18// to COM components. If you need to access a type in this assembly from
19// COM, set the ComVisible attribute to true on that type.
20[assembly: ComVisible(false)]
21
22// The following GUID is for the ID of the typelib if this project is exposed to COM
23[assembly: Guid("9d3dbc6b-9d85-483b-af48-c1dfc261b7ac")]
24
25// Version information for an assembly consists of the following four values:
26//
27// Major Version
28// Minor Version
29// Build Number
30// Revision
31//
32[assembly: AssemblyVersion("0.8.2.*")]
33
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs
new file mode 100644
index 0000000..a935dd2
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs
@@ -0,0 +1,272 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Net;
30using log4net.Config;
31using Nini.Config;
32using NUnit.Framework;
33using OpenMetaverse;
34using OpenMetaverse.Packets;
35using OpenSim.Framework;
36using OpenSim.Framework.Monitoring;
37using OpenSim.Region.Framework.Scenes;
38using OpenSim.Tests.Common;
39
40namespace OpenSim.Region.ClientStack.LindenUDP.Tests
41{
42 /// <summary>
43 /// This will contain basic tests for the LindenUDP client stack
44 /// </summary>
45 [TestFixture]
46 public class BasicCircuitTests : OpenSimTestCase
47 {
48 private Scene m_scene;
49
50 [TestFixtureSetUp]
51 public void FixtureInit()
52 {
53 // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
54 Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest;
55 }
56
57 [TestFixtureTearDown]
58 public void TearDown()
59 {
60 // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
61 // threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression
62 // tests really shouldn't).
63 Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
64 }
65
66 [SetUp]
67 public override void SetUp()
68 {
69 base.SetUp();
70 m_scene = new SceneHelpers().SetupScene();
71 StatsManager.SimExtraStats = new SimExtraStatsCollector();
72 }
73
74// /// <summary>
75// /// Build an object name packet for test purposes
76// /// </summary>
77// /// <param name="objectLocalId"></param>
78// /// <param name="objectName"></param>
79// private ObjectNamePacket BuildTestObjectNamePacket(uint objectLocalId, string objectName)
80// {
81// ObjectNamePacket onp = new ObjectNamePacket();
82// ObjectNamePacket.ObjectDataBlock odb = new ObjectNamePacket.ObjectDataBlock();
83// odb.LocalID = objectLocalId;
84// odb.Name = Utils.StringToBytes(objectName);
85// onp.ObjectData = new ObjectNamePacket.ObjectDataBlock[] { odb };
86// onp.Header.Zerocoded = false;
87//
88// return onp;
89// }
90//
91 /// <summary>
92 /// Test adding a client to the stack
93 /// </summary>
94 [Test]
95 public void TestAddClient()
96 {
97 TestHelpers.InMethod();
98// TestHelpers.EnableLogging();
99
100 TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(m_scene);
101
102 UUID myAgentUuid = TestHelpers.ParseTail(0x1);
103 UUID mySessionUuid = TestHelpers.ParseTail(0x2);
104 uint myCircuitCode = 123456;
105 IPEndPoint testEp = new IPEndPoint(IPAddress.Loopback, 999);
106
107 UseCircuitCodePacket uccp = new UseCircuitCodePacket();
108
109 UseCircuitCodePacket.CircuitCodeBlock uccpCcBlock
110 = new UseCircuitCodePacket.CircuitCodeBlock();
111 uccpCcBlock.Code = myCircuitCode;
112 uccpCcBlock.ID = myAgentUuid;
113 uccpCcBlock.SessionID = mySessionUuid;
114 uccp.CircuitCode = uccpCcBlock;
115
116 byte[] uccpBytes = uccp.ToBytes();
117 UDPPacketBuffer upb = new UDPPacketBuffer(testEp, uccpBytes.Length);
118 upb.DataLength = uccpBytes.Length; // God knows why this isn't set by the constructor.
119 Buffer.BlockCopy(uccpBytes, 0, upb.Data, 0, uccpBytes.Length);
120
121 udpServer.PacketReceived(upb);
122
123 // Presence shouldn't exist since the circuit manager doesn't know about this circuit for authentication yet
124 Assert.That(m_scene.GetScenePresence(myAgentUuid), Is.Null);
125
126 AgentCircuitData acd = new AgentCircuitData();
127 acd.AgentID = myAgentUuid;
128 acd.SessionID = mySessionUuid;
129
130 m_scene.AuthenticateHandler.AddNewCircuit(myCircuitCode, acd);
131
132 udpServer.PacketReceived(upb);
133
134 // Should succeed now
135 ScenePresence sp = m_scene.GetScenePresence(myAgentUuid);
136 Assert.That(sp.UUID, Is.EqualTo(myAgentUuid));
137
138 Assert.That(udpServer.PacketsSent.Count, Is.EqualTo(1));
139
140 Packet packet = udpServer.PacketsSent[0];
141 Assert.That(packet, Is.InstanceOf(typeof(PacketAckPacket)));
142
143 PacketAckPacket ackPacket = packet as PacketAckPacket;
144 Assert.That(ackPacket.Packets.Length, Is.EqualTo(1));
145 Assert.That(ackPacket.Packets[0].ID, Is.EqualTo(0));
146 }
147
148 [Test]
149 public void TestLogoutClientDueToAck()
150 {
151 TestHelpers.InMethod();
152// TestHelpers.EnableLogging();
153
154 IniConfigSource ics = new IniConfigSource();
155 IConfig config = ics.AddConfig("ClientStack.LindenUDP");
156 config.Set("AckTimeout", -1);
157 TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(m_scene, ics);
158
159 ScenePresence sp
160 = ClientStackHelpers.AddChildClient(
161 m_scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456);
162
163 udpServer.ClientOutgoingPacketHandler(sp.ControllingClient, true, false, false);
164
165 ScenePresence spAfterAckTimeout = m_scene.GetScenePresence(sp.UUID);
166 Assert.That(spAfterAckTimeout, Is.Null);
167 }
168
169// /// <summary>
170// /// Test removing a client from the stack
171// /// </summary>
172// [Test]
173// public void TestRemoveClient()
174// {
175// TestHelper.InMethod();
176//
177// uint myCircuitCode = 123457;
178//
179// TestLLUDPServer testLLUDPServer;
180// TestLLPacketServer testLLPacketServer;
181// AgentCircuitManager acm;
182// SetupStack(new MockScene(), out testLLUDPServer, out testLLPacketServer, out acm);
183// AddClient(myCircuitCode, new IPEndPoint(IPAddress.Loopback, 1000), testLLUDPServer, acm);
184//
185// testLLUDPServer.RemoveClientCircuit(myCircuitCode);
186// Assert.IsFalse(testLLUDPServer.HasCircuit(myCircuitCode));
187//
188// // Check that removing a non-existent circuit doesn't have any bad effects
189// testLLUDPServer.RemoveClientCircuit(101);
190// Assert.IsFalse(testLLUDPServer.HasCircuit(101));
191// }
192//
193// /// <summary>
194// /// Make sure that the client stack reacts okay to malformed packets
195// /// </summary>
196// [Test]
197// public void TestMalformedPacketSend()
198// {
199// TestHelper.InMethod();
200//
201// uint myCircuitCode = 123458;
202// EndPoint testEp = new IPEndPoint(IPAddress.Loopback, 1001);
203// MockScene scene = new MockScene();
204//
205// TestLLUDPServer testLLUDPServer;
206// TestLLPacketServer testLLPacketServer;
207// AgentCircuitManager acm;
208// SetupStack(scene, out testLLUDPServer, out testLLPacketServer, out acm);
209// AddClient(myCircuitCode, testEp, testLLUDPServer, acm);
210//
211// byte[] data = new byte[] { 0x01, 0x02, 0x03, 0x04 };
212//
213// // Send two garbled 'packets' in succession
214// testLLUDPServer.LoadReceive(data, testEp);
215// testLLUDPServer.LoadReceive(data, testEp);
216// testLLUDPServer.ReceiveData(null);
217//
218// // Check that we are still here
219// Assert.IsTrue(testLLUDPServer.HasCircuit(myCircuitCode));
220// Assert.That(testLLPacketServer.GetTotalPacketsReceived(), Is.EqualTo(0));
221//
222// // Check that sending a valid packet to same circuit still succeeds
223// Assert.That(scene.ObjectNameCallsReceived, Is.EqualTo(0));
224//
225// testLLUDPServer.LoadReceive(BuildTestObjectNamePacket(1, "helloooo"), testEp);
226// testLLUDPServer.ReceiveData(null);
227//
228// Assert.That(testLLPacketServer.GetTotalPacketsReceived(), Is.EqualTo(1));
229// Assert.That(testLLPacketServer.GetPacketsReceivedFor(PacketType.ObjectName), Is.EqualTo(1));
230// }
231//
232// /// <summary>
233// /// Test that the stack continues to work even if some client has caused a
234// /// SocketException on Socket.BeginReceive()
235// /// </summary>
236// [Test]
237// public void TestExceptionOnBeginReceive()
238// {
239// TestHelper.InMethod();
240//
241// MockScene scene = new MockScene();
242//
243// uint circuitCodeA = 130000;
244// EndPoint epA = new IPEndPoint(IPAddress.Loopback, 1300);
245// UUID agentIdA = UUID.Parse("00000000-0000-0000-0000-000000001300");
246// UUID sessionIdA = UUID.Parse("00000000-0000-0000-0000-000000002300");
247//
248// uint circuitCodeB = 130001;
249// EndPoint epB = new IPEndPoint(IPAddress.Loopback, 1301);
250// UUID agentIdB = UUID.Parse("00000000-0000-0000-0000-000000001301");
251// UUID sessionIdB = UUID.Parse("00000000-0000-0000-0000-000000002301");
252//
253// TestLLUDPServer testLLUDPServer;
254// TestLLPacketServer testLLPacketServer;
255// AgentCircuitManager acm;
256// SetupStack(scene, out testLLUDPServer, out testLLPacketServer, out acm);
257// AddClient(circuitCodeA, epA, agentIdA, sessionIdA, testLLUDPServer, acm);
258// AddClient(circuitCodeB, epB, agentIdB, sessionIdB, testLLUDPServer, acm);
259//
260// testLLUDPServer.LoadReceive(BuildTestObjectNamePacket(1, "packet1"), epA);
261// testLLUDPServer.LoadReceive(BuildTestObjectNamePacket(1, "packet2"), epB);
262// testLLUDPServer.LoadReceiveWithBeginException(epA);
263// testLLUDPServer.LoadReceive(BuildTestObjectNamePacket(2, "packet3"), epB);
264// testLLUDPServer.ReceiveData(null);
265//
266// Assert.IsFalse(testLLUDPServer.HasCircuit(circuitCodeA));
267//
268// Assert.That(testLLPacketServer.GetTotalPacketsReceived(), Is.EqualTo(3));
269// Assert.That(testLLPacketServer.GetPacketsReceivedFor(PacketType.ObjectName), Is.EqualTo(3));
270// }
271 }
272}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs
new file mode 100644
index 0000000..6c57e6d
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs
@@ -0,0 +1,174 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.IO;
30using System.Net;
31using System.Reflection;
32using System.Threading;
33using log4net.Config;
34using Nini.Config;
35using NUnit.Framework;
36using OpenMetaverse;
37using OpenMetaverse.Packets;
38using OpenSim.Framework;
39using OpenSim.Region.CoreModules.Agent.TextureSender;
40using OpenSim.Region.Framework.Scenes;
41using OpenSim.Tests.Common;
42
43namespace OpenSim.Region.ClientStack.LindenUDP.Tests
44{
45 [TestFixture]
46 public class LLImageManagerTests : OpenSimTestCase
47 {
48 private AssetBase m_testImageAsset;
49 private Scene scene;
50 private LLImageManager llim;
51 private TestClient tc;
52
53 [TestFixtureSetUp]
54 public void FixtureInit()
55 {
56 // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
57 Util.FireAndForgetMethod = FireAndForgetMethod.None;
58
59 using (
60 Stream resource
61 = GetType().Assembly.GetManifestResourceStream(
62 "OpenSim.Region.ClientStack.LindenUDP.Tests.Resources.4-tile2.jp2"))
63 {
64 using (BinaryReader br = new BinaryReader(resource))
65 {
66 m_testImageAsset
67 = new AssetBase(
68 TestHelpers.ParseTail(0x1),
69 "Test Image",
70 (sbyte)AssetType.Texture,
71 TestHelpers.ParseTail(0x2).ToString());
72
73 m_testImageAsset.Data = br.ReadBytes(99999999);
74 }
75 }
76 }
77
78 [TestFixtureTearDown]
79 public void TearDown()
80 {
81 // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
82 // threads. Possibly, later tests should be rewritten not to worry about such things.
83 Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
84 }
85
86 [SetUp]
87 public override void SetUp()
88 {
89 base.SetUp();
90
91 UUID userId = TestHelpers.ParseTail(0x3);
92
93 J2KDecoderModule j2kdm = new J2KDecoderModule();
94
95 SceneHelpers sceneHelpers = new SceneHelpers();
96 scene = sceneHelpers.SetupScene();
97 SceneHelpers.SetupSceneModules(scene, j2kdm);
98
99 tc = new TestClient(SceneHelpers.GenerateAgentData(userId), scene);
100 llim = new LLImageManager(tc, scene.AssetService, j2kdm);
101 }
102
103 [Test]
104 public void TestSendImage()
105 {
106 TestHelpers.InMethod();
107// XmlConfigurator.Configure();
108
109 scene.AssetService.Store(m_testImageAsset);
110
111 TextureRequestArgs args = new TextureRequestArgs();
112 args.RequestedAssetID = m_testImageAsset.FullID;
113 args.DiscardLevel = 0;
114 args.PacketNumber = 1;
115 args.Priority = 5;
116 args.requestSequence = 1;
117
118 llim.EnqueueReq(args);
119 llim.ProcessImageQueue(20);
120
121 Assert.That(tc.SentImageDataPackets.Count, Is.EqualTo(1));
122 }
123
124 [Test]
125 public void TestDiscardImage()
126 {
127 TestHelpers.InMethod();
128// XmlConfigurator.Configure();
129
130 scene.AssetService.Store(m_testImageAsset);
131
132 TextureRequestArgs args = new TextureRequestArgs();
133 args.RequestedAssetID = m_testImageAsset.FullID;
134 args.DiscardLevel = 0;
135 args.PacketNumber = 1;
136 args.Priority = 5;
137 args.requestSequence = 1;
138 llim.EnqueueReq(args);
139
140 // Now create a discard request
141 TextureRequestArgs discardArgs = new TextureRequestArgs();
142 discardArgs.RequestedAssetID = m_testImageAsset.FullID;
143 discardArgs.DiscardLevel = -1;
144 discardArgs.PacketNumber = 1;
145 discardArgs.Priority = 0;
146 discardArgs.requestSequence = 2;
147 llim.EnqueueReq(discardArgs);
148
149 llim.ProcessImageQueue(20);
150
151 Assert.That(tc.SentImageDataPackets.Count, Is.EqualTo(0));
152 }
153
154 [Test]
155 public void TestMissingImage()
156 {
157 TestHelpers.InMethod();
158// XmlConfigurator.Configure();
159
160 TextureRequestArgs args = new TextureRequestArgs();
161 args.RequestedAssetID = m_testImageAsset.FullID;
162 args.DiscardLevel = 0;
163 args.PacketNumber = 1;
164 args.Priority = 5;
165 args.requestSequence = 1;
166
167 llim.EnqueueReq(args);
168 llim.ProcessImageQueue(20);
169
170 Assert.That(tc.SentImageDataPackets.Count, Is.EqualTo(0));
171 Assert.That(tc.SentImageNotInDatabasePackets.Count, Is.EqualTo(1));
172 }
173 }
174} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs
new file mode 100644
index 0000000..92f1fc3
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs
@@ -0,0 +1,104 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using Nini.Config;
29using NUnit.Framework;
30using OpenMetaverse;
31using OpenMetaverse.Packets;
32using OpenSim.Framework;
33using OpenSim.Tests.Common;
34
35namespace OpenSim.Region.ClientStack.LindenUDP.Tests
36{
37 /// <summary>
38 /// Tests for the LL packet handler
39 /// </summary>
40 [TestFixture]
41 public class PacketHandlerTests : OpenSimTestCase
42 {
43// [Test]
44// /// <summary>
45// /// More a placeholder, really
46// /// </summary>
47// public void InPacketTest()
48// {
49// TestHelper.InMethod();
50//
51// AgentCircuitData agent = new AgentCircuitData();
52// agent.AgentID = UUID.Random();
53// agent.firstname = "testfirstname";
54// agent.lastname = "testlastname";
55// agent.SessionID = UUID.Zero;
56// agent.SecureSessionID = UUID.Zero;
57// agent.circuitcode = 123;
58// agent.BaseFolder = UUID.Zero;
59// agent.InventoryFolder = UUID.Zero;
60// agent.startpos = Vector3.Zero;
61// agent.CapsPath = "http://wibble.com";
62//
63// TestLLUDPServer testLLUDPServer;
64// TestLLPacketServer testLLPacketServer;
65// AgentCircuitManager acm;
66// IScene scene = new MockScene();
67// SetupStack(scene, out testLLUDPServer, out testLLPacketServer, out acm);
68//
69// TestClient testClient = new TestClient(agent, scene);
70//
71// LLPacketHandler packetHandler
72// = new LLPacketHandler(testClient, testLLPacketServer, new ClientStackUserSettings());
73//
74// packetHandler.InPacket(new AgentAnimationPacket());
75// LLQueItem receivedPacket = packetHandler.PacketQueue.Dequeue();
76//
77// Assert.That(receivedPacket, Is.Not.Null);
78// Assert.That(receivedPacket.Incoming, Is.True);
79// Assert.That(receivedPacket.Packet, Is.TypeOf(typeof(AgentAnimationPacket)));
80// }
81//
82// /// <summary>
83// /// Add a client for testing
84// /// </summary>
85// /// <param name="scene"></param>
86// /// <param name="testLLUDPServer"></param>
87// /// <param name="testPacketServer"></param>
88// /// <param name="acm">Agent circuit manager used in setting up the stack</param>
89// protected void SetupStack(
90// IScene scene, out TestLLUDPServer testLLUDPServer, out TestLLPacketServer testPacketServer,
91// out AgentCircuitManager acm)
92// {
93// IConfigSource configSource = new IniConfigSource();
94// ClientStackUserSettings userSettings = new ClientStackUserSettings();
95// testLLUDPServer = new TestLLUDPServer();
96// acm = new AgentCircuitManager();
97//
98// uint port = 666;
99// testLLUDPServer.Initialise(null, ref port, 0, false, configSource, acm);
100// testPacketServer = new TestLLPacketServer(testLLUDPServer, userSettings);
101// testLLUDPServer.LocalScene = scene;
102// }
103 }
104}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/Resources/4-tile2.jp2 b/OpenSim/Region/ClientStack/Linden/UDP/Tests/Resources/4-tile2.jp2
new file mode 100644
index 0000000..8c63104
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/Resources/4-tile2.jp2
Binary files differ
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs
new file mode 100644
index 0000000..3c82a78
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs
@@ -0,0 +1,427 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using Nini.Config;
30using NUnit.Framework;
31using OpenMetaverse.Packets;
32using OpenSim.Framework;
33using OpenSim.Region.Framework.Scenes;
34using OpenSim.Tests.Common;
35
36namespace OpenSim.Region.ClientStack.LindenUDP.Tests
37{
38 [TestFixture]
39 public class ThrottleTests : OpenSimTestCase
40 {
41 [TestFixtureSetUp]
42 public void FixtureInit()
43 {
44 // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
45 Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest;
46 }
47
48 [TestFixtureTearDown]
49 public void TearDown()
50 {
51 // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
52 // threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression
53 // tests really shouldn't).
54 Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
55 }
56
57 [Test]
58 public void TestSetRequestDripRate()
59 {
60 TestHelpers.InMethod();
61
62 TokenBucket tb = new TokenBucket("tb", null, 5000, 0);
63 AssertRates(tb, 5000, 0, 5000, 0);
64
65 tb.RequestedDripRate = 4000;
66 AssertRates(tb, 4000, 0, 4000, 0);
67
68 tb.RequestedDripRate = 6000;
69 AssertRates(tb, 6000, 0, 6000, 0);
70 }
71
72 [Test]
73 public void TestSetRequestDripRateWithMax()
74 {
75 TestHelpers.InMethod();
76
77 TokenBucket tb = new TokenBucket("tb", null, 5000, 10000);
78 AssertRates(tb, 5000, 0, 5000, 10000);
79
80 tb.RequestedDripRate = 4000;
81 AssertRates(tb, 4000, 0, 4000, 10000);
82
83 tb.RequestedDripRate = 6000;
84 AssertRates(tb, 6000, 0, 6000, 10000);
85
86 tb.RequestedDripRate = 12000;
87 AssertRates(tb, 10000, 0, 10000, 10000);
88 }
89
90 [Test]
91 public void TestSetRequestDripRateWithChildren()
92 {
93 TestHelpers.InMethod();
94
95 TokenBucket tbParent = new TokenBucket("tbParent", null, 0, 0);
96 TokenBucket tbChild1 = new TokenBucket("tbChild1", tbParent, 3000, 0);
97 TokenBucket tbChild2 = new TokenBucket("tbChild2", tbParent, 5000, 0);
98
99 AssertRates(tbParent, 8000, 8000, 8000, 0);
100 AssertRates(tbChild1, 3000, 0, 3000, 0);
101 AssertRates(tbChild2, 5000, 0, 5000, 0);
102
103 // Test: Setting a parent request greater than total children requests.
104 tbParent.RequestedDripRate = 10000;
105
106 AssertRates(tbParent, 10000, 8000, 8000, 0);
107 AssertRates(tbChild1, 3000, 0, 3000, 0);
108 AssertRates(tbChild2, 5000, 0, 5000, 0);
109
110 // Test: Setting a parent request lower than total children requests.
111 tbParent.RequestedDripRate = 6000;
112
113 AssertRates(tbParent, 6000, 8000, 6000, 0);
114 AssertRates(tbChild1, 3000, 0, 6000 / 8 * 3, 0);
115 AssertRates(tbChild2, 5000, 0, 6000 / 8 * 5, 0);
116 }
117
118 private void AssertRates(
119 TokenBucket tb, double requestedDripRate, double totalDripRequest, double dripRate, double maxDripRate)
120 {
121 Assert.AreEqual((int)requestedDripRate, tb.RequestedDripRate, "Requested drip rate");
122 Assert.AreEqual((int)totalDripRequest, tb.TotalDripRequest, "Total drip request");
123 Assert.AreEqual((int)dripRate, tb.DripRate, "Drip rate");
124 Assert.AreEqual((int)maxDripRate, tb.MaxDripRate, "Max drip rate");
125 }
126
127 [Test]
128 public void TestClientThrottleSetNoLimit()
129 {
130 TestHelpers.InMethod();
131// TestHelpers.EnableLogging();
132
133 Scene scene = new SceneHelpers().SetupScene();
134 TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene);
135
136 ScenePresence sp
137 = ClientStackHelpers.AddChildClient(
138 scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456);
139
140 LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
141
142 udpServer.Throttle.DebugLevel = 1;
143 udpClient.ThrottleDebugLevel = 1;
144
145 int resendBytes = 1000;
146 int landBytes = 2000;
147 int windBytes = 3000;
148 int cloudBytes = 4000;
149 int taskBytes = 5000;
150 int textureBytes = 6000;
151 int assetBytes = 7000;
152
153 SetThrottles(
154 udpClient, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes);
155
156 // We expect this to be lower because of the minimum bound set by MTU
157 int totalBytes = LLUDPServer.MTU + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes;
158
159 AssertThrottles(
160 udpClient,
161 LLUDPServer.MTU, landBytes, windBytes, cloudBytes, taskBytes,
162 textureBytes, assetBytes, totalBytes, 0, 0);
163 }
164
165 [Test]
166 public void TestClientThrottleAdaptiveNoLimit()
167 {
168 TestHelpers.InMethod();
169// TestHelpers.EnableLogging();
170
171 Scene scene = new SceneHelpers().SetupScene();
172
173 IniConfigSource ics = new IniConfigSource();
174 IConfig config = ics.AddConfig("ClientStack.LindenUDP");
175 config.Set("enable_adaptive_throttles", true);
176 config.Set("adaptive_throttle_min_bps", 32000);
177
178 TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene, ics);
179
180 ScenePresence sp
181 = ClientStackHelpers.AddChildClient(
182 scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456);
183
184 LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
185
186 udpServer.Throttle.DebugLevel = 1;
187 udpClient.ThrottleDebugLevel = 1;
188
189 // Total is 275000
190 int resendBytes = 5000; // this is set low to test the minimum throttle override
191 int landBytes = 20000;
192 int windBytes = 30000;
193 int cloudBytes = 40000;
194 int taskBytes = 50000;
195 int textureBytes = 60000;
196 int assetBytes = 70000;
197 int totalBytes = resendBytes + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes;
198
199 SetThrottles(
200 udpClient, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes);
201
202 // Ratio of current adaptive drip rate to requested bytes, minimum rate is 32000
203 double commitRatio = 32000.0 / totalBytes;
204
205 AssertThrottles(
206 udpClient,
207 LLUDPServer.MTU, landBytes * commitRatio, windBytes * commitRatio, cloudBytes * commitRatio, taskBytes * commitRatio,
208 textureBytes * commitRatio, assetBytes * commitRatio, udpClient.FlowThrottle.AdjustedDripRate, totalBytes, 0);
209
210 // Test an increase in target throttle, ack of 20 packets adds 20 * LLUDPServer.MTU bytes
211 // to the throttle, recompute commitratio from those numbers
212 udpClient.FlowThrottle.AcknowledgePackets(20);
213 commitRatio = (32000.0 + 20.0 * LLUDPServer.MTU) / totalBytes;
214
215 AssertThrottles(
216 udpClient,
217 LLUDPServer.MTU, landBytes * commitRatio, windBytes * commitRatio, cloudBytes * commitRatio, taskBytes * commitRatio,
218 textureBytes * commitRatio, assetBytes * commitRatio, udpClient.FlowThrottle.AdjustedDripRate, totalBytes, 0);
219
220 // Test a decrease in target throttle, adaptive throttle should cut the rate by 50% with a floor
221 // set by the minimum adaptive rate
222 udpClient.FlowThrottle.ExpirePackets(1);
223 commitRatio = (32000.0 + (20.0 * LLUDPServer.MTU)/Math.Pow(2,1)) / totalBytes;
224
225 AssertThrottles(
226 udpClient,
227 LLUDPServer.MTU, landBytes * commitRatio, windBytes * commitRatio, cloudBytes * commitRatio, taskBytes * commitRatio,
228 textureBytes * commitRatio, assetBytes * commitRatio, udpClient.FlowThrottle.AdjustedDripRate, totalBytes, 0);
229 }
230
231 /// <summary>
232 /// Test throttle setttings where max client throttle has been limited server side.
233 /// </summary>
234 [Test]
235 public void TestSingleClientThrottleRegionLimited()
236 {
237 TestHelpers.InMethod();
238 // TestHelpers.EnableLogging();
239
240 int resendBytes = 6000;
241 int landBytes = 8000;
242 int windBytes = 10000;
243 int cloudBytes = 12000;
244 int taskBytes = 14000;
245 int textureBytes = 16000;
246 int assetBytes = 18000;
247 int totalBytes
248 = (int)((resendBytes + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes) / 2);
249
250 Scene scene = new SceneHelpers().SetupScene();
251 TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene);
252 udpServer.Throttle.RequestedDripRate = totalBytes;
253
254 ScenePresence sp1
255 = ClientStackHelpers.AddChildClient(
256 scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456);
257
258 LLUDPClient udpClient1 = ((LLClientView)sp1.ControllingClient).UDPClient;
259
260 SetThrottles(
261 udpClient1, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes);
262
263 AssertThrottles(
264 udpClient1,
265 resendBytes / 2, landBytes / 2, windBytes / 2, cloudBytes / 2, taskBytes / 2,
266 textureBytes / 2, assetBytes / 2, totalBytes, 0, 0);
267
268 // Test: Now add another client
269 ScenePresence sp2
270 = ClientStackHelpers.AddChildClient(
271 scene, udpServer, TestHelpers.ParseTail(0x10), TestHelpers.ParseTail(0x20), 123457);
272
273 LLUDPClient udpClient2 = ((LLClientView)sp2.ControllingClient).UDPClient;
274 // udpClient.ThrottleDebugLevel = 1;
275
276 SetThrottles(
277 udpClient2, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes);
278
279 AssertThrottles(
280 udpClient1,
281 resendBytes / 4, landBytes / 4, windBytes / 4, cloudBytes / 4, taskBytes / 4,
282 textureBytes / 4, assetBytes / 4, totalBytes / 2, 0, 0);
283
284 AssertThrottles(
285 udpClient2,
286 resendBytes / 4, landBytes / 4, windBytes / 4, cloudBytes / 4, taskBytes / 4,
287 textureBytes / 4, assetBytes / 4, totalBytes / 2, 0, 0);
288 }
289
290 /// <summary>
291 /// Test throttle setttings where max client throttle has been limited server side.
292 /// </summary>
293 [Test]
294 public void TestClientThrottlePerClientLimited()
295 {
296 TestHelpers.InMethod();
297 // TestHelpers.EnableLogging();
298
299 int resendBytes = 4000;
300 int landBytes = 6000;
301 int windBytes = 8000;
302 int cloudBytes = 10000;
303 int taskBytes = 12000;
304 int textureBytes = 14000;
305 int assetBytes = 16000;
306 int totalBytes
307 = (int)((resendBytes + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes) / 2);
308
309 Scene scene = new SceneHelpers().SetupScene();
310 TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene);
311 udpServer.ThrottleRates.Total = totalBytes;
312
313 ScenePresence sp
314 = ClientStackHelpers.AddChildClient(
315 scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456);
316
317 LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
318 // udpClient.ThrottleDebugLevel = 1;
319
320 SetThrottles(
321 udpClient, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes);
322
323 AssertThrottles(
324 udpClient,
325 resendBytes / 2, landBytes / 2, windBytes / 2, cloudBytes / 2, taskBytes / 2,
326 textureBytes / 2, assetBytes / 2, totalBytes, 0, totalBytes);
327 }
328
329 [Test]
330 public void TestClientThrottlePerClientAndRegionLimited()
331 {
332 TestHelpers.InMethod();
333 //TestHelpers.EnableLogging();
334
335 int resendBytes = 4000;
336 int landBytes = 6000;
337 int windBytes = 8000;
338 int cloudBytes = 10000;
339 int taskBytes = 12000;
340 int textureBytes = 14000;
341 int assetBytes = 16000;
342
343 // current total 70000
344 int totalBytes = resendBytes + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes;
345
346 Scene scene = new SceneHelpers().SetupScene();
347 TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene);
348 udpServer.ThrottleRates.Total = (int)(totalBytes * 1.1);
349 udpServer.Throttle.RequestedDripRate = (int)(totalBytes * 1.5);
350
351 ScenePresence sp1
352 = ClientStackHelpers.AddChildClient(
353 scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456);
354
355 LLUDPClient udpClient1 = ((LLClientView)sp1.ControllingClient).UDPClient;
356 udpClient1.ThrottleDebugLevel = 1;
357
358 SetThrottles(
359 udpClient1, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes);
360
361 AssertThrottles(
362 udpClient1,
363 resendBytes, landBytes, windBytes, cloudBytes, taskBytes,
364 textureBytes, assetBytes, totalBytes, 0, totalBytes * 1.1);
365
366 // Now add another client
367 ScenePresence sp2
368 = ClientStackHelpers.AddChildClient(
369 scene, udpServer, TestHelpers.ParseTail(0x10), TestHelpers.ParseTail(0x20), 123457);
370
371 LLUDPClient udpClient2 = ((LLClientView)sp2.ControllingClient).UDPClient;
372 udpClient2.ThrottleDebugLevel = 1;
373
374 SetThrottles(
375 udpClient2, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes);
376
377 AssertThrottles(
378 udpClient1,
379 resendBytes * 0.75, landBytes * 0.75, windBytes * 0.75, cloudBytes * 0.75, taskBytes * 0.75,
380 textureBytes * 0.75, assetBytes * 0.75, totalBytes * 0.75, 0, totalBytes * 1.1);
381
382 AssertThrottles(
383 udpClient2,
384 resendBytes * 0.75, landBytes * 0.75, windBytes * 0.75, cloudBytes * 0.75, taskBytes * 0.75,
385 textureBytes * 0.75, assetBytes * 0.75, totalBytes * 0.75, 0, totalBytes * 1.1);
386 }
387
388 private void AssertThrottles(
389 LLUDPClient udpClient,
390 double resendBytes, double landBytes, double windBytes, double cloudBytes, double taskBytes, double textureBytes, double assetBytes,
391 double totalBytes, double targetBytes, double maxBytes)
392 {
393 ClientInfo ci = udpClient.GetClientInfo();
394
395// Console.WriteLine(
396// "Resend={0}, Land={1}, Wind={2}, Cloud={3}, Task={4}, Texture={5}, Asset={6}, TOTAL = {7}",
397// ci.resendThrottle, ci.landThrottle, ci.windThrottle, ci.cloudThrottle, ci.taskThrottle, ci.textureThrottle, ci.assetThrottle, ci.totalThrottle);
398
399 Assert.AreEqual((int)resendBytes, ci.resendThrottle, "Resend");
400 Assert.AreEqual((int)landBytes, ci.landThrottle, "Land");
401 Assert.AreEqual((int)windBytes, ci.windThrottle, "Wind");
402 Assert.AreEqual((int)cloudBytes, ci.cloudThrottle, "Cloud");
403 Assert.AreEqual((int)taskBytes, ci.taskThrottle, "Task");
404 Assert.AreEqual((int)textureBytes, ci.textureThrottle, "Texture");
405 Assert.AreEqual((int)assetBytes, ci.assetThrottle, "Asset");
406 Assert.AreEqual((int)totalBytes, ci.totalThrottle, "Total");
407 Assert.AreEqual((int)targetBytes, ci.targetThrottle, "Target");
408 Assert.AreEqual((int)maxBytes, ci.maxThrottle, "Max");
409 }
410
411 private void SetThrottles(
412 LLUDPClient udpClient, int resendBytes, int landBytes, int windBytes, int cloudBytes, int taskBytes, int textureBytes, int assetBytes)
413 {
414 byte[] throttles = new byte[28];
415
416 Array.Copy(BitConverter.GetBytes((float)resendBytes * 8), 0, throttles, 0, 4);
417 Array.Copy(BitConverter.GetBytes((float)landBytes * 8), 0, throttles, 4, 4);
418 Array.Copy(BitConverter.GetBytes((float)windBytes * 8), 0, throttles, 8, 4);
419 Array.Copy(BitConverter.GetBytes((float)cloudBytes * 8), 0, throttles, 12, 4);
420 Array.Copy(BitConverter.GetBytes((float)taskBytes * 8), 0, throttles, 16, 4);
421 Array.Copy(BitConverter.GetBytes((float)textureBytes * 8), 0, throttles, 20, 4);
422 Array.Copy(BitConverter.GetBytes((float)assetBytes * 8), 0, throttles, 24, 4);
423
424 udpClient.SetThrottles(throttles);
425 }
426 }
427} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs
new file mode 100644
index 0000000..7a2756b
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs
@@ -0,0 +1,126 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using OpenSim.Framework;
30using Nini.Config;
31
32namespace OpenSim.Region.ClientStack.LindenUDP
33{
34 /// <summary>
35 /// Holds drip rates and maximum burst rates for throttling with hierarchical
36 /// token buckets. The maximum burst rates set here are hard limits and can
37 /// not be overridden by client requests
38 /// </summary>
39 public sealed class ThrottleRates
40 {
41 /// <summary>Drip rate for resent packets</summary>
42 public int Resend;
43 /// <summary>Drip rate for terrain packets</summary>
44 public int Land;
45 /// <summary>Drip rate for wind packets</summary>
46 public int Wind;
47 /// <summary>Drip rate for cloud packets</summary>
48 public int Cloud;
49 /// <summary>Drip rate for task packets</summary>
50 public int Task;
51 /// <summary>Drip rate for texture packets</summary>
52 public int Texture;
53 /// <summary>Drip rate for asset packets</summary>
54 public int Asset;
55
56 /// <summary>Drip rate for the parent token bucket</summary>
57 public int Total;
58
59 /// <summary>Flag used to enable adaptive throttles</summary>
60 public bool AdaptiveThrottlesEnabled;
61
62 /// <summary>
63 /// Set the minimum rate that the adaptive throttles can set. The viewer
64 /// can still throttle lower than this, but the adaptive throttles will
65 /// never decrease rates below this no matter how many packets are dropped
66 /// </summary>
67 public Int64 MinimumAdaptiveThrottleRate;
68
69 /// <summary>Amount of the texture throttle to steal for the task throttle</summary>
70 public double CannibalizeTextureRate;
71
72 /// <summary>
73 /// Default constructor
74 /// </summary>
75 /// <param name="config">Config source to load defaults from</param>
76 public ThrottleRates(IConfigSource config)
77 {
78 try
79 {
80 IConfig throttleConfig = config.Configs["ClientStack.LindenUDP"];
81
82 // Current default total is 66750
83 Resend = throttleConfig.GetInt("resend_default", 6625);
84 Land = throttleConfig.GetInt("land_default", 9125);
85 Wind = throttleConfig.GetInt("wind_default", 1750);
86 Cloud = throttleConfig.GetInt("cloud_default", 1750);
87 Task = throttleConfig.GetInt("task_default", 18500);
88 Texture = throttleConfig.GetInt("texture_default", 18500);
89 Asset = throttleConfig.GetInt("asset_default", 10500);
90
91 Total = throttleConfig.GetInt("client_throttle_max_bps", 0);
92
93 AdaptiveThrottlesEnabled = throttleConfig.GetBoolean("enable_adaptive_throttles", false);
94 MinimumAdaptiveThrottleRate = throttleConfig.GetInt("adaptive_throttle_min_bps", 32000);
95
96 CannibalizeTextureRate = (double)throttleConfig.GetFloat("CannibalizeTextureRate", 0.0f);
97 CannibalizeTextureRate = Util.Clamp<double>(CannibalizeTextureRate,0.0, 0.9);
98 }
99 catch (Exception) { }
100 }
101
102 public int GetRate(ThrottleOutPacketType type)
103 {
104 switch (type)
105 {
106 case ThrottleOutPacketType.Resend:
107 return Resend;
108 case ThrottleOutPacketType.Land:
109 return Land;
110 case ThrottleOutPacketType.Wind:
111 return Wind;
112 case ThrottleOutPacketType.Cloud:
113 return Cloud;
114 case ThrottleOutPacketType.Task:
115 return Task;
116 case ThrottleOutPacketType.Texture:
117 return Texture;
118 case ThrottleOutPacketType.Asset:
119 return Asset;
120 case ThrottleOutPacketType.Unknown:
121 default:
122 return 0;
123 }
124 }
125 }
126}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs
new file mode 100644
index 0000000..4616203
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs
@@ -0,0 +1,464 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Reflection;
32using OpenSim.Framework;
33
34using log4net;
35
36namespace OpenSim.Region.ClientStack.LindenUDP
37{
38 /// <summary>
39 /// A hierarchical token bucket for bandwidth throttling. See
40 /// http://en.wikipedia.org/wiki/Token_bucket for more information
41 /// </summary>
42 public class TokenBucket
43 {
44 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
45
46 public string Identifier { get; private set; }
47
48 public int DebugLevel { get; set; }
49
50 /// <summary>
51 /// Number of ticks (ms) per quantum, drip rate and max burst
52 /// are defined over this interval.
53 /// </summary>
54 protected const Int32 m_ticksPerQuantum = 1000;
55
56 /// <summary>
57 /// This is the number of quantums worth of packets that can
58 /// be accommodated during a burst
59 /// </summary>
60 protected const Double m_quantumsPerBurst = 1.5;
61
62 /// <summary>
63 /// </summary>
64 protected const Int32 m_minimumDripRate = LLUDPServer.MTU;
65
66 /// <summary>Time of the last drip, in system ticks</summary>
67 protected Int32 m_lastDrip;
68
69 /// <summary>
70 /// The number of bytes that can be sent at this moment. This is the
71 /// current number of tokens in the bucket
72 /// </summary>
73 protected Int64 m_tokenCount;
74
75 /// <summary>
76 /// Map of children buckets and their requested maximum burst rate
77 /// </summary>
78 protected Dictionary<TokenBucket,Int64> m_children = new Dictionary<TokenBucket,Int64>();
79
80 /// <summary>
81 /// The parent bucket of this bucket, or null if this bucket has no
82 /// parent. The parent bucket will limit the aggregate bandwidth of all
83 /// of its children buckets
84 /// </summary>
85 public TokenBucket Parent { get; protected set; }
86
87 /// <summary>
88 /// Maximum burst rate in bytes per second. This is the maximum number
89 /// of tokens that can accumulate in the bucket at any one time. This
90 /// also sets the total request for leaf nodes
91 /// </summary>
92 protected Int64 m_burstRate;
93 public Int64 RequestedBurstRate
94 {
95 get { return m_burstRate; }
96 set { m_burstRate = (value < 0 ? 0 : value); }
97 }
98
99 public Int64 BurstRate
100 {
101 get {
102 double rate = RequestedBurstRate * BurstRateModifier();
103 if (rate < m_minimumDripRate * m_quantumsPerBurst)
104 rate = m_minimumDripRate * m_quantumsPerBurst;
105
106 return (Int64) rate;
107 }
108 }
109
110 /// <summary>
111 /// The requested drip rate for this particular bucket.
112 /// </summary>
113 /// <remarks>
114 /// 0 then TotalDripRequest is used instead.
115 /// Can never be above MaxDripRate.
116 /// Tokens are added to the bucket at any time
117 /// <seealso cref="RemoveTokens"/> is called, at the granularity of
118 /// the system tick interval (typically around 15-22ms)
119 /// FIXME: It is extremely confusing to be able to set a RequestedDripRate of 0 and then receive a positive
120 /// number on get if TotalDripRequest is set. This also stops us being able to retrieve the fact that
121 /// RequestedDripRate is set to 0. Really, this should always return m_dripRate and then we can get
122 /// (m_dripRate == 0 ? TotalDripRequest : m_dripRate) on some other properties.
123 /// </remarks>
124 public virtual Int64 RequestedDripRate
125 {
126 get { return (m_dripRate == 0 ? TotalDripRequest : m_dripRate); }
127 set
128 {
129 if (value <= 0)
130 m_dripRate = 0;
131 else if (MaxDripRate > 0 && value > MaxDripRate)
132 m_dripRate = MaxDripRate;
133 else
134 m_dripRate = value;
135
136 m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst);
137
138 if (Parent != null)
139 Parent.RegisterRequest(this, m_dripRate);
140 }
141 }
142
143 /// <summary>
144 /// Gets the drip rate.
145 /// </summary>
146 /// <value>
147 /// DripRate can never be above max drip rate or below min drip rate.
148 /// If we are a child bucket then the drip rate return is modifed by the total load on the capacity of the
149 /// parent bucket.
150 /// </value>
151 public virtual Int64 DripRate
152 {
153 get
154 {
155 double rate;
156
157 // FIXME: This doesn't properly work if we have a parent and children and a requested drip rate set
158 // on ourselves which is not equal to the child drip rates.
159 if (Parent == null)
160 {
161 if (TotalDripRequest > 0)
162 rate = Math.Min(RequestedDripRate, TotalDripRequest);
163 else
164 rate = RequestedDripRate;
165 }
166 else
167 {
168 rate = (double)RequestedDripRate * Parent.DripRateModifier();
169 }
170
171 if (rate < m_minimumDripRate)
172 rate = m_minimumDripRate;
173 else if (MaxDripRate > 0 && rate > MaxDripRate)
174 rate = MaxDripRate;
175
176 return (Int64)rate;
177 }
178 }
179 protected Int64 m_dripRate;
180
181 // <summary>
182 // The maximum rate for flow control. Drip rate can never be greater than this.
183 // </summary>
184 public Int64 MaxDripRate { get; set; }
185
186 /// <summary>
187 /// The current total of the requested maximum burst rates of children buckets.
188 /// </summary>
189 public Int64 TotalDripRequest { get; protected set; }
190
191 /// <summary>
192 /// Default constructor
193 /// </summary>
194 /// <param name="identifier">Identifier for this token bucket</param>
195 /// <param name="parent">Parent bucket if this is a child bucket, or
196 /// null if this is a root bucket</param>
197 /// <param name="requestedDripRate">
198 /// Requested rate that the bucket fills, in bytes per
199 /// second. If zero, the bucket always remains full.
200 /// </param>
201 public TokenBucket(string identifier, TokenBucket parent, Int64 requestedDripRate, Int64 maxDripRate)
202 {
203 Identifier = identifier;
204
205 Parent = parent;
206 RequestedDripRate = requestedDripRate;
207 MaxDripRate = maxDripRate;
208 m_lastDrip = Util.EnvironmentTickCount();
209 }
210
211 /// <summary>
212 /// Compute a modifier for the MaxBurst rate. This is 1.0, meaning
213 /// no modification if the requested bandwidth is less than the
214 /// max burst bandwidth all the way to the root of the throttle
215 /// hierarchy. However, if any of the parents is over-booked, then
216 /// the modifier will be less than 1.
217 /// </summary>
218 protected double DripRateModifier()
219 {
220 Int64 driprate = DripRate;
221 double modifier = driprate >= TotalDripRequest ? 1.0 : (double)driprate / (double)TotalDripRequest;
222
223// if (DebugLevel > 0)
224// m_log.DebugFormat(
225// "[TOKEN BUCKET]: Returning drip modifier {0}/{1} = {2} from {3}",
226// driprate, TotalDripRequest, modifier, Identifier);
227
228 return modifier;
229 }
230
231 /// <summary>
232 /// </summary>
233 protected double BurstRateModifier()
234 {
235 // for now... burst rate is always m_quantumsPerBurst (constant)
236 // larger than drip rate so the ratio of burst requests is the
237 // same as the drip ratio
238 return DripRateModifier();
239 }
240
241 /// <summary>
242 /// Register drip rate requested by a child of this throttle. Pass the
243 /// changes up the hierarchy.
244 /// </summary>
245 public void RegisterRequest(TokenBucket child, Int64 request)
246 {
247 lock (m_children)
248 {
249 m_children[child] = request;
250
251 TotalDripRequest = 0;
252 foreach (KeyValuePair<TokenBucket, Int64> cref in m_children)
253 TotalDripRequest += cref.Value;
254 }
255
256 // Pass the new values up to the parent
257 if (Parent != null)
258 {
259 Int64 effectiveDripRate;
260
261 if (RequestedDripRate > 0)
262 effectiveDripRate = Math.Min(RequestedDripRate, TotalDripRequest);
263 else
264 effectiveDripRate = TotalDripRequest;
265
266 Parent.RegisterRequest(this, effectiveDripRate);
267 }
268 }
269
270 /// <summary>
271 /// Remove the rate requested by a child of this throttle. Pass the
272 /// changes up the hierarchy.
273 /// </summary>
274 public void UnregisterRequest(TokenBucket child)
275 {
276 lock (m_children)
277 {
278 m_children.Remove(child);
279
280 TotalDripRequest = 0;
281 foreach (KeyValuePair<TokenBucket, Int64> cref in m_children)
282 TotalDripRequest += cref.Value;
283 }
284
285 // Pass the new values up to the parent
286 if (Parent != null)
287 Parent.RegisterRequest(this,Math.Min(RequestedDripRate, TotalDripRequest));
288 }
289
290 /// <summary>
291 /// Remove a given number of tokens from the bucket
292 /// </summary>
293 /// <param name="amount">Number of tokens to remove from the bucket</param>
294 /// <returns>True if the requested number of tokens were removed from
295 /// the bucket, otherwise false</returns>
296 public bool RemoveTokens(Int64 amount)
297 {
298 // Deposit tokens for this interval
299 Drip();
300
301 // If we have enough tokens then remove them and return
302 if (m_tokenCount - amount >= 0)
303 {
304 // we don't have to remove from the parent, the drip rate is already
305 // reflective of the drip rate limits in the parent
306 m_tokenCount -= amount;
307 return true;
308 }
309
310 return false;
311 }
312
313 /// <summary>
314 /// Deposit tokens into the bucket from a child bucket that did
315 /// not use all of its available tokens
316 /// </summary>
317 protected void Deposit(Int64 count)
318 {
319 m_tokenCount += count;
320
321 // Deposit the overflow in the parent bucket, this is how we share
322 // unused bandwidth
323 Int64 burstrate = BurstRate;
324 if (m_tokenCount > burstrate)
325 m_tokenCount = burstrate;
326 }
327
328 /// <summary>
329 /// Add tokens to the bucket over time. The number of tokens added each
330 /// call depends on the length of time that has passed since the last
331 /// call to Drip
332 /// </summary>
333 /// <returns>True if tokens were added to the bucket, otherwise false</returns>
334 protected void Drip()
335 {
336 // This should never happen... means we are a leaf node and were created
337 // with no drip rate...
338 if (DripRate == 0)
339 {
340 m_log.WarnFormat("[TOKENBUCKET] something odd is happening and drip rate is 0 for {0}", Identifier);
341 return;
342 }
343
344 // Determine the interval over which we are adding tokens, never add
345 // more than a single quantum of tokens
346 Int32 deltaMS = Math.Min(Util.EnvironmentTickCountSubtract(m_lastDrip), m_ticksPerQuantum);
347 m_lastDrip = Util.EnvironmentTickCount();
348
349 // This can be 0 in the very unusual case that the timer wrapped
350 // It can be 0 if we try add tokens at a sub-tick rate
351 if (deltaMS <= 0)
352 return;
353
354 Deposit(deltaMS * DripRate / m_ticksPerQuantum);
355 }
356 }
357
358 public class AdaptiveTokenBucket : TokenBucket
359 {
360 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
361
362 public bool AdaptiveEnabled { get; set; }
363
364 /// <summary>
365 /// Target drip rate for this bucket.
366 /// </summary>
367 /// <remarks>Usually set by the client. If adaptive is enabled then throttles will increase until we reach this.</remarks>
368 public Int64 TargetDripRate
369 {
370 get { return m_targetDripRate; }
371 set
372 {
373 m_targetDripRate = Math.Max(value, m_minimumFlow);
374 }
375 }
376 protected Int64 m_targetDripRate;
377
378 // <summary>
379 // Adjust drip rate in response to network conditions.
380 // </summary>
381 public virtual Int64 AdjustedDripRate
382 {
383 get { return m_dripRate; }
384 set
385 {
386 m_dripRate = OpenSim.Framework.Util.Clamp<Int64>(value, m_minimumFlow, TargetDripRate);
387 m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst);
388
389 if (Parent != null)
390 Parent.RegisterRequest(this, m_dripRate);
391 }
392 }
393
394 /// <summary>
395 /// The minimum rate for adaptive flow control.
396 /// </summary>
397 protected Int64 m_minimumFlow = 32000;
398
399 /// <summary>
400 /// Constructor for the AdaptiveTokenBucket class
401 /// <param name="identifier">Unique identifier for the client</param>
402 /// <param name="parent">Parent bucket in the hierarchy</param>
403 /// <param name="requestedDripRate"></param>
404 /// <param name="maxDripRate">The ceiling rate for adaptation</param>
405 /// <param name="minDripRate">The floor rate for adaptation</param>
406 /// </summary>
407 public AdaptiveTokenBucket(string identifier, TokenBucket parent, Int64 requestedDripRate, Int64 maxDripRate, Int64 minDripRate, bool enabled)
408 : base(identifier, parent, requestedDripRate, maxDripRate)
409 {
410 AdaptiveEnabled = enabled;
411
412 if (AdaptiveEnabled)
413 {
414// m_log.DebugFormat("[TOKENBUCKET]: Adaptive throttle enabled");
415 m_minimumFlow = minDripRate;
416 TargetDripRate = m_minimumFlow;
417 AdjustedDripRate = m_minimumFlow;
418 }
419 }
420
421 /// <summary>
422 /// Reliable packets sent to the client for which we never received an ack adjust the drip rate down.
423 /// <param name="packets">Number of packets that expired without successful delivery</param>
424 /// </summary>
425 public void ExpirePackets(Int32 packets)
426 {
427 if (AdaptiveEnabled)
428 {
429 if (DebugLevel > 0)
430 m_log.WarnFormat(
431 "[ADAPTIVEBUCKET] drop {0} by {1} expired packets for {2}",
432 AdjustedDripRate, packets, Identifier);
433
434 // AdjustedDripRate = (Int64) (AdjustedDripRate / Math.Pow(2,packets));
435
436 // Compute the fallback solely on the rate allocated beyond the minimum, this
437 // should smooth out the fallback to the minimum rate
438 AdjustedDripRate = m_minimumFlow + (Int64) ((AdjustedDripRate - m_minimumFlow) / Math.Pow(2, packets));
439 }
440 }
441
442 /// <summary>
443 /// Reliable packets acked by the client adjust the drip rate up.
444 /// <param name="packets">Number of packets successfully acknowledged</param>
445 /// </summary>
446 public void AcknowledgePackets(Int32 packets)
447 {
448 if (AdaptiveEnabled)
449 AdjustedDripRate = AdjustedDripRate + packets * LLUDPServer.MTU;
450 }
451
452 /// <summary>
453 /// Adjust the minimum flow level for the adaptive throttle, this will drop adjusted
454 /// throttles back to the minimum levels
455 /// <param>minDripRate--the new minimum flow</param>
456 /// </summary>
457 public void ResetMinimumAdaptiveFlow(Int64 minDripRate)
458 {
459 m_minimumFlow = minDripRate;
460 TargetDripRate = m_minimumFlow;
461 AdjustedDripRate = m_minimumFlow;
462 }
463 }
464} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs b/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs
new file mode 100644
index 0000000..b546a99
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs
@@ -0,0 +1,243 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Net;
31using System.Threading;
32using OpenMetaverse;
33
34//using System.Reflection;
35//using log4net;
36
37namespace OpenSim.Region.ClientStack.LindenUDP
38{
39 /// <summary>
40 /// Special collection that is optimized for tracking unacknowledged packets
41 /// </summary>
42 public sealed class UnackedPacketCollection
43 {
44 /// <summary>
45 /// Holds information about a pending acknowledgement
46 /// </summary>
47 private struct PendingAck
48 {
49 /// <summary>Sequence number of the packet to remove</summary>
50 public uint SequenceNumber;
51 /// <summary>Environment.TickCount value when the remove was queued.
52 /// This is used to update round-trip times for packets</summary>
53 public int RemoveTime;
54 /// <summary>Whether or not this acknowledgement was attached to a
55 /// resent packet. If so, round-trip time will not be calculated</summary>
56 public bool FromResend;
57
58 public PendingAck(uint sequenceNumber, int currentTime, bool fromResend)
59 {
60 SequenceNumber = sequenceNumber;
61 RemoveTime = currentTime;
62 FromResend = fromResend;
63 }
64 }
65
66 //private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
67
68 /// <summary>Holds the actual unacked packet data, sorted by sequence number</summary>
69 private Dictionary<uint, OutgoingPacket> m_packets = new Dictionary<uint, OutgoingPacket>();
70 /// <summary>Holds packets that need to be added to the unacknowledged list</summary>
71 private LocklessQueue<OutgoingPacket> m_pendingAdds = new LocklessQueue<OutgoingPacket>();
72 /// <summary>Holds information about pending acknowledgements</summary>
73 private LocklessQueue<PendingAck> m_pendingAcknowledgements = new LocklessQueue<PendingAck>();
74 /// <summary>Holds information about pending removals</summary>
75 private LocklessQueue<uint> m_pendingRemoves = new LocklessQueue<uint>();
76
77 /// <summary>
78 /// Add an unacked packet to the collection
79 /// </summary>
80 /// <param name="packet">Packet that is awaiting acknowledgement</param>
81 /// <returns>True if the packet was successfully added, false if the
82 /// packet already existed in the collection</returns>
83 /// <remarks>This does not immediately add the ACK to the collection,
84 /// it only queues it so it can be added in a thread-safe way later</remarks>
85 public void Add(OutgoingPacket packet)
86 {
87 m_pendingAdds.Enqueue(packet);
88 Interlocked.Add(ref packet.Client.UnackedBytes, packet.Buffer.DataLength);
89 }
90
91 /// <summary>
92 /// Marks a packet as acknowledged
93 /// This method is used when an acknowledgement is received from the network for a previously
94 /// sent packet. Effects of removal this way are to update unacked byte count, adjust RTT
95 /// and increase throttle to the coresponding client.
96 /// </summary>
97 /// <param name="sequenceNumber">Sequence number of the packet to
98 /// acknowledge</param>
99 /// <param name="currentTime">Current value of Environment.TickCount</param>
100 /// <remarks>This does not immediately acknowledge the packet, it only
101 /// queues the ack so it can be handled in a thread-safe way later</remarks>
102 public void Acknowledge(uint sequenceNumber, int currentTime, bool fromResend)
103 {
104 m_pendingAcknowledgements.Enqueue(new PendingAck(sequenceNumber, currentTime, fromResend));
105 }
106
107 /// <summary>
108 /// Marks a packet as no longer needing acknowledgement without a received acknowledgement.
109 /// This method is called when a packet expires and we no longer need an acknowledgement.
110 /// When some reliable packet types expire, they are handled in a way other than simply
111 /// resending them. The only effect of removal this way is to update unacked byte count.
112 /// </summary>
113 /// <param name="sequenceNumber">Sequence number of the packet to
114 /// acknowledge</param>
115 /// <remarks>The does not immediately remove the packet, it only queues the removal
116 /// so it can be handled in a thread safe way later</remarks>
117 public void Remove(uint sequenceNumber)
118 {
119 m_pendingRemoves.Enqueue(sequenceNumber);
120 }
121
122 /// <summary>
123 /// Returns a list of all of the packets with a TickCount older than
124 /// the specified timeout
125 /// </summary>
126 /// <remarks>
127 /// This function is not thread safe, and cannot be called
128 /// multiple times concurrently
129 /// </remarks>
130 /// <param name="timeoutMS">Number of ticks (milliseconds) before a
131 /// packet is considered expired
132 /// </param>
133 /// <returns>
134 /// A list of all expired packets according to the given
135 /// expiration timeout
136 /// </returns>
137 public List<OutgoingPacket> GetExpiredPackets(int timeoutMS)
138 {
139 ProcessQueues();
140
141 List<OutgoingPacket> expiredPackets = null;
142
143 if (m_packets.Count > 0)
144 {
145 int now = Environment.TickCount & Int32.MaxValue;
146
147 foreach (OutgoingPacket packet in m_packets.Values)
148 {
149 // TickCount of zero means a packet is in the resend queue
150 // but hasn't actually been sent over the wire yet
151 if (packet.TickCount == 0)
152 continue;
153
154 if (now - packet.TickCount >= timeoutMS)
155 {
156 if (expiredPackets == null)
157 expiredPackets = new List<OutgoingPacket>();
158
159 // The TickCount will be set to the current time when the packet
160 // is actually sent out again
161 packet.TickCount = 0;
162
163 // As with other network applications, assume that an expired packet is
164 // an indication of some network problem, slow transmission
165 packet.Client.FlowThrottle.ExpirePackets(1);
166
167 expiredPackets.Add(packet);
168 }
169 }
170 }
171
172 // if (expiredPackets != null)
173 // m_log.DebugFormat("[UNACKED PACKET COLLECTION]: Found {0} expired packets on timeout of {1}", expiredPackets.Count, timeoutMS);
174
175 return expiredPackets;
176 }
177
178 private void ProcessQueues()
179 {
180 // Process all the pending adds
181 OutgoingPacket pendingAdd;
182 while (m_pendingAdds.TryDequeue(out pendingAdd))
183 if (pendingAdd != null)
184 m_packets[pendingAdd.SequenceNumber] = pendingAdd;
185
186 // Process all the pending removes, including updating statistics and round-trip times
187 PendingAck pendingAcknowledgement;
188 while (m_pendingAcknowledgements.TryDequeue(out pendingAcknowledgement))
189 {
190 //m_log.DebugFormat("[UNACKED PACKET COLLECTION]: Processing ack {0}", pendingAcknowledgement.SequenceNumber);
191 OutgoingPacket ackedPacket;
192 if (m_packets.TryGetValue(pendingAcknowledgement.SequenceNumber, out ackedPacket))
193 {
194 if (ackedPacket != null)
195 {
196 m_packets.Remove(pendingAcknowledgement.SequenceNumber);
197
198 // As with other network applications, assume that an acknowledged packet is an
199 // indication that the network can handle a little more load, speed up the transmission
200 ackedPacket.Client.FlowThrottle.AcknowledgePackets(1);
201
202 // Update stats
203 Interlocked.Add(ref ackedPacket.Client.UnackedBytes, -ackedPacket.Buffer.DataLength);
204
205 if (!pendingAcknowledgement.FromResend)
206 {
207 // Calculate the round-trip time for this packet and its ACK
208 int rtt = pendingAcknowledgement.RemoveTime - ackedPacket.TickCount;
209 if (rtt > 0)
210 ackedPacket.Client.UpdateRoundTrip(rtt);
211 }
212 }
213 else
214 {
215 // m_log.WarnFormat("[UNACKED PACKET COLLECTION]: found null packet for sequence number {0} to ack",
216 // pendingAcknowledgement.SequenceNumber);
217 }
218 }
219 else
220 {
221 // m_log.WarnFormat("[UNACKED PACKET COLLECTION]: Could not find packet with sequence number {0} to ack",
222 // pendingAcknowledgement.SequenceNumber);
223 }
224 }
225
226 uint pendingRemove;
227 while(m_pendingRemoves.TryDequeue(out pendingRemove))
228 {
229 OutgoingPacket removedPacket;
230 if (m_packets.TryGetValue(pendingRemove, out removedPacket))
231 {
232 if (removedPacket != null)
233 {
234 m_packets.Remove(pendingRemove);
235
236 // Update stats
237 Interlocked.Add(ref removedPacket.Client.UnackedBytes, -removedPacket.Buffer.DataLength);
238 }
239 }
240 }
241 }
242 }
243} \ No newline at end of file