aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ClientStack')
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs1021
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCapsModule.cs (renamed from OpenSim/Region/ClientStack/LindenUDP/Tests/TestLLPacketServer.cs)87
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs809
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs399
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs94
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs139
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs143
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs149
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs271
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs368
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs375
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs202
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs112
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs163
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/IncomingPacket.cs (renamed from OpenSim/Region/ClientStack/LindenUDP/IncomingPacket.cs)0
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/IncomingPacketHistoryCollection.cs (renamed from OpenSim/Region/ClientStack/LindenUDP/IncomingPacketHistoryCollection.cs)0
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs (renamed from OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs)20
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs (renamed from OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs)2881
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs (renamed from OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs)5
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs (renamed from OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs)281
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs (renamed from OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs)451
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs (renamed from OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs)2
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/OutgoingPacket.cs (renamed from OpenSim/Region/ClientStack/LindenUDP/OutgoingPacket.cs)7
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs318
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs (renamed from OpenSim/Region/ClientStack/LindenUDP/Tests/MockScene.cs)13
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs105
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/TestLLUDPServer.cs161
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs (renamed from OpenSim/Region/ClientStack/LindenUDP/ThrottleRates.cs)80
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs394
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs (renamed from OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs)115
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLFileTransfer.cs365
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/Tests/BasicCircuitTests.cs299
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/Tests/PacketHandlerTests.cs106
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/Tests/TestLLUDPServer.cs153
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs217
-rw-r--r--OpenSim/Region/ClientStack/RegionApplicationBase.cs53
36 files changed, 7708 insertions, 2650 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
new file mode 100644
index 0000000..2347cf2
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
@@ -0,0 +1,1021 @@
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.IO;
32using System.Reflection;
33using System.Text;
34
35using OpenMetaverse;
36using OpenMetaverse.StructuredData;
37using Nini.Config;
38using log4net;
39
40using OpenSim.Framework;
41using OpenSim.Framework.Capabilities;
42using OpenSim.Region.Framework;
43using OpenSim.Region.Framework.Scenes;
44using OpenSim.Region.Framework.Scenes.Serialization;
45using OpenSim.Framework.Servers;
46using OpenSim.Framework.Servers.HttpServer;
47using OpenSim.Services.Interfaces;
48
49using Caps = OpenSim.Framework.Capabilities.Caps;
50using OSDArray = OpenMetaverse.StructuredData.OSDArray;
51using OSDMap = OpenMetaverse.StructuredData.OSDMap;
52
53namespace OpenSim.Region.ClientStack.Linden
54{
55 public delegate void UpLoadedAsset(
56 string assetName, string description, UUID assetID, UUID inventoryItem, UUID parentFolder,
57 byte[] data, string inventoryType, string assetType);
58
59 public delegate UUID UpdateItem(UUID itemID, byte[] data);
60
61 public delegate void UpdateTaskScript(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors);
62
63 public delegate void NewInventoryItem(UUID userID, InventoryItemBase item);
64
65 public delegate void NewAsset(AssetBase asset);
66
67 public delegate UUID ItemUpdatedCallback(UUID userID, UUID itemID, byte[] data);
68
69 public delegate ArrayList TaskScriptUpdatedCallback(UUID userID, UUID itemID, UUID primID,
70 bool isScriptRunning, byte[] data);
71
72 public delegate InventoryCollection FetchInventoryDescendentsCAPS(UUID agentID, UUID folderID, UUID ownerID,
73 bool fetchFolders, bool fetchItems, int sortOrder, out int version);
74
75 /// <summary>
76 /// XXX Probably not a particularly nice way of allow us to get the scene presence from the scene (chiefly so that
77 /// we can popup a message on the user's client if the inventory service has permanently failed). But I didn't want
78 /// to just pass the whole Scene into CAPS.
79 /// </summary>
80 public delegate IClientAPI GetClientDelegate(UUID agentID);
81
82 public class BunchOfCaps
83 {
84 private static readonly ILog m_log =
85 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
86
87 private Scene m_Scene;
88 private Caps m_HostCapsObj;
89
90 private static readonly string m_requestPath = "0000/";
91 // private static readonly string m_mapLayerPath = "0001/";
92 private static readonly string m_newInventory = "0002/";
93 //private static readonly string m_requestTexture = "0003/";
94 private static readonly string m_notecardUpdatePath = "0004/";
95 private static readonly string m_notecardTaskUpdatePath = "0005/";
96 // private static readonly string m_fetchInventoryPath = "0006/";
97 // private static readonly string m_remoteParcelRequestPath = "0009/";// This is in the LandManagementModule.
98
99
100 // These are callbacks which will be setup by the scene so that we can update scene data when we
101 // receive capability calls
102 public NewInventoryItem AddNewInventoryItem = null;
103 public NewAsset AddNewAsset = null;
104 public ItemUpdatedCallback ItemUpdatedCall = null;
105 public TaskScriptUpdatedCallback TaskScriptUpdatedCall = null;
106 public FetchInventoryDescendentsCAPS CAPSFetchInventoryDescendents = null;
107 public GetClientDelegate GetClient = null;
108
109 private bool m_persistBakedTextures = false;
110 private IAssetService m_assetService;
111 private bool m_dumpAssetsToFile = false;
112 private string m_regionName;
113
114 public BunchOfCaps(Scene scene, Caps caps)
115 {
116 m_Scene = scene;
117 m_HostCapsObj = caps;
118 IConfigSource config = m_Scene.Config;
119 if (config != null)
120 {
121 IConfig sconfig = config.Configs["Startup"];
122 if (sconfig != null)
123 m_persistBakedTextures = sconfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures);
124 }
125
126 m_assetService = m_Scene.AssetService;
127 m_regionName = m_Scene.RegionInfo.RegionName;
128
129 RegisterHandlers();
130
131 AddNewInventoryItem = m_Scene.AddUploadedInventoryItem;
132 ItemUpdatedCall = m_Scene.CapsUpdateInventoryItemAsset;
133 TaskScriptUpdatedCall = m_Scene.CapsUpdateTaskInventoryScriptAsset;
134 GetClient = m_Scene.SceneGraph.GetControllingClient;
135 }
136
137 /// <summary>
138 /// Register a bunch of CAPS http service handlers
139 /// </summary>
140 public void RegisterHandlers()
141 {
142 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath;
143
144 RegisterRegionServiceHandlers(capsBase);
145 RegisterInventoryServiceHandlers(capsBase);
146 }
147
148 public void RegisterRegionServiceHandlers(string capsBase)
149 {
150 try
151 {
152 // the root of all evil
153 m_HostCapsObj.RegisterHandler("SEED", new RestStreamHandler("POST", capsBase + m_requestPath, SeedCapRequest));
154 m_log.DebugFormat(
155 "[CAPS]: Registered seed capability {0} for {1}", capsBase + m_requestPath, m_HostCapsObj.AgentID);
156
157 //m_capsHandlers["MapLayer"] =
158 // new LLSDStreamhandler<OSDMapRequest, OSDMapLayerResponse>("POST",
159 // capsBase + m_mapLayerPath,
160 // GetMapLayer);
161 IRequestHandler req = new RestStreamHandler("POST", capsBase + m_notecardTaskUpdatePath, ScriptTaskInventory);
162 m_HostCapsObj.RegisterHandler("UpdateScriptTaskInventory", req);
163 m_HostCapsObj.RegisterHandler("UpdateScriptTask", req);
164 }
165 catch (Exception e)
166 {
167 m_log.Error("[CAPS]: " + e.ToString());
168 }
169 }
170
171 public void RegisterInventoryServiceHandlers(string capsBase)
172 {
173 try
174 {
175 // I don't think this one works...
176 m_HostCapsObj.RegisterHandler("NewFileAgentInventory", new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDAssetUploadResponse>("POST",
177 capsBase + m_newInventory,
178 NewAgentInventoryRequest));
179 IRequestHandler req = new RestStreamHandler("POST", capsBase + m_notecardUpdatePath, NoteCardAgentInventory);
180 m_HostCapsObj.RegisterHandler("UpdateNotecardAgentInventory", req);
181 m_HostCapsObj.RegisterHandler("UpdateScriptAgentInventory", req);
182 m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req);
183
184 // As of RC 1.22.9 of the Linden client this is
185 // supported
186
187 //m_capsHandlers["WebFetchInventoryDescendents"] =new RestStreamHandler("POST", capsBase + m_fetchInventoryPath, FetchInventoryDescendentsRequest);
188
189 // justincc: I've disabled the CAPS service for now to fix problems with selecting textures, and
190 // subsequent inventory breakage, in the edit object pane (such as mantis 1085). This requires
191 // enhancements (probably filling out the folder part of the LLSD reply) to our CAPS service,
192 // but when I went on the Linden grid, the
193 // simulators I visited (version 1.21) were, surprisingly, no longer supplying this capability. Instead,
194 // the 1.19.1.4 client appeared to be happily flowing inventory data over UDP
195 //
196 // This is very probably just a temporary measure - once the CAPS service appears again on the Linden grid
197 // we will be
198 // able to get the data we need to implement the necessary part of the protocol to fix the issue above.
199 // m_capsHandlers["FetchInventoryDescendents"] =
200 // new RestStreamHandler("POST", capsBase + m_fetchInventoryPath, FetchInventoryRequest);
201
202 // m_capsHandlers["FetchInventoryDescendents"] =
203 // new LLSDStreamhandler<LLSDFetchInventoryDescendents, LLSDInventoryDescendents>("POST",
204 // capsBase + m_fetchInventory,
205 // FetchInventory));
206 // m_capsHandlers["RequestTextureDownload"] = new RestStreamHandler("POST",
207 // capsBase + m_requestTexture,
208 // RequestTexture);
209 }
210 catch (Exception e)
211 {
212 m_log.Error("[CAPS]: " + e.ToString());
213 }
214 }
215
216 /// <summary>
217 /// Construct a client response detailing all the capabilities this server can provide.
218 /// </summary>
219 /// <param name="request"></param>
220 /// <param name="path"></param>
221 /// <param name="param"></param>
222 /// <param name="httpRequest">HTTP request header object</param>
223 /// <param name="httpResponse">HTTP response header object</param>
224 /// <returns></returns>
225 public string SeedCapRequest(string request, string path, string param,
226 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
227 {
228// m_log.Debug("[CAPS]: Seed Caps Request in region: " + m_regionName);
229
230 if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint))
231 {
232 m_log.DebugFormat("[CAPS]: Unauthorized CAPS client");
233 return string.Empty;
234 }
235
236 Hashtable caps = m_HostCapsObj.CapsHandlers.GetCapsDetails(true);
237
238 // Add the external too
239 foreach (KeyValuePair<string, string> kvp in m_HostCapsObj.ExternalCapsHandlers)
240 caps[kvp.Key] = kvp.Value;
241
242 string result = LLSDHelpers.SerialiseLLSDReply(caps);
243
244 //m_log.DebugFormat("[CAPS] CapsRequest {0}", result);
245
246 return result;
247 }
248
249 /// <summary>
250 /// Called by the script task update handler. Provides a URL to which the client can upload a new asset.
251 /// </summary>
252 /// <param name="request"></param>
253 /// <param name="path"></param>
254 /// <param name="param"></param>
255 /// <param name="httpRequest">HTTP request header object</param>
256 /// <param name="httpResponse">HTTP response header object</param>
257 /// <returns></returns>
258 public string ScriptTaskInventory(string request, string path, string param,
259 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
260 {
261 try
262 {
263 m_log.Debug("[CAPS]: ScriptTaskInventory Request in region: " + m_regionName);
264 //m_log.DebugFormat("[CAPS]: request: {0}, path: {1}, param: {2}", request, path, param);
265
266 Hashtable hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request));
267 LLSDTaskScriptUpdate llsdUpdateRequest = new LLSDTaskScriptUpdate();
268 LLSDHelpers.DeserialiseOSDMap(hash, llsdUpdateRequest);
269
270 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath;
271 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000");
272
273 TaskInventoryScriptUpdater uploader =
274 new TaskInventoryScriptUpdater(
275 llsdUpdateRequest.item_id,
276 llsdUpdateRequest.task_id,
277 llsdUpdateRequest.is_script_running,
278 capsBase + uploaderPath,
279 m_HostCapsObj.HttpListener,
280 m_dumpAssetsToFile);
281 uploader.OnUpLoad += TaskScriptUpdated;
282
283 m_HostCapsObj.HttpListener.AddStreamHandler(new BinaryStreamHandler("POST", capsBase + uploaderPath, uploader.uploaderCaps));
284
285 string protocol = "http://";
286
287 if (m_HostCapsObj.SSLCaps)
288 protocol = "https://";
289
290 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase +
291 uploaderPath;
292
293 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse();
294 uploadResponse.uploader = uploaderURL;
295 uploadResponse.state = "upload";
296
297 // m_log.InfoFormat("[CAPS]: " +
298 // "ScriptTaskInventory response: {0}",
299 // LLSDHelpers.SerialiseLLSDReply(uploadResponse)));
300
301 return LLSDHelpers.SerialiseLLSDReply(uploadResponse);
302 }
303 catch (Exception e)
304 {
305 m_log.Error("[CAPS]: " + e.ToString());
306 }
307
308 return null;
309 }
310
311 /// <summary>
312 /// Called when new asset data for an agent inventory item update has been uploaded.
313 /// </summary>
314 /// <param name="itemID">Item to update</param>
315 /// <param name="primID">Prim containing item to update</param>
316 /// <param name="isScriptRunning">Signals whether the script to update is currently running</param>
317 /// <param name="data">New asset data</param>
318 public void TaskScriptUpdated(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors)
319 {
320 if (TaskScriptUpdatedCall != null)
321 {
322 ArrayList e = TaskScriptUpdatedCall(m_HostCapsObj.AgentID, itemID, primID, isScriptRunning, data);
323 foreach (Object item in e)
324 errors.Add(item);
325 }
326 }
327
328 /// <summary>
329 /// Called when new asset data for an agent inventory item update has been uploaded.
330 /// </summary>
331 /// <param name="itemID">Item to update</param>
332 /// <param name="data">New asset data</param>
333 /// <returns></returns>
334 public UUID ItemUpdated(UUID itemID, byte[] data)
335 {
336 if (ItemUpdatedCall != null)
337 {
338 return ItemUpdatedCall(m_HostCapsObj.AgentID, itemID, data);
339 }
340
341 return UUID.Zero;
342 }
343
344 /// <summary>
345 ///
346 /// </summary>
347 /// <param name="llsdRequest"></param>
348 /// <returns></returns>
349 public LLSDAssetUploadResponse NewAgentInventoryRequest(LLSDAssetUploadRequest llsdRequest)
350 {
351 //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString());
352 //m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type);
353
354 if (llsdRequest.asset_type == "texture" ||
355 llsdRequest.asset_type == "animation" ||
356 llsdRequest.asset_type == "sound")
357 {
358 IClientAPI client = null;
359 IScene scene = null;
360 if (GetClient != null)
361 {
362 client = GetClient(m_HostCapsObj.AgentID);
363 scene = client.Scene;
364
365 IMoneyModule mm = scene.RequestModuleInterface<IMoneyModule>();
366
367 if (mm != null)
368 {
369 if (!mm.UploadCovered(client, mm.UploadCharge))
370 {
371 if (client != null)
372 client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false);
373
374 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
375 errorResponse.uploader = "";
376 errorResponse.state = "error";
377 return errorResponse;
378 }
379 }
380 }
381 }
382
383 string assetName = llsdRequest.name;
384 string assetDes = llsdRequest.description;
385 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath;
386 UUID newAsset = UUID.Random();
387 UUID newInvItem = UUID.Random();
388 UUID parentFolder = llsdRequest.folder_id;
389 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000");
390
391 AssetUploader uploader =
392 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type,
393 llsdRequest.asset_type, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile);
394 m_HostCapsObj.HttpListener.AddStreamHandler(
395 new BinaryStreamHandler("POST", capsBase + uploaderPath, uploader.uploaderCaps));
396
397 string protocol = "http://";
398
399 if (m_HostCapsObj.SSLCaps)
400 protocol = "https://";
401
402 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase +
403 uploaderPath;
404
405 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse();
406 uploadResponse.uploader = uploaderURL;
407 uploadResponse.state = "upload";
408 uploader.OnUpLoad += UploadCompleteHandler;
409 return uploadResponse;
410 }
411
412 /// <summary>
413 /// Convert raw uploaded data into the appropriate asset and item.
414 /// </summary>
415 /// <param name="assetID"></param>
416 /// <param name="inventoryItem"></param>
417 /// <param name="data"></param>
418 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID,
419 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType,
420 string assetType)
421 {
422 m_log.DebugFormat(
423 "Uploaded asset {0} for inventory item {1}, inv type {2}, asset type {3}",
424 assetID, inventoryItem, inventoryType, assetType);
425
426 sbyte assType = 0;
427 sbyte inType = 0;
428
429 if (inventoryType == "sound")
430 {
431 inType = 1;
432 assType = 1;
433 }
434 else if (inventoryType == "animation")
435 {
436 inType = 19;
437 assType = 20;
438 }
439 else if (inventoryType == "wearable")
440 {
441 inType = 18;
442 switch (assetType)
443 {
444 case "bodypart":
445 assType = 13;
446 break;
447 case "clothing":
448 assType = 5;
449 break;
450 }
451 }
452 else if (inventoryType == "object")
453 {
454 inType = (sbyte)InventoryType.Object;
455 assType = (sbyte)AssetType.Object;
456
457 List<Vector3> positions = new List<Vector3>();
458 List<Quaternion> rotations = new List<Quaternion>();
459 OSDMap request = (OSDMap)OSDParser.DeserializeLLSDXml(data);
460 OSDArray instance_list = (OSDArray)request["instance_list"];
461 OSDArray mesh_list = (OSDArray)request["mesh_list"];
462 OSDArray texture_list = (OSDArray)request["texture_list"];
463 SceneObjectGroup grp = null;
464
465 List<UUID> textures = new List<UUID>();
466 for (int i = 0; i < texture_list.Count; i++)
467 {
468 AssetBase textureAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Texture, "");
469 textureAsset.Data = texture_list[i].AsBinary();
470 m_assetService.Store(textureAsset);
471 textures.Add(textureAsset.FullID);
472 }
473
474 for (int i = 0; i < mesh_list.Count; i++)
475 {
476 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox();
477
478 Primitive.TextureEntry textureEntry
479 = new Primitive.TextureEntry(Primitive.TextureEntry.WHITE_TEXTURE);
480 OSDMap inner_instance_list = (OSDMap)instance_list[i];
481
482 OSDArray face_list = (OSDArray)inner_instance_list["face_list"];
483 for (uint face = 0; face < face_list.Count; face++)
484 {
485 OSDMap faceMap = (OSDMap)face_list[(int)face];
486 Primitive.TextureEntryFace f = pbs.Textures.CreateFace(face);
487 if(faceMap.ContainsKey("fullbright"))
488 f.Fullbright = faceMap["fullbright"].AsBoolean();
489 if (faceMap.ContainsKey ("diffuse_color"))
490 f.RGBA = faceMap["diffuse_color"].AsColor4();
491
492 int textureNum = faceMap["image"].AsInteger();
493 float imagerot = faceMap["imagerot"].AsInteger();
494 float offsets = (float)faceMap["offsets"].AsReal();
495 float offsett = (float)faceMap["offsett"].AsReal();
496 float scales = (float)faceMap["scales"].AsReal();
497 float scalet = (float)faceMap["scalet"].AsReal();
498
499 if(imagerot != 0)
500 f.Rotation = imagerot;
501
502 if(offsets != 0)
503 f.OffsetU = offsets;
504
505 if (offsett != 0)
506 f.OffsetV = offsett;
507
508 if (scales != 0)
509 f.RepeatU = scales;
510
511 if (scalet != 0)
512 f.RepeatV = scalet;
513
514 if (textures.Count > textureNum)
515 f.TextureID = textures[textureNum];
516 else
517 f.TextureID = Primitive.TextureEntry.WHITE_TEXTURE;
518
519 textureEntry.FaceTextures[face] = f;
520 }
521
522 pbs.TextureEntry = textureEntry.GetBytes();
523
524 AssetBase meshAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Mesh, "");
525 meshAsset.Data = mesh_list[i].AsBinary();
526 m_assetService.Store(meshAsset);
527
528 pbs.SculptEntry = true;
529 pbs.SculptTexture = meshAsset.FullID;
530 pbs.SculptType = (byte)SculptType.Mesh;
531 pbs.SculptData = meshAsset.Data;
532
533 Vector3 position = inner_instance_list["position"].AsVector3();
534 Vector3 scale = inner_instance_list["scale"].AsVector3();
535 Quaternion rotation = inner_instance_list["rotation"].AsQuaternion();
536
537// no longer used - begin ------------------------
538// int physicsShapeType = inner_instance_list["physics_shape_type"].AsInteger();
539// int material = inner_instance_list["material"].AsInteger();
540// int mesh = inner_instance_list["mesh"].AsInteger();
541
542// OSDMap permissions = (OSDMap)inner_instance_list["permissions"];
543// int base_mask = permissions["base_mask"].AsInteger();
544// int everyone_mask = permissions["everyone_mask"].AsInteger();
545// UUID creator_id = permissions["creator_id"].AsUUID();
546// UUID group_id = permissions["group_id"].AsUUID();
547// int group_mask = permissions["group_mask"].AsInteger();
548// bool is_owner_group = permissions["is_owner_group"].AsBoolean();
549// UUID last_owner_id = permissions["last_owner_id"].AsUUID();
550// int next_owner_mask = permissions["next_owner_mask"].AsInteger();
551// UUID owner_id = permissions["owner_id"].AsUUID();
552// int owner_mask = permissions["owner_mask"].AsInteger();
553// no longer used - end ------------------------
554
555 UUID owner_id = m_HostCapsObj.AgentID;
556
557 SceneObjectPart prim
558 = new SceneObjectPart(owner_id, pbs, position, Quaternion.Identity, Vector3.Zero);
559
560 prim.Scale = scale;
561 prim.OffsetPosition = position;
562 rotations.Add(rotation);
563 positions.Add(position);
564 prim.UUID = UUID.Random();
565 prim.CreatorID = owner_id;
566 prim.OwnerID = owner_id;
567 prim.GroupID = UUID.Zero;
568 prim.LastOwnerID = prim.OwnerID;
569 prim.CreationDate = Util.UnixTimeSinceEpoch();
570 prim.Name = assetName;
571 prim.Description = "";
572
573// prim.BaseMask = (uint)base_mask;
574// prim.EveryoneMask = (uint)everyone_mask;
575// prim.GroupMask = (uint)group_mask;
576// prim.NextOwnerMask = (uint)next_owner_mask;
577// prim.OwnerMask = (uint)owner_mask;
578
579 if (grp == null)
580 grp = new SceneObjectGroup(prim);
581 else
582 grp.AddPart(prim);
583 }
584
585 // Fix first link number
586 if (grp.Parts.Length > 1)
587 grp.RootPart.LinkNum++;
588
589 Vector3 rootPos = positions[0];
590 grp.AbsolutePosition = rootPos;
591 for (int i = 0; i < positions.Count; i++)
592 {
593 Vector3 offset = positions[i] - rootPos;
594 grp.Parts[i].OffsetPosition = offset;
595 }
596
597 for (int i = 0; i < rotations.Count; i++)
598 {
599 if (i != 0)
600 grp.Parts[i].RotationOffset = rotations[i];
601 }
602
603 grp.UpdateGroupRotationR(rotations[0]);
604 data = ASCIIEncoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(grp));
605 }
606
607 AssetBase asset;
608 asset = new AssetBase(assetID, assetName, assType, m_HostCapsObj.AgentID.ToString());
609 asset.Data = data;
610 if (AddNewAsset != null)
611 AddNewAsset(asset);
612 else if (m_assetService != null)
613 m_assetService.Store(asset);
614
615 InventoryItemBase item = new InventoryItemBase();
616 item.Owner = m_HostCapsObj.AgentID;
617 item.CreatorId = m_HostCapsObj.AgentID.ToString();
618 item.CreatorData = String.Empty;
619 item.ID = inventoryItem;
620 item.AssetID = asset.FullID;
621 item.Description = assetDescription;
622 item.Name = assetName;
623 item.AssetType = assType;
624 item.InvType = inType;
625 item.Folder = parentFolder;
626 item.CurrentPermissions = (uint)PermissionMask.All;
627 item.BasePermissions = (uint)PermissionMask.All;
628 item.EveryOnePermissions = 0;
629 item.NextPermissions = (uint)PermissionMask.All;
630 item.CreationDate = Util.UnixTimeSinceEpoch();
631
632 if (AddNewInventoryItem != null)
633 {
634 AddNewInventoryItem(m_HostCapsObj.AgentID, item);
635 }
636 }
637
638 /// <summary>
639 ///
640 /// </summary>
641 /// <param name="mapReq"></param>
642 /// <returns></returns>
643 public LLSDMapLayerResponse GetMapLayer(LLSDMapRequest mapReq)
644 {
645 m_log.Debug("[CAPS]: MapLayer Request in region: " + m_regionName);
646 LLSDMapLayerResponse mapResponse = new LLSDMapLayerResponse();
647 mapResponse.LayerData.Array.Add(GetOSDMapLayerResponse());
648 return mapResponse;
649 }
650
651 /// <summary>
652 ///
653 /// </summary>
654 /// <returns></returns>
655 protected static OSDMapLayer GetOSDMapLayerResponse()
656 {
657 OSDMapLayer mapLayer = new OSDMapLayer();
658 mapLayer.Right = 5000;
659 mapLayer.Top = 5000;
660 mapLayer.ImageID = new UUID("00000000-0000-1111-9999-000000000006");
661
662 return mapLayer;
663 }
664
665 /// <summary>
666 ///
667 /// </summary>
668 /// <param name="request"></param>
669 /// <param name="path"></param>
670 /// <param name="param"></param>
671 /// <returns></returns>
672 public string RequestTexture(string request, string path, string param)
673 {
674 m_log.Debug("texture request " + request);
675 // Needs implementing (added to remove compiler warning)
676 return String.Empty;
677 }
678
679
680 /// <summary>
681 /// Called by the notecard update handler. Provides a URL to which the client can upload a new asset.
682 /// </summary>
683 /// <param name="request"></param>
684 /// <param name="path"></param>
685 /// <param name="param"></param>
686 /// <returns></returns>
687 public string NoteCardAgentInventory(string request, string path, string param,
688 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
689 {
690 //m_log.Debug("[CAPS]: NoteCardAgentInventory Request in region: " + m_regionName + "\n" + request);
691 //m_log.Debug("[CAPS]: NoteCardAgentInventory Request is: " + request);
692
693 //OpenMetaverse.StructuredData.OSDMap hash = (OpenMetaverse.StructuredData.OSDMap)OpenMetaverse.StructuredData.LLSDParser.DeserializeBinary(Utils.StringToBytes(request));
694 Hashtable hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request));
695 LLSDItemUpdate llsdRequest = new LLSDItemUpdate();
696 LLSDHelpers.DeserialiseOSDMap(hash, llsdRequest);
697
698 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath;
699 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000");
700
701 ItemUpdater uploader =
702 new ItemUpdater(llsdRequest.item_id, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile);
703 uploader.OnUpLoad += ItemUpdated;
704
705 m_HostCapsObj.HttpListener.AddStreamHandler(
706 new BinaryStreamHandler("POST", capsBase + uploaderPath, uploader.uploaderCaps));
707
708 string protocol = "http://";
709
710 if (m_HostCapsObj.SSLCaps)
711 protocol = "https://";
712
713 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase +
714 uploaderPath;
715
716 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse();
717 uploadResponse.uploader = uploaderURL;
718 uploadResponse.state = "upload";
719
720 // m_log.InfoFormat("[CAPS]: " +
721 // "NoteCardAgentInventory response: {0}",
722 // LLSDHelpers.SerialiseLLSDReply(uploadResponse)));
723
724 return LLSDHelpers.SerialiseLLSDReply(uploadResponse);
725 }
726 }
727
728 public class AssetUploader
729 {
730 public event UpLoadedAsset OnUpLoad;
731 private UpLoadedAsset handlerUpLoad = null;
732
733 private string uploaderPath = String.Empty;
734 private UUID newAssetID;
735 private UUID inventoryItemID;
736 private UUID parentFolder;
737 private IHttpServer httpListener;
738 private bool m_dumpAssetsToFile;
739 private string m_assetName = String.Empty;
740 private string m_assetDes = String.Empty;
741
742 private string m_invType = String.Empty;
743 private string m_assetType = String.Empty;
744
745 public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem,
746 UUID parentFolderID, string invType, string assetType, string path,
747 IHttpServer httpServer, bool dumpAssetsToFile)
748 {
749 m_assetName = assetName;
750 m_assetDes = description;
751 newAssetID = assetID;
752 inventoryItemID = inventoryItem;
753 uploaderPath = path;
754 httpListener = httpServer;
755 parentFolder = parentFolderID;
756 m_assetType = assetType;
757 m_invType = invType;
758 m_dumpAssetsToFile = dumpAssetsToFile;
759 }
760
761 /// <summary>
762 /// Handle raw asset upload data via the capability.
763 /// </summary>
764 /// <param name="data"></param>
765 /// <param name="path"></param>
766 /// <param name="param"></param>
767 /// <returns></returns>
768 public string uploaderCaps(byte[] data, string path, string param)
769 {
770 UUID inv = inventoryItemID;
771 string res = String.Empty;
772 LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete();
773 uploadComplete.new_asset = newAssetID.ToString();
774 uploadComplete.new_inventory_item = inv;
775 uploadComplete.state = "complete";
776
777 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
778
779 httpListener.RemoveStreamHandler("POST", uploaderPath);
780
781 // TODO: probably make this a better set of extensions here
782 string extension = ".jp2";
783 if (m_invType != "image")
784 {
785 extension = ".dat";
786 }
787
788 if (m_dumpAssetsToFile)
789 {
790 SaveAssetToFile(m_assetName + extension, data);
791 }
792 handlerUpLoad = OnUpLoad;
793 if (handlerUpLoad != null)
794 {
795 handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType);
796 }
797
798 return res;
799 }
800
801 ///Left this in and commented in case there are unforseen issues
802 //private void SaveAssetToFile(string filename, byte[] data)
803 //{
804 // FileStream fs = File.Create(filename);
805 // BinaryWriter bw = new BinaryWriter(fs);
806 // bw.Write(data);
807 // bw.Close();
808 // fs.Close();
809 //}
810
811 private static void SaveAssetToFile(string filename, byte[] data)
812 {
813 string assetPath = "UserAssets";
814 if (!Directory.Exists(assetPath))
815 {
816 Directory.CreateDirectory(assetPath);
817 }
818 FileStream fs = File.Create(Path.Combine(assetPath, Util.safeFileName(filename)));
819 BinaryWriter bw = new BinaryWriter(fs);
820 bw.Write(data);
821 bw.Close();
822 fs.Close();
823 }
824 }
825
826 /// <summary>
827 /// This class is a callback invoked when a client sends asset data to
828 /// an agent inventory notecard update url
829 /// </summary>
830 public class ItemUpdater
831 {
832 public event UpdateItem OnUpLoad;
833
834 private UpdateItem handlerUpdateItem = null;
835
836 private string uploaderPath = String.Empty;
837 private UUID inventoryItemID;
838 private IHttpServer httpListener;
839 private bool m_dumpAssetToFile;
840
841 public ItemUpdater(UUID inventoryItem, string path, IHttpServer httpServer, bool dumpAssetToFile)
842 {
843 m_dumpAssetToFile = dumpAssetToFile;
844
845 inventoryItemID = inventoryItem;
846 uploaderPath = path;
847 httpListener = httpServer;
848 }
849
850 /// <summary>
851 /// Handle raw uploaded asset data.
852 /// </summary>
853 /// <param name="data"></param>
854 /// <param name="path"></param>
855 /// <param name="param"></param>
856 /// <returns></returns>
857 public string uploaderCaps(byte[] data, string path, string param)
858 {
859 UUID inv = inventoryItemID;
860 string res = String.Empty;
861 LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete();
862 UUID assetID = UUID.Zero;
863 handlerUpdateItem = OnUpLoad;
864 if (handlerUpdateItem != null)
865 {
866 assetID = handlerUpdateItem(inv, data);
867 }
868
869 uploadComplete.new_asset = assetID.ToString();
870 uploadComplete.new_inventory_item = inv;
871 uploadComplete.state = "complete";
872
873 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
874
875 httpListener.RemoveStreamHandler("POST", uploaderPath);
876
877 if (m_dumpAssetToFile)
878 {
879 SaveAssetToFile("updateditem" + Util.RandomClass.Next(1, 1000) + ".dat", data);
880 }
881
882 return res;
883 }
884
885 ///Left this in and commented in case there are unforseen issues
886 //private void SaveAssetToFile(string filename, byte[] data)
887 //{
888 // FileStream fs = File.Create(filename);
889 // BinaryWriter bw = new BinaryWriter(fs);
890 // bw.Write(data);
891 // bw.Close();
892 // fs.Close();
893 //}
894
895 private static void SaveAssetToFile(string filename, byte[] data)
896 {
897 string assetPath = "UserAssets";
898 if (!Directory.Exists(assetPath))
899 {
900 Directory.CreateDirectory(assetPath);
901 }
902 FileStream fs = File.Create(Path.Combine(assetPath, filename));
903 BinaryWriter bw = new BinaryWriter(fs);
904 bw.Write(data);
905 bw.Close();
906 fs.Close();
907 }
908 }
909
910 /// <summary>
911 /// This class is a callback invoked when a client sends asset data to
912 /// a task inventory script update url
913 /// </summary>
914 public class TaskInventoryScriptUpdater
915 {
916 private static readonly ILog m_log =
917 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
918
919 public event UpdateTaskScript OnUpLoad;
920
921 private UpdateTaskScript handlerUpdateTaskScript = null;
922
923 private string uploaderPath = String.Empty;
924 private UUID inventoryItemID;
925 private UUID primID;
926 private bool isScriptRunning;
927 private IHttpServer httpListener;
928 private bool m_dumpAssetToFile;
929
930 public TaskInventoryScriptUpdater(UUID inventoryItemID, UUID primID, int isScriptRunning,
931 string path, IHttpServer httpServer, bool dumpAssetToFile)
932 {
933 m_dumpAssetToFile = dumpAssetToFile;
934
935 this.inventoryItemID = inventoryItemID;
936 this.primID = primID;
937
938 // This comes in over the packet as an integer, but actually appears to be treated as a bool
939 this.isScriptRunning = (0 == isScriptRunning ? false : true);
940
941 uploaderPath = path;
942 httpListener = httpServer;
943 }
944
945 /// <summary>
946 ///
947 /// </summary>
948 /// <param name="data"></param>
949 /// <param name="path"></param>
950 /// <param name="param"></param>
951 /// <returns></returns>
952 public string uploaderCaps(byte[] data, string path, string param)
953 {
954 try
955 {
956 // m_log.InfoFormat("[CAPS]: " +
957 // "TaskInventoryScriptUpdater received data: {0}, path: {1}, param: {2}",
958 // data, path, param));
959
960 string res = String.Empty;
961 LLSDTaskScriptUploadComplete uploadComplete = new LLSDTaskScriptUploadComplete();
962
963 ArrayList errors = new ArrayList();
964 handlerUpdateTaskScript = OnUpLoad;
965 if (handlerUpdateTaskScript != null)
966 {
967 handlerUpdateTaskScript(inventoryItemID, primID, isScriptRunning, data, ref errors);
968 }
969
970 uploadComplete.new_asset = inventoryItemID;
971 uploadComplete.compiled = errors.Count > 0 ? false : true;
972 uploadComplete.state = "complete";
973 uploadComplete.errors = new OpenSim.Framework.Capabilities.OSDArray();
974 uploadComplete.errors.Array = errors;
975
976 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
977
978 httpListener.RemoveStreamHandler("POST", uploaderPath);
979
980 if (m_dumpAssetToFile)
981 {
982 SaveAssetToFile("updatedtaskscript" + Util.RandomClass.Next(1, 1000) + ".dat", data);
983 }
984
985 // m_log.InfoFormat("[CAPS]: TaskInventoryScriptUpdater.uploaderCaps res: {0}", res);
986
987 return res;
988 }
989 catch (Exception e)
990 {
991 m_log.Error("[CAPS]: " + e.ToString());
992 }
993
994 // XXX Maybe this should be some meaningful error packet
995 return null;
996 }
997
998 ///Left this in and commented in case there are unforseen issues
999 //private void SaveAssetToFile(string filename, byte[] data)
1000 //{
1001 // FileStream fs = File.Create(filename);
1002 // BinaryWriter bw = new BinaryWriter(fs);
1003 // bw.Write(data);
1004 // bw.Close();
1005 // fs.Close();
1006 //}
1007 private static void SaveAssetToFile(string filename, byte[] data)
1008 {
1009 string assetPath = "UserAssets";
1010 if (!Directory.Exists(assetPath))
1011 {
1012 Directory.CreateDirectory(assetPath);
1013 }
1014 FileStream fs = File.Create(Path.Combine(assetPath, filename));
1015 BinaryWriter bw = new BinaryWriter(fs);
1016 bw.Write(data);
1017 bw.Close();
1018 fs.Close();
1019 }
1020 }
1021} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/LindenUDP/Tests/TestLLPacketServer.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCapsModule.cs
index e995d65..66b865f 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/Tests/TestLLPacketServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCapsModule.cs
@@ -25,48 +25,67 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System;
28using System.Collections.Generic; 29using System.Collections.Generic;
29using OpenMetaverse.Packets; 30using System.Reflection;
30 31
31namespace OpenSim.Region.ClientStack.LindenUDP.Tests 32using log4net;
32{ 33using Nini.Config;
33 public class TestLLPacketServer : LLPacketServer 34using OpenMetaverse;
35using Mono.Addins;
36
37using OpenSim.Framework;
38using OpenSim.Region.Framework;
39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Region.Framework.Scenes;
41using Caps = OpenSim.Framework.Capabilities.Caps;
42
43[assembly: Addin("LindenCaps", "0.1")]
44[assembly: AddinDependency("OpenSim", "0.5")]
45namespace OpenSim.Region.ClientStack.Linden
46{
47
48 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
49 public class BunchOfCapsModule : INonSharedRegionModule
34 { 50 {
35 /// <summary> 51// private static readonly ILog m_log =
36 /// Record counts of packets received 52// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
37 /// </summary> 53
38 protected Dictionary<PacketType, int> m_packetsReceived = new Dictionary<PacketType, int>(); 54 private Scene m_Scene;
39 55
40 public TestLLPacketServer(LLUDPServer networkHandler, ClientStackUserSettings userSettings) 56 #region INonSharedRegionModule
41 : base(networkHandler, userSettings) 57
42 {} 58 public string Name { get { return "BunchOfCapsModule"; } }
43 59
44 public override void InPacket(uint circuitCode, Packet packet) 60 public Type ReplaceableInterface { get { return null; } }
61
62 public void Initialise(IConfigSource source)
45 { 63 {
46 base.InPacket(circuitCode, packet);
47
48 if (m_packetsReceived.ContainsKey(packet.Type))
49 m_packetsReceived[packet.Type]++;
50 else
51 m_packetsReceived[packet.Type] = 1;
52 } 64 }
53 65
54 public int GetTotalPacketsReceived() 66 public void Close() { }
67
68 public void AddRegion(Scene scene)
55 { 69 {
56 int totalCount = 0; 70 m_Scene = scene;
57 71 m_Scene.EventManager.OnRegisterCaps += OnRegisterCaps;
58 foreach (int count in m_packetsReceived.Values)
59 totalCount += count;
60
61 return totalCount;
62 } 72 }
63 73
64 public int GetPacketsReceivedFor(PacketType packetType) 74 public void RemoveRegion(Scene scene)
65 { 75 {
66 if (m_packetsReceived.ContainsKey(packetType))
67 return m_packetsReceived[packetType];
68 else
69 return 0;
70 } 76 }
77
78 public void RegionLoaded(Scene scene)
79 {
80 }
81
82 public void PostInitialise() { }
83 #endregion
84
85 private void OnRegisterCaps(UUID agentID, Caps caps)
86 {
87 new BunchOfCaps(m_Scene, caps);
88 }
89
71 } 90 }
72} 91}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
new file mode 100644
index 0000000..8ba6f61
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
@@ -0,0 +1,809 @@
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.Threading;
34using log4net;
35using Nini.Config;
36using Mono.Addins;
37using OpenMetaverse;
38using OpenMetaverse.Messages.Linden;
39using OpenMetaverse.Packets;
40using OpenMetaverse.StructuredData;
41using OpenSim.Framework;
42using OpenSim.Framework.Console;
43using OpenSim.Framework.Servers;
44using OpenSim.Framework.Servers.HttpServer;
45using OpenSim.Region.Framework.Interfaces;
46using OpenSim.Region.Framework.Scenes;
47using BlockingLLSDQueue = OpenSim.Framework.BlockingQueue<OpenMetaverse.StructuredData.OSD>;
48using Caps=OpenSim.Framework.Capabilities.Caps;
49
50namespace OpenSim.Region.ClientStack.Linden
51{
52 public struct QueueItem
53 {
54 public int id;
55 public OSDMap body;
56 }
57
58 //[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
59 public class EventQueueGetModule : IEventQueue, IRegionModule
60 {
61 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
62
63 /// <value>
64 /// Debug level.
65 /// </value>
66 public int DebugLevel { get; set; }
67
68 protected Scene m_scene;
69 private IConfigSource m_gConfig;
70 bool enabledYN;
71
72 private Dictionary<UUID, int> m_ids = new Dictionary<UUID, int>();
73
74 private Dictionary<UUID, Queue<OSD>> queues = new Dictionary<UUID, Queue<OSD>>();
75 private Dictionary<UUID, UUID> m_QueueUUIDAvatarMapping = new Dictionary<UUID, UUID>();
76 private Dictionary<UUID, UUID> m_AvatarQueueUUIDMapping = new Dictionary<UUID, UUID>();
77
78 #region IRegionModule methods
79 public virtual void Initialise(Scene scene, IConfigSource config)
80 {
81 m_gConfig = config;
82
83 IConfig startupConfig = m_gConfig.Configs["Startup"];
84
85 ReadConfigAndPopulate(scene, startupConfig, "Startup");
86
87 if (enabledYN)
88 {
89 m_scene = scene;
90 scene.RegisterModuleInterface<IEventQueue>(this);
91
92 // Register fallback handler
93 // Why does EQG Fail on region crossings!
94
95 //scene.CommsManager.HttpServer.AddLLSDHandler("/CAPS/EQG/", EventQueueFallBack);
96
97 scene.EventManager.OnNewClient += OnNewClient;
98
99 // TODO: Leaving these open, or closing them when we
100 // become a child is incorrect. It messes up TP in a big
101 // way. CAPS/EQ need to be active as long as the UDP
102 // circuit is there.
103
104 scene.EventManager.OnClientClosed += ClientClosed;
105 scene.EventManager.OnMakeChildAgent += MakeChildAgent;
106 scene.EventManager.OnRegisterCaps += OnRegisterCaps;
107
108 MainConsole.Instance.Commands.AddCommand(
109 "event queue",
110 false,
111 "debug eq",
112 "debug eq [0|1]",
113 "Turn on event queue debugging",
114 "debug eq 1 will turn on event queue debugging. This will log all outgoing event queue messages to clients.\n"
115 + "debug eq 0 will turn off event queue debugging.",
116 HandleDebugEq);
117 }
118 else
119 {
120 m_gConfig = null;
121 }
122 }
123
124 private void ReadConfigAndPopulate(Scene scene, IConfig startupConfig, string p)
125 {
126 enabledYN = startupConfig.GetBoolean("EventQueue", true);
127 }
128
129 public void PostInitialise()
130 {
131 }
132
133 public virtual void Close()
134 {
135 }
136
137 public virtual string Name
138 {
139 get { return "EventQueueGetModule"; }
140 }
141
142 public bool IsSharedModule
143 {
144 get { return false; }
145 }
146 #endregion
147
148 protected void HandleDebugEq(string module, string[] args)
149 {
150 int debugLevel;
151
152 if (!(args.Length == 3 && int.TryParse(args[2], out debugLevel)))
153 {
154 MainConsole.Instance.OutputFormat("Usage: debug eq [0|1]");
155 }
156 else
157 {
158 DebugLevel = debugLevel;
159 MainConsole.Instance.OutputFormat(
160 "Set event queue debug level to {0} in {1}", DebugLevel, m_scene.RegionInfo.RegionName);
161 }
162 }
163
164 /// <summary>
165 /// Always returns a valid queue
166 /// </summary>
167 /// <param name="agentId"></param>
168 /// <returns></returns>
169 private Queue<OSD> TryGetQueue(UUID agentId)
170 {
171 lock (queues)
172 {
173 if (!queues.ContainsKey(agentId))
174 {
175 /*
176 m_log.DebugFormat(
177 "[EVENTQUEUE]: Adding new queue for agent {0} in region {1}",
178 agentId, m_scene.RegionInfo.RegionName);
179 */
180 queues[agentId] = new Queue<OSD>();
181 }
182
183 return queues[agentId];
184 }
185 }
186
187 /// <summary>
188 /// May return a null queue
189 /// </summary>
190 /// <param name="agentId"></param>
191 /// <returns></returns>
192 private Queue<OSD> GetQueue(UUID agentId)
193 {
194 lock (queues)
195 {
196 if (queues.ContainsKey(agentId))
197 {
198 return queues[agentId];
199 }
200 else
201 return null;
202 }
203 }
204
205 #region IEventQueue Members
206
207 public bool Enqueue(OSD ev, UUID avatarID)
208 {
209 //m_log.DebugFormat("[EVENTQUEUE]: Enqueuing event for {0} in region {1}", avatarID, m_scene.RegionInfo.RegionName);
210 try
211 {
212 Queue<OSD> queue = GetQueue(avatarID);
213 if (queue != null)
214 lock (queue)
215 queue.Enqueue(ev);
216 }
217 catch (NullReferenceException e)
218 {
219 m_log.Error("[EVENTQUEUE] Caught exception: " + e);
220 return false;
221 }
222
223 return true;
224 }
225
226 #endregion
227
228 private void OnNewClient(IClientAPI client)
229 {
230 //client.OnLogout += ClientClosed;
231 }
232
233// private void ClientClosed(IClientAPI client)
234// {
235// ClientClosed(client.AgentId);
236// }
237
238 private void ClientClosed(UUID AgentID, Scene scene)
239 {
240// m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", AgentID, m_scene.RegionInfo.RegionName);
241
242 int count = 0;
243 while (queues.ContainsKey(AgentID) && queues[AgentID].Count > 0 && count++ < 5)
244 {
245 Thread.Sleep(1000);
246 }
247
248 lock (queues)
249 {
250 queues.Remove(AgentID);
251 }
252
253 List<UUID> removeitems = new List<UUID>();
254 lock (m_AvatarQueueUUIDMapping)
255 {
256 foreach (UUID ky in m_AvatarQueueUUIDMapping.Keys)
257 {
258// m_log.DebugFormat("[EVENTQUEUE]: Found key {0} in m_AvatarQueueUUIDMapping while looking for {1}", ky, AgentID);
259 if (ky == AgentID)
260 {
261 removeitems.Add(ky);
262 }
263 }
264
265 foreach (UUID ky in removeitems)
266 {
267 UUID eventQueueGetUuid = m_AvatarQueueUUIDMapping[ky];
268 m_AvatarQueueUUIDMapping.Remove(ky);
269
270 MainServer.Instance.RemovePollServiceHTTPHandler("","/CAPS/EQG/" + eventQueueGetUuid.ToString() + "/");
271 }
272 }
273
274 UUID searchval = UUID.Zero;
275
276 removeitems.Clear();
277
278 lock (m_QueueUUIDAvatarMapping)
279 {
280 foreach (UUID ky in m_QueueUUIDAvatarMapping.Keys)
281 {
282 searchval = m_QueueUUIDAvatarMapping[ky];
283
284 if (searchval == AgentID)
285 {
286 removeitems.Add(ky);
287 }
288 }
289
290 foreach (UUID ky in removeitems)
291 m_QueueUUIDAvatarMapping.Remove(ky);
292 }
293 }
294
295 private void MakeChildAgent(ScenePresence avatar)
296 {
297 //m_log.DebugFormat("[EVENTQUEUE]: Make Child agent {0} in region {1}.", avatar.UUID, m_scene.RegionInfo.RegionName);
298 //lock (m_ids)
299 // {
300 //if (m_ids.ContainsKey(avatar.UUID))
301 //{
302 // close the event queue.
303 //m_ids[avatar.UUID] = -1;
304 //}
305 //}
306 }
307
308 public void OnRegisterCaps(UUID agentID, Caps caps)
309 {
310 // Register an event queue for the client
311
312 //m_log.DebugFormat(
313 // "[EVENTQUEUE]: OnRegisterCaps: agentID {0} caps {1} region {2}",
314 // agentID, caps, m_scene.RegionInfo.RegionName);
315
316 // Let's instantiate a Queue for this agent right now
317 TryGetQueue(agentID);
318
319 string capsBase = "/CAPS/EQG/";
320 UUID EventQueueGetUUID = UUID.Zero;
321
322 lock (m_AvatarQueueUUIDMapping)
323 {
324 // Reuse open queues. The client does!
325 if (m_AvatarQueueUUIDMapping.ContainsKey(agentID))
326 {
327 //m_log.DebugFormat("[EVENTQUEUE]: Found Existing UUID!");
328 EventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID];
329 }
330 else
331 {
332 EventQueueGetUUID = UUID.Random();
333 //m_log.DebugFormat("[EVENTQUEUE]: Using random UUID!");
334 }
335 }
336
337 lock (m_QueueUUIDAvatarMapping)
338 {
339 if (!m_QueueUUIDAvatarMapping.ContainsKey(EventQueueGetUUID))
340 m_QueueUUIDAvatarMapping.Add(EventQueueGetUUID, agentID);
341 }
342
343 lock (m_AvatarQueueUUIDMapping)
344 {
345 if (!m_AvatarQueueUUIDMapping.ContainsKey(agentID))
346 m_AvatarQueueUUIDMapping.Add(agentID, EventQueueGetUUID);
347 }
348
349 // Register this as a caps handler
350 // FIXME: Confusingly, we need to register separate as a capability so that the client is told about
351 // EventQueueGet when it receive capability information, but then we replace the rest handler immediately
352 // afterwards with the poll service. So for now, we'll pass a null instead to simplify code reading, but
353 // really it should be possible to directly register the poll handler as a capability.
354 caps.RegisterHandler("EventQueueGet",
355 new RestHTTPHandler("POST", capsBase + EventQueueGetUUID.ToString() + "/", null));
356// delegate(Hashtable m_dhttpMethod)
357// {
358// return ProcessQueue(m_dhttpMethod, agentID, caps);
359// }));
360
361 // This will persist this beyond the expiry of the caps handlers
362 MainServer.Instance.AddPollServiceHTTPHandler(
363 capsBase + EventQueueGetUUID.ToString() + "/",
364 new PollServiceEventArgs(null, HasEvents, GetEvents, NoEvents, agentID));
365
366 Random rnd = new Random(Environment.TickCount);
367 lock (m_ids)
368 {
369 if (!m_ids.ContainsKey(agentID))
370 m_ids.Add(agentID, rnd.Next(30000000));
371 }
372 }
373
374 public bool HasEvents(UUID requestID, UUID agentID)
375 {
376 // Don't use this, because of race conditions at agent closing time
377 //Queue<OSD> queue = TryGetQueue(agentID);
378
379 Queue<OSD> queue = GetQueue(agentID);
380 if (queue != null)
381 lock (queue)
382 return queue.Count > 0;
383
384 return false;
385 }
386
387 public Hashtable GetEvents(UUID requestID, UUID pAgentId, string request)
388 {
389// m_log.DebugFormat("[EVENT QUEUE GET MODULE]: Invoked GetEvents() for {0}", pAgentId);
390
391 Queue<OSD> queue = TryGetQueue(pAgentId);
392 OSD element;
393 lock (queue)
394 {
395 if (queue.Count == 0)
396 return NoEvents(requestID, pAgentId);
397 element = queue.Dequeue(); // 15s timeout
398 }
399
400 int thisID = 0;
401 lock (m_ids)
402 thisID = m_ids[pAgentId];
403
404 OSDArray array = new OSDArray();
405 if (element == null) // didn't have an event in 15s
406 {
407 // Send it a fake event to keep the client polling! It doesn't like 502s like the proxys say!
408 array.Add(EventQueueHelper.KeepAliveEvent());
409 //m_log.DebugFormat("[EVENTQUEUE]: adding fake event for {0} in region {1}", pAgentId, m_scene.RegionInfo.RegionName);
410 }
411 else
412 {
413 if (DebugLevel > 0 && element is OSDMap)
414 {
415 OSDMap ev = (OSDMap)element;
416 m_log.DebugFormat(
417 "[EVENT QUEUE GET MODULE]: Eq OUT {0} to {1}",
418 ev["message"], m_scene.GetScenePresence(pAgentId).Name);
419 }
420
421 array.Add(element);
422
423 lock (queue)
424 {
425 while (queue.Count > 0)
426 {
427 element = queue.Dequeue();
428
429 if (DebugLevel > 0 && element is OSDMap)
430 {
431 OSDMap ev = (OSDMap)element;
432 m_log.DebugFormat(
433 "[EVENT QUEUE GET MODULE]: Eq OUT {0} to {1}",
434 ev["message"], m_scene.GetScenePresence(pAgentId).Name);
435 }
436
437 array.Add(element);
438 thisID++;
439 }
440 }
441 }
442
443 OSDMap events = new OSDMap();
444 events.Add("events", array);
445
446 events.Add("id", new OSDInteger(thisID));
447 lock (m_ids)
448 {
449 m_ids[pAgentId] = thisID + 1;
450 }
451 Hashtable responsedata = new Hashtable();
452 responsedata["int_response_code"] = 200;
453 responsedata["content_type"] = "application/xml";
454 responsedata["keepalive"] = false;
455 responsedata["reusecontext"] = false;
456 responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(events);
457 //m_log.DebugFormat("[EVENTQUEUE]: sending response for {0} in region {1}: {2}", pAgentId, m_scene.RegionInfo.RegionName, responsedata["str_response_string"]);
458 return responsedata;
459 }
460
461 public Hashtable NoEvents(UUID requestID, UUID agentID)
462 {
463 Hashtable responsedata = new Hashtable();
464 responsedata["int_response_code"] = 502;
465 responsedata["content_type"] = "text/plain";
466 responsedata["keepalive"] = false;
467 responsedata["reusecontext"] = false;
468 responsedata["str_response_string"] = "Upstream error: ";
469 responsedata["error_status_text"] = "Upstream error:";
470 responsedata["http_protocol_version"] = "HTTP/1.0";
471 return responsedata;
472 }
473
474// public Hashtable ProcessQueue(Hashtable request, UUID agentID, Caps caps)
475// {
476// // TODO: this has to be redone to not busy-wait (and block the thread),
477// // TODO: as soon as we have a non-blocking way to handle HTTP-requests.
478//
479//// if (m_log.IsDebugEnabled)
480//// {
481//// String debug = "[EVENTQUEUE]: Got request for agent {0} in region {1} from thread {2}: [ ";
482//// foreach (object key in request.Keys)
483//// {
484//// debug += key.ToString() + "=" + request[key].ToString() + " ";
485//// }
486//// m_log.DebugFormat(debug + " ]", agentID, m_scene.RegionInfo.RegionName, System.Threading.Thread.CurrentThread.Name);
487//// }
488//
489// Queue<OSD> queue = TryGetQueue(agentID);
490// OSD element;
491//
492// lock (queue)
493// element = queue.Dequeue(); // 15s timeout
494//
495// Hashtable responsedata = new Hashtable();
496//
497// int thisID = 0;
498// lock (m_ids)
499// thisID = m_ids[agentID];
500//
501// if (element == null)
502// {
503// //m_log.ErrorFormat("[EVENTQUEUE]: Nothing to process in " + m_scene.RegionInfo.RegionName);
504// if (thisID == -1) // close-request
505// {
506// m_log.ErrorFormat("[EVENTQUEUE]: 404 in " + m_scene.RegionInfo.RegionName);
507// responsedata["int_response_code"] = 404; //501; //410; //404;
508// responsedata["content_type"] = "text/plain";
509// responsedata["keepalive"] = false;
510// responsedata["str_response_string"] = "Closed EQG";
511// return responsedata;
512// }
513// responsedata["int_response_code"] = 502;
514// responsedata["content_type"] = "text/plain";
515// responsedata["keepalive"] = false;
516// responsedata["str_response_string"] = "Upstream error: ";
517// responsedata["error_status_text"] = "Upstream error:";
518// responsedata["http_protocol_version"] = "HTTP/1.0";
519// return responsedata;
520// }
521//
522// OSDArray array = new OSDArray();
523// if (element == null) // didn't have an event in 15s
524// {
525// // Send it a fake event to keep the client polling! It doesn't like 502s like the proxys say!
526// array.Add(EventQueueHelper.KeepAliveEvent());
527// //m_log.DebugFormat("[EVENTQUEUE]: adding fake event for {0} in region {1}", agentID, m_scene.RegionInfo.RegionName);
528// }
529// else
530// {
531// array.Add(element);
532//
533// if (element is OSDMap)
534// {
535// OSDMap ev = (OSDMap)element;
536// m_log.DebugFormat(
537// "[EVENT QUEUE GET MODULE]: Eq OUT {0} to {1}",
538// ev["message"], m_scene.GetScenePresence(agentID).Name);
539// }
540//
541// lock (queue)
542// {
543// while (queue.Count > 0)
544// {
545// element = queue.Dequeue();
546//
547// if (element is OSDMap)
548// {
549// OSDMap ev = (OSDMap)element;
550// m_log.DebugFormat(
551// "[EVENT QUEUE GET MODULE]: Eq OUT {0} to {1}",
552// ev["message"], m_scene.GetScenePresence(agentID).Name);
553// }
554//
555// array.Add(element);
556// thisID++;
557// }
558// }
559// }
560//
561// OSDMap events = new OSDMap();
562// events.Add("events", array);
563//
564// events.Add("id", new OSDInteger(thisID));
565// lock (m_ids)
566// {
567// m_ids[agentID] = thisID + 1;
568// }
569//
570// responsedata["int_response_code"] = 200;
571// responsedata["content_type"] = "application/xml";
572// responsedata["keepalive"] = false;
573// responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(events);
574//
575// m_log.DebugFormat("[EVENTQUEUE]: sending response for {0} in region {1}: {2}", agentID, m_scene.RegionInfo.RegionName, responsedata["str_response_string"]);
576//
577// return responsedata;
578// }
579
580// public Hashtable EventQueuePath2(Hashtable request)
581// {
582// string capuuid = (string)request["uri"]; //path.Replace("/CAPS/EQG/","");
583// // pull off the last "/" in the path.
584// Hashtable responsedata = new Hashtable();
585// capuuid = capuuid.Substring(0, capuuid.Length - 1);
586// capuuid = capuuid.Replace("/CAPS/EQG/", "");
587// UUID AvatarID = UUID.Zero;
588// UUID capUUID = UUID.Zero;
589//
590// // parse the path and search for the avatar with it registered
591// if (UUID.TryParse(capuuid, out capUUID))
592// {
593// lock (m_QueueUUIDAvatarMapping)
594// {
595// if (m_QueueUUIDAvatarMapping.ContainsKey(capUUID))
596// {
597// AvatarID = m_QueueUUIDAvatarMapping[capUUID];
598// }
599// }
600//
601// if (AvatarID != UUID.Zero)
602// {
603// return ProcessQueue(request, AvatarID, m_scene.CapsModule.GetCapsForUser(AvatarID));
604// }
605// else
606// {
607// responsedata["int_response_code"] = 404;
608// responsedata["content_type"] = "text/plain";
609// responsedata["keepalive"] = false;
610// responsedata["str_response_string"] = "Not Found";
611// responsedata["error_status_text"] = "Not Found";
612// responsedata["http_protocol_version"] = "HTTP/1.0";
613// return responsedata;
614// // return 404
615// }
616// }
617// else
618// {
619// responsedata["int_response_code"] = 404;
620// responsedata["content_type"] = "text/plain";
621// responsedata["keepalive"] = false;
622// responsedata["str_response_string"] = "Not Found";
623// responsedata["error_status_text"] = "Not Found";
624// responsedata["http_protocol_version"] = "HTTP/1.0";
625// return responsedata;
626// // return 404
627// }
628// }
629
630 public OSD EventQueueFallBack(string path, OSD request, string endpoint)
631 {
632 // This is a fallback element to keep the client from loosing EventQueueGet
633 // Why does CAPS fail sometimes!?
634 m_log.Warn("[EVENTQUEUE]: In the Fallback handler! We lost the Queue in the rest handler!");
635 string capuuid = path.Replace("/CAPS/EQG/","");
636 capuuid = capuuid.Substring(0, capuuid.Length - 1);
637
638// UUID AvatarID = UUID.Zero;
639 UUID capUUID = UUID.Zero;
640 if (UUID.TryParse(capuuid, out capUUID))
641 {
642/* Don't remove this yet code cleaners!
643 * Still testing this!
644 *
645 lock (m_QueueUUIDAvatarMapping)
646 {
647 if (m_QueueUUIDAvatarMapping.ContainsKey(capUUID))
648 {
649 AvatarID = m_QueueUUIDAvatarMapping[capUUID];
650 }
651 }
652
653
654 if (AvatarID != UUID.Zero)
655 {
656 // Repair the CAP!
657 //OpenSim.Framework.Capabilities.Caps caps = m_scene.GetCapsHandlerForUser(AvatarID);
658 //string capsBase = "/CAPS/EQG/";
659 //caps.RegisterHandler("EventQueueGet",
660 //new RestHTTPHandler("POST", capsBase + capUUID.ToString() + "/",
661 //delegate(Hashtable m_dhttpMethod)
662 //{
663 // return ProcessQueue(m_dhttpMethod, AvatarID, caps);
664 //}));
665 // start new ID sequence.
666 Random rnd = new Random(System.Environment.TickCount);
667 lock (m_ids)
668 {
669 if (!m_ids.ContainsKey(AvatarID))
670 m_ids.Add(AvatarID, rnd.Next(30000000));
671 }
672
673
674 int thisID = 0;
675 lock (m_ids)
676 thisID = m_ids[AvatarID];
677
678 BlockingLLSDQueue queue = GetQueue(AvatarID);
679 OSDArray array = new OSDArray();
680 LLSD element = queue.Dequeue(15000); // 15s timeout
681 if (element == null)
682 {
683
684 array.Add(EventQueueHelper.KeepAliveEvent());
685 }
686 else
687 {
688 array.Add(element);
689 while (queue.Count() > 0)
690 {
691 array.Add(queue.Dequeue(1));
692 thisID++;
693 }
694 }
695 OSDMap events = new OSDMap();
696 events.Add("events", array);
697
698 events.Add("id", new LLSDInteger(thisID));
699
700 lock (m_ids)
701 {
702 m_ids[AvatarID] = thisID + 1;
703 }
704
705 return events;
706 }
707 else
708 {
709 return new LLSD();
710 }
711*
712*/
713 }
714 else
715 {
716 //return new LLSD();
717 }
718
719 return new OSDString("shutdown404!");
720 }
721
722 public void DisableSimulator(ulong handle, UUID avatarID)
723 {
724 OSD item = EventQueueHelper.DisableSimulator(handle);
725 Enqueue(item, avatarID);
726 }
727
728 public virtual void EnableSimulator(ulong handle, IPEndPoint endPoint, UUID avatarID)
729 {
730 OSD item = EventQueueHelper.EnableSimulator(handle, endPoint);
731 Enqueue(item, avatarID);
732 }
733
734 public virtual void EstablishAgentCommunication(UUID avatarID, IPEndPoint endPoint, string capsPath)
735 {
736 OSD item = EventQueueHelper.EstablishAgentCommunication(avatarID, endPoint.ToString(), capsPath);
737 Enqueue(item, avatarID);
738 }
739
740 public virtual void TeleportFinishEvent(ulong regionHandle, byte simAccess,
741 IPEndPoint regionExternalEndPoint,
742 uint locationID, uint flags, string capsURL,
743 UUID avatarID)
744 {
745 OSD item = EventQueueHelper.TeleportFinishEvent(regionHandle, simAccess, regionExternalEndPoint,
746 locationID, flags, capsURL, avatarID);
747 Enqueue(item, avatarID);
748 }
749
750 public virtual void CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt,
751 IPEndPoint newRegionExternalEndPoint,
752 string capsURL, UUID avatarID, UUID sessionID)
753 {
754 OSD item = EventQueueHelper.CrossRegion(handle, pos, lookAt, newRegionExternalEndPoint,
755 capsURL, avatarID, sessionID);
756 Enqueue(item, avatarID);
757 }
758
759 public void ChatterboxInvitation(UUID sessionID, string sessionName,
760 UUID fromAgent, string message, UUID toAgent, string fromName, byte dialog,
761 uint timeStamp, bool offline, int parentEstateID, Vector3 position,
762 uint ttl, UUID transactionID, bool fromGroup, byte[] binaryBucket)
763 {
764 OSD item = EventQueueHelper.ChatterboxInvitation(sessionID, sessionName, fromAgent, message, toAgent, fromName, dialog,
765 timeStamp, offline, parentEstateID, position, ttl, transactionID,
766 fromGroup, binaryBucket);
767 Enqueue(item, toAgent);
768 //m_log.InfoFormat("########### eq ChatterboxInvitation #############\n{0}", item);
769
770 }
771
772 public void ChatterBoxSessionAgentListUpdates(UUID sessionID, UUID fromAgent, UUID toAgent, bool canVoiceChat,
773 bool isModerator, bool textMute)
774 {
775 OSD item = EventQueueHelper.ChatterBoxSessionAgentListUpdates(sessionID, fromAgent, canVoiceChat,
776 isModerator, textMute);
777 Enqueue(item, toAgent);
778 //m_log.InfoFormat("########### eq ChatterBoxSessionAgentListUpdates #############\n{0}", item);
779 }
780
781 public void ParcelProperties(ParcelPropertiesMessage parcelPropertiesMessage, UUID avatarID)
782 {
783 OSD item = EventQueueHelper.ParcelProperties(parcelPropertiesMessage);
784 Enqueue(item, avatarID);
785 }
786
787 public void GroupMembership(AgentGroupDataUpdatePacket groupUpdate, UUID avatarID)
788 {
789 OSD item = EventQueueHelper.GroupMembership(groupUpdate);
790 Enqueue(item, avatarID);
791 }
792
793 public void QueryReply(PlacesReplyPacket groupUpdate, UUID avatarID)
794 {
795 OSD item = EventQueueHelper.PlacesQuery(groupUpdate);
796 Enqueue(item, avatarID);
797 }
798
799 public OSD ScriptRunningEvent(UUID objectID, UUID itemID, bool running, bool mono)
800 {
801 return EventQueueHelper.ScriptRunningReplyEvent(objectID, itemID, running, mono);
802 }
803
804 public OSD BuildEvent(string eventName, OSD eventBody)
805 {
806 return EventQueueHelper.BuildEvent(eventName, eventBody);
807 }
808 }
809}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
new file mode 100644
index 0000000..3f49aba
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
@@ -0,0 +1,399 @@
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 OpenMetaverse;
31using OpenMetaverse.Packets;
32using OpenMetaverse.StructuredData;
33using OpenMetaverse.Messages.Linden;
34
35namespace OpenSim.Region.ClientStack.Linden
36{
37 public class EventQueueHelper
38 {
39 private EventQueueHelper() {} // no construction possible, it's an utility class
40
41 private static byte[] ulongToByteArray(ulong uLongValue)
42 {
43 // Reverse endianness of RegionHandle
44 return new byte[]
45 {
46 (byte)((uLongValue >> 56) % 256),
47 (byte)((uLongValue >> 48) % 256),
48 (byte)((uLongValue >> 40) % 256),
49 (byte)((uLongValue >> 32) % 256),
50 (byte)((uLongValue >> 24) % 256),
51 (byte)((uLongValue >> 16) % 256),
52 (byte)((uLongValue >> 8) % 256),
53 (byte)(uLongValue % 256)
54 };
55 }
56
57// private static byte[] uintToByteArray(uint uIntValue)
58// {
59// byte[] result = new byte[4];
60// Utils.UIntToBytesBig(uIntValue, result, 0);
61// return result;
62// }
63
64 public static OSD BuildEvent(string eventName, OSD eventBody)
65 {
66 OSDMap llsdEvent = new OSDMap(2);
67 llsdEvent.Add("message", new OSDString(eventName));
68 llsdEvent.Add("body", eventBody);
69
70 return llsdEvent;
71 }
72
73 public static OSD EnableSimulator(ulong handle, IPEndPoint endPoint)
74 {
75 OSDMap llsdSimInfo = new OSDMap(3);
76
77 llsdSimInfo.Add("Handle", new OSDBinary(ulongToByteArray(handle)));
78 llsdSimInfo.Add("IP", new OSDBinary(endPoint.Address.GetAddressBytes()));
79 llsdSimInfo.Add("Port", new OSDInteger(endPoint.Port));
80
81 OSDArray arr = new OSDArray(1);
82 arr.Add(llsdSimInfo);
83
84 OSDMap llsdBody = new OSDMap(1);
85 llsdBody.Add("SimulatorInfo", arr);
86
87 return BuildEvent("EnableSimulator", llsdBody);
88 }
89
90 public static OSD DisableSimulator(ulong handle)
91 {
92 //OSDMap llsdSimInfo = new OSDMap(1);
93
94 //llsdSimInfo.Add("Handle", new OSDBinary(regionHandleToByteArray(handle)));
95
96 //OSDArray arr = new OSDArray(1);
97 //arr.Add(llsdSimInfo);
98
99 OSDMap llsdBody = new OSDMap(0);
100 //llsdBody.Add("SimulatorInfo", arr);
101
102 return BuildEvent("DisableSimulator", llsdBody);
103 }
104
105 public static OSD CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt,
106 IPEndPoint newRegionExternalEndPoint,
107 string capsURL, UUID agentID, UUID sessionID)
108 {
109 OSDArray lookAtArr = new OSDArray(3);
110 lookAtArr.Add(OSD.FromReal(lookAt.X));
111 lookAtArr.Add(OSD.FromReal(lookAt.Y));
112 lookAtArr.Add(OSD.FromReal(lookAt.Z));
113
114 OSDArray positionArr = new OSDArray(3);
115 positionArr.Add(OSD.FromReal(pos.X));
116 positionArr.Add(OSD.FromReal(pos.Y));
117 positionArr.Add(OSD.FromReal(pos.Z));
118
119 OSDMap infoMap = new OSDMap(2);
120 infoMap.Add("LookAt", lookAtArr);
121 infoMap.Add("Position", positionArr);
122
123 OSDArray infoArr = new OSDArray(1);
124 infoArr.Add(infoMap);
125
126 OSDMap agentDataMap = new OSDMap(2);
127 agentDataMap.Add("AgentID", OSD.FromUUID(agentID));
128 agentDataMap.Add("SessionID", OSD.FromUUID(sessionID));
129
130 OSDArray agentDataArr = new OSDArray(1);
131 agentDataArr.Add(agentDataMap);
132
133 OSDMap regionDataMap = new OSDMap(4);
134 regionDataMap.Add("RegionHandle", OSD.FromBinary(ulongToByteArray(handle)));
135 regionDataMap.Add("SeedCapability", OSD.FromString(capsURL));
136 regionDataMap.Add("SimIP", OSD.FromBinary(newRegionExternalEndPoint.Address.GetAddressBytes()));
137 regionDataMap.Add("SimPort", OSD.FromInteger(newRegionExternalEndPoint.Port));
138
139 OSDArray regionDataArr = new OSDArray(1);
140 regionDataArr.Add(regionDataMap);
141
142 OSDMap llsdBody = new OSDMap(3);
143 llsdBody.Add("Info", infoArr);
144 llsdBody.Add("AgentData", agentDataArr);
145 llsdBody.Add("RegionData", regionDataArr);
146
147 return BuildEvent("CrossedRegion", llsdBody);
148 }
149
150 public static OSD TeleportFinishEvent(
151 ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint,
152 uint locationID, uint flags, string capsURL, UUID agentID)
153 {
154 OSDMap info = new OSDMap();
155 info.Add("AgentID", OSD.FromUUID(agentID));
156 info.Add("LocationID", OSD.FromInteger(4)); // TODO what is this?
157 info.Add("RegionHandle", OSD.FromBinary(ulongToByteArray(regionHandle)));
158 info.Add("SeedCapability", OSD.FromString(capsURL));
159 info.Add("SimAccess", OSD.FromInteger(simAccess));
160 info.Add("SimIP", OSD.FromBinary(regionExternalEndPoint.Address.GetAddressBytes()));
161 info.Add("SimPort", OSD.FromInteger(regionExternalEndPoint.Port));
162 info.Add("TeleportFlags", OSD.FromULong(1L << 4)); // AgentManager.TeleportFlags.ViaLocation
163
164 OSDArray infoArr = new OSDArray();
165 infoArr.Add(info);
166
167 OSDMap body = new OSDMap();
168 body.Add("Info", infoArr);
169
170 return BuildEvent("TeleportFinish", body);
171 }
172
173 public static OSD ScriptRunningReplyEvent(UUID objectID, UUID itemID, bool running, bool mono)
174 {
175 OSDMap script = new OSDMap();
176 script.Add("ObjectID", OSD.FromUUID(objectID));
177 script.Add("ItemID", OSD.FromUUID(itemID));
178 script.Add("Running", OSD.FromBoolean(running));
179 script.Add("Mono", OSD.FromBoolean(mono));
180
181 OSDArray scriptArr = new OSDArray();
182 scriptArr.Add(script);
183
184 OSDMap body = new OSDMap();
185 body.Add("Script", scriptArr);
186
187 return BuildEvent("ScriptRunningReply", body);
188 }
189
190 public static OSD EstablishAgentCommunication(UUID agentID, string simIpAndPort, string seedcap)
191 {
192 OSDMap body = new OSDMap(3);
193 body.Add("agent-id", new OSDUUID(agentID));
194 body.Add("sim-ip-and-port", new OSDString(simIpAndPort));
195 body.Add("seed-capability", new OSDString(seedcap));
196
197 return BuildEvent("EstablishAgentCommunication", body);
198 }
199
200 public static OSD KeepAliveEvent()
201 {
202 return BuildEvent("FAKEEVENT", new OSDMap());
203 }
204
205 public static OSD AgentParams(UUID agentID, bool checkEstate, int godLevel, bool limitedToEstate)
206 {
207 OSDMap body = new OSDMap(4);
208
209 body.Add("agent_id", new OSDUUID(agentID));
210 body.Add("check_estate", new OSDInteger(checkEstate ? 1 : 0));
211 body.Add("god_level", new OSDInteger(godLevel));
212 body.Add("limited_to_estate", new OSDInteger(limitedToEstate ? 1 : 0));
213
214 return body;
215 }
216
217 public static OSD InstantMessageParams(UUID fromAgent, string message, UUID toAgent,
218 string fromName, byte dialog, uint timeStamp, bool offline, int parentEstateID,
219 Vector3 position, uint ttl, UUID transactionID, bool fromGroup, byte[] binaryBucket)
220 {
221 OSDMap messageParams = new OSDMap(15);
222 messageParams.Add("type", new OSDInteger((int)dialog));
223
224 OSDArray positionArray = new OSDArray(3);
225 positionArray.Add(OSD.FromReal(position.X));
226 positionArray.Add(OSD.FromReal(position.Y));
227 positionArray.Add(OSD.FromReal(position.Z));
228 messageParams.Add("position", positionArray);
229
230 messageParams.Add("region_id", new OSDUUID(UUID.Zero));
231 messageParams.Add("to_id", new OSDUUID(toAgent));
232 messageParams.Add("source", new OSDInteger(0));
233
234 OSDMap data = new OSDMap(1);
235 data.Add("binary_bucket", OSD.FromBinary(binaryBucket));
236 messageParams.Add("data", data);
237 messageParams.Add("message", new OSDString(message));
238 messageParams.Add("id", new OSDUUID(transactionID));
239 messageParams.Add("from_name", new OSDString(fromName));
240 messageParams.Add("timestamp", new OSDInteger((int)timeStamp));
241 messageParams.Add("offline", new OSDInteger(offline ? 1 : 0));
242 messageParams.Add("parent_estate_id", new OSDInteger(parentEstateID));
243 messageParams.Add("ttl", new OSDInteger((int)ttl));
244 messageParams.Add("from_id", new OSDUUID(fromAgent));
245 messageParams.Add("from_group", new OSDInteger(fromGroup ? 1 : 0));
246
247 return messageParams;
248 }
249
250 public static OSD InstantMessage(UUID fromAgent, string message, UUID toAgent,
251 string fromName, byte dialog, uint timeStamp, bool offline, int parentEstateID,
252 Vector3 position, uint ttl, UUID transactionID, bool fromGroup, byte[] binaryBucket,
253 bool checkEstate, int godLevel, bool limitedToEstate)
254 {
255 OSDMap im = new OSDMap(2);
256 im.Add("message_params", InstantMessageParams(fromAgent, message, toAgent,
257 fromName, dialog, timeStamp, offline, parentEstateID,
258 position, ttl, transactionID, fromGroup, binaryBucket));
259
260 im.Add("agent_params", AgentParams(fromAgent, checkEstate, godLevel, limitedToEstate));
261
262 return im;
263 }
264
265
266 public static OSD ChatterboxInvitation(UUID sessionID, string sessionName,
267 UUID fromAgent, string message, UUID toAgent, string fromName, byte dialog,
268 uint timeStamp, bool offline, int parentEstateID, Vector3 position,
269 uint ttl, UUID transactionID, bool fromGroup, byte[] binaryBucket)
270 {
271 OSDMap body = new OSDMap(5);
272 body.Add("session_id", new OSDUUID(sessionID));
273 body.Add("from_name", new OSDString(fromName));
274 body.Add("session_name", new OSDString(sessionName));
275 body.Add("from_id", new OSDUUID(fromAgent));
276
277 body.Add("instantmessage", InstantMessage(fromAgent, message, toAgent,
278 fromName, dialog, timeStamp, offline, parentEstateID, position,
279 ttl, transactionID, fromGroup, binaryBucket, true, 0, true));
280
281 OSDMap chatterboxInvitation = new OSDMap(2);
282 chatterboxInvitation.Add("message", new OSDString("ChatterBoxInvitation"));
283 chatterboxInvitation.Add("body", body);
284 return chatterboxInvitation;
285 }
286
287 public static OSD ChatterBoxSessionAgentListUpdates(UUID sessionID,
288 UUID agentID, bool canVoiceChat, bool isModerator, bool textMute)
289 {
290 OSDMap body = new OSDMap();
291 OSDMap agentUpdates = new OSDMap();
292 OSDMap infoDetail = new OSDMap();
293 OSDMap mutes = new OSDMap();
294
295 mutes.Add("text", OSD.FromBoolean(textMute));
296 infoDetail.Add("can_voice_chat", OSD.FromBoolean(canVoiceChat));
297 infoDetail.Add("is_moderator", OSD.FromBoolean(isModerator));
298 infoDetail.Add("mutes", mutes);
299 OSDMap info = new OSDMap();
300 info.Add("info", infoDetail);
301 agentUpdates.Add(agentID.ToString(), info);
302 body.Add("agent_updates", agentUpdates);
303 body.Add("session_id", OSD.FromUUID(sessionID));
304 body.Add("updates", new OSD());
305
306 OSDMap chatterBoxSessionAgentListUpdates = new OSDMap();
307 chatterBoxSessionAgentListUpdates.Add("message", OSD.FromString("ChatterBoxSessionAgentListUpdates"));
308 chatterBoxSessionAgentListUpdates.Add("body", body);
309
310 return chatterBoxSessionAgentListUpdates;
311 }
312
313 public static OSD GroupMembership(AgentGroupDataUpdatePacket groupUpdatePacket)
314 {
315 OSDMap groupUpdate = new OSDMap();
316 groupUpdate.Add("message", OSD.FromString("AgentGroupDataUpdate"));
317
318 OSDMap body = new OSDMap();
319 OSDArray agentData = new OSDArray();
320 OSDMap agentDataMap = new OSDMap();
321 agentDataMap.Add("AgentID", OSD.FromUUID(groupUpdatePacket.AgentData.AgentID));
322 agentData.Add(agentDataMap);
323 body.Add("AgentData", agentData);
324
325 OSDArray groupData = new OSDArray();
326
327 foreach (AgentGroupDataUpdatePacket.GroupDataBlock groupDataBlock in groupUpdatePacket.GroupData)
328 {
329 OSDMap groupDataMap = new OSDMap();
330 groupDataMap.Add("ListInProfile", OSD.FromBoolean(false));
331 groupDataMap.Add("GroupID", OSD.FromUUID(groupDataBlock.GroupID));
332 groupDataMap.Add("GroupInsigniaID", OSD.FromUUID(groupDataBlock.GroupInsigniaID));
333 groupDataMap.Add("Contribution", OSD.FromInteger(groupDataBlock.Contribution));
334 groupDataMap.Add("GroupPowers", OSD.FromBinary(ulongToByteArray(groupDataBlock.GroupPowers)));
335 groupDataMap.Add("GroupName", OSD.FromString(Utils.BytesToString(groupDataBlock.GroupName)));
336 groupDataMap.Add("AcceptNotices", OSD.FromBoolean(groupDataBlock.AcceptNotices));
337
338 groupData.Add(groupDataMap);
339
340 }
341 body.Add("GroupData", groupData);
342 groupUpdate.Add("body", body);
343
344 return groupUpdate;
345 }
346
347 public static OSD PlacesQuery(PlacesReplyPacket PlacesReply)
348 {
349 OSDMap placesReply = new OSDMap();
350 placesReply.Add("message", OSD.FromString("PlacesReplyMessage"));
351
352 OSDMap body = new OSDMap();
353 OSDArray agentData = new OSDArray();
354 OSDMap agentDataMap = new OSDMap();
355 agentDataMap.Add("AgentID", OSD.FromUUID(PlacesReply.AgentData.AgentID));
356 agentDataMap.Add("QueryID", OSD.FromUUID(PlacesReply.AgentData.QueryID));
357 agentDataMap.Add("TransactionID", OSD.FromUUID(PlacesReply.TransactionData.TransactionID));
358 agentData.Add(agentDataMap);
359 body.Add("AgentData", agentData);
360
361 OSDArray QueryData = new OSDArray();
362
363 foreach (PlacesReplyPacket.QueryDataBlock groupDataBlock in PlacesReply.QueryData)
364 {
365 OSDMap QueryDataMap = new OSDMap();
366 QueryDataMap.Add("ActualArea", OSD.FromInteger(groupDataBlock.ActualArea));
367 QueryDataMap.Add("BillableArea", OSD.FromInteger(groupDataBlock.BillableArea));
368 QueryDataMap.Add("Description", OSD.FromBinary(groupDataBlock.Desc));
369 QueryDataMap.Add("Dwell", OSD.FromInteger((int)groupDataBlock.Dwell));
370 QueryDataMap.Add("Flags", OSD.FromString(Convert.ToString(groupDataBlock.Flags)));
371 QueryDataMap.Add("GlobalX", OSD.FromInteger((int)groupDataBlock.GlobalX));
372 QueryDataMap.Add("GlobalY", OSD.FromInteger((int)groupDataBlock.GlobalY));
373 QueryDataMap.Add("GlobalZ", OSD.FromInteger((int)groupDataBlock.GlobalZ));
374 QueryDataMap.Add("Name", OSD.FromBinary(groupDataBlock.Name));
375 QueryDataMap.Add("OwnerID", OSD.FromUUID(groupDataBlock.OwnerID));
376 QueryDataMap.Add("SimName", OSD.FromBinary(groupDataBlock.SimName));
377 QueryDataMap.Add("SnapShotID", OSD.FromUUID(groupDataBlock.SnapshotID));
378 QueryDataMap.Add("ProductSku", OSD.FromInteger(0));
379 QueryDataMap.Add("Price", OSD.FromInteger(groupDataBlock.Price));
380
381 QueryData.Add(QueryDataMap);
382 }
383 body.Add("QueryData", QueryData);
384 placesReply.Add("QueryData[]", body);
385
386 return placesReply;
387 }
388
389 public static OSD ParcelProperties(ParcelPropertiesMessage parcelPropertiesMessage)
390 {
391 OSDMap message = new OSDMap();
392 message.Add("message", OSD.FromString("ParcelProperties"));
393 OSD message_body = parcelPropertiesMessage.Serialize();
394 message.Add("body", message_body);
395 return message;
396 }
397
398 }
399}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs
new file mode 100644
index 0000000..a5209b7
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs
@@ -0,0 +1,94 @@
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 log4net.Config;
32using Nini.Config;
33using NUnit.Framework;
34using OpenMetaverse;
35using OpenMetaverse.Packets;
36using OpenSim.Framework;
37using OpenSim.Framework.Servers;
38using OpenSim.Framework.Servers.HttpServer;
39using OpenSim.Region.ClientStack.Linden;
40using OpenSim.Region.CoreModules.Framework;
41using OpenSim.Tests.Common;
42using OpenSim.Tests.Common.Mock;
43
44namespace OpenSim.Region.ClientStack.Linden.Tests
45{
46 [TestFixture]
47 public class EventQueueTests
48 {
49 private TestScene m_scene;
50
51 [SetUp]
52 public void SetUp()
53 {
54 MainServer.Instance = new BaseHttpServer(9999, false, 9998, "");
55
56 IConfigSource config = new IniConfigSource();
57 config.AddConfig("Startup");
58 config.Configs["Startup"].Set("EventQueue", "true");
59
60 CapabilitiesModule capsModule = new CapabilitiesModule();
61 EventQueueGetModule eqgModule = new EventQueueGetModule();
62
63 m_scene = SceneHelpers.SetupScene();
64 SceneHelpers.SetupSceneModules(m_scene, config, capsModule, eqgModule);
65 }
66
67 [Test]
68 public void AddForClient()
69 {
70 TestHelpers.InMethod();
71// log4net.Config.XmlConfigurator.Configure();
72
73 SceneHelpers.AddScenePresence(m_scene, TestHelpers.ParseTail(0x1));
74
75 // TODO: Add more assertions for the other aspects of event queues
76 Assert.That(MainServer.Instance.GetPollServiceHandlerKeys().Count, Is.EqualTo(1));
77 }
78
79 [Test]
80 public void RemoveForClient()
81 {
82 TestHelpers.InMethod();
83// log4net.Config.XmlConfigurator.Configure();
84
85 UUID spId = TestHelpers.ParseTail(0x1);
86
87 SceneHelpers.AddScenePresence(m_scene, spId);
88 m_scene.IncomingCloseAgent(spId);
89
90 // TODO: Add more assertions for the other aspects of event queues
91 Assert.That(MainServer.Instance.GetPollServiceHandlerKeys().Count, Is.EqualTo(0));
92 }
93 }
94} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs
new file mode 100644
index 0000000..e7bd2e7
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs
@@ -0,0 +1,139 @@
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.Specialized;
31using System.Reflection;
32using System.IO;
33using System.Web;
34using Mono.Addins;
35using log4net;
36using Nini.Config;
37using OpenMetaverse;
38using OpenMetaverse.StructuredData;
39using OpenSim.Capabilities.Handlers;
40using OpenSim.Framework;
41using OpenSim.Framework.Servers;
42using OpenSim.Framework.Servers.HttpServer;
43using OpenSim.Region.Framework.Interfaces;
44using OpenSim.Region.Framework.Scenes;
45using OpenSim.Services.Interfaces;
46using Caps = OpenSim.Framework.Capabilities.Caps;
47
48namespace OpenSim.Region.ClientStack.Linden
49{
50 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
51 public class GetMeshModule : INonSharedRegionModule
52 {
53// private static readonly ILog m_log =
54// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
55
56 private Scene m_scene;
57 private IAssetService m_AssetService;
58 private bool m_Enabled = true;
59 private string m_URL;
60
61 #region IRegionModuleBase Members
62
63 public Type ReplaceableInterface
64 {
65 get { return null; }
66 }
67
68 public void Initialise(IConfigSource source)
69 {
70 IConfig config = source.Configs["ClientStack.LindenCaps"];
71 if (config == null)
72 return;
73
74 m_URL = config.GetString("Cap_GetMesh", string.Empty);
75 // Cap doesn't exist
76 if (m_URL != string.Empty)
77 m_Enabled = true;
78 }
79
80 public void AddRegion(Scene pScene)
81 {
82 if (!m_Enabled)
83 return;
84
85 m_scene = pScene;
86 }
87
88 public void RemoveRegion(Scene scene)
89 {
90 if (!m_Enabled)
91 return;
92
93 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
94 m_scene = null;
95 }
96
97 public void RegionLoaded(Scene scene)
98 {
99 if (!m_Enabled)
100 return;
101
102 m_AssetService = m_scene.RequestModuleInterface<IAssetService>();
103 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
104 }
105
106
107 public void Close() { }
108
109 public string Name { get { return "GetMeshModule"; } }
110
111 #endregion
112
113
114 public void RegisterCaps(UUID agentID, Caps caps)
115 {
116// UUID capID = UUID.Random();
117
118 //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture));
119 if (m_URL == "localhost")
120 {
121// m_log.DebugFormat("[GETMESH]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName);
122 GetMeshHandler gmeshHandler = new GetMeshHandler(m_AssetService);
123 IRequestHandler reqHandler = new RestHTTPHandler("GET", "/CAPS/" + UUID.Random(),
124 delegate(Hashtable m_dhttpMethod)
125 {
126 return gmeshHandler.ProcessGetMesh(m_dhttpMethod, UUID.Zero, null);
127 });
128
129 caps.RegisterHandler("GetMesh", reqHandler);
130 }
131 else
132 {
133// m_log.DebugFormat("[GETMESH]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName);
134 caps.RegisterHandler("GetMesh", m_URL);
135 }
136 }
137
138 }
139}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
new file mode 100644
index 0000000..fffcee2
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
@@ -0,0 +1,143 @@
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.Specialized;
31using System.Drawing;
32using System.Drawing.Imaging;
33using System.Reflection;
34using System.IO;
35using System.Web;
36using log4net;
37using Nini.Config;
38using Mono.Addins;
39using OpenMetaverse;
40using OpenMetaverse.StructuredData;
41using OpenMetaverse.Imaging;
42using OpenSim.Framework;
43using OpenSim.Framework.Servers;
44using OpenSim.Framework.Servers.HttpServer;
45using OpenSim.Region.Framework.Interfaces;
46using OpenSim.Region.Framework.Scenes;
47using OpenSim.Services.Interfaces;
48using Caps = OpenSim.Framework.Capabilities.Caps;
49using OpenSim.Capabilities.Handlers;
50
51namespace OpenSim.Region.ClientStack.Linden
52{
53
54 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
55 public class GetTextureModule : INonSharedRegionModule
56 {
57// private static readonly ILog m_log =
58// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
59
60 private Scene m_scene;
61 private IAssetService m_assetService;
62
63 private bool m_Enabled = false;
64
65 // TODO: Change this to a config option
66 const string REDIRECT_URL = null;
67
68 private string m_URL;
69
70 #region ISharedRegionModule Members
71
72 public void Initialise(IConfigSource source)
73 {
74 IConfig config = source.Configs["ClientStack.LindenCaps"];
75 if (config == null)
76 return;
77
78 m_URL = config.GetString("Cap_GetTexture", string.Empty);
79 // Cap doesn't exist
80 if (m_URL != string.Empty)
81 m_Enabled = true;
82 }
83
84 public void AddRegion(Scene s)
85 {
86 if (!m_Enabled)
87 return;
88
89 m_scene = s;
90 }
91
92 public void RemoveRegion(Scene s)
93 {
94 if (!m_Enabled)
95 return;
96
97 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
98 m_scene = null;
99 }
100
101 public void RegionLoaded(Scene s)
102 {
103 if (!m_Enabled)
104 return;
105
106 m_assetService = m_scene.RequestModuleInterface<IAssetService>();
107 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
108 }
109
110 public void PostInitialise()
111 {
112 }
113
114 public void Close() { }
115
116 public string Name { get { return "GetTextureModule"; } }
117
118 public Type ReplaceableInterface
119 {
120 get { return null; }
121 }
122
123 #endregion
124
125 public void RegisterCaps(UUID agentID, Caps caps)
126 {
127 UUID capID = UUID.Random();
128
129 //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture));
130 if (m_URL == "localhost")
131 {
132// m_log.DebugFormat("[GETTEXTURE]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName);
133 caps.RegisterHandler("GetTexture", new GetTextureHandler("/CAPS/" + capID + "/", m_assetService));
134 }
135 else
136 {
137// m_log.DebugFormat("[GETTEXTURE]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName);
138 caps.RegisterHandler("GetTexture", m_URL);
139 }
140 }
141
142 }
143}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs
new file mode 100644
index 0000000..18c7eae
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs
@@ -0,0 +1,149 @@
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.Reflection;
31using log4net;
32using Nini.Config;
33using Mono.Addins;
34using OpenMetaverse;
35using OpenMetaverse.StructuredData;
36using OpenSim.Framework;
37using OpenSim.Framework.Servers.HttpServer;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Services.Interfaces;
41using Caps = OpenSim.Framework.Capabilities.Caps;
42
43namespace OpenSim.Region.ClientStack.Linden
44{
45 /// <summary>
46 /// MeshUploadFlag capability. This is required for uploading Mesh.
47 /// </summary>
48 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
49 public class MeshUploadFlagModule : INonSharedRegionModule
50 {
51// private static readonly ILog m_log =
52// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
53
54 /// <summary>
55 /// Is this module enabled?
56 /// </summary>
57 public bool Enabled { get; private set; }
58
59 private Scene m_scene;
60 private UUID m_agentID;
61
62 #region ISharedRegionModule Members
63
64 public MeshUploadFlagModule()
65 {
66 Enabled = true;
67 }
68
69 public void Initialise(IConfigSource source)
70 {
71 IConfig config = source.Configs["Mesh"];
72 if (config == null)
73 {
74 return;
75 }
76 else
77 {
78 Enabled = config.GetBoolean("AllowMeshUpload", Enabled);
79 }
80 }
81
82 public void AddRegion(Scene s)
83 {
84 if (!Enabled)
85 return;
86
87 m_scene = s;
88 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
89 }
90
91 public void RemoveRegion(Scene s)
92 {
93 if (!Enabled)
94 return;
95
96 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
97 }
98
99 public void RegionLoaded(Scene s)
100 {
101 }
102
103 public void PostInitialise()
104 {
105 }
106
107 public void Close() { }
108
109 public string Name { get { return "MeshUploadFlagModule"; } }
110
111 public Type ReplaceableInterface
112 {
113 get { return null; }
114 }
115
116 #endregion
117
118 public void RegisterCaps(UUID agentID, Caps caps)
119 {
120 IRequestHandler reqHandler = new RestHTTPHandler("GET", "/CAPS/" + UUID.Random(), MeshUploadFlag);
121 caps.RegisterHandler("MeshUploadFlag", reqHandler);
122 m_agentID = agentID;
123 }
124
125 private Hashtable MeshUploadFlag(Hashtable mDhttpMethod)
126 {
127// m_log.DebugFormat("[MESH UPLOAD FLAG MODULE]: MeshUploadFlag request");
128
129 OSDMap data = new OSDMap();
130 ScenePresence sp = m_scene.GetScenePresence(m_agentID);
131 data["username"] = sp.Firstname + "." + sp.Lastname;
132 data["display_name_next_update"] = new OSDDate(DateTime.Now);
133 data["legacy_first_name"] = sp.Firstname;
134 data["mesh_upload_status"] = "valid";
135 data["display_name"] = sp.Firstname + " " + sp.Lastname;
136 data["legacy_last_name"] = sp.Lastname;
137 data["id"] = m_agentID;
138 data["is_display_name_default"] = true;
139
140 //Send back data
141 Hashtable responsedata = new Hashtable();
142 responsedata["int_response_code"] = 200;
143 responsedata["content_type"] = "text/plain";
144 responsedata["keepalive"] = false;
145 responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(data);
146 return responsedata;
147 }
148 }
149} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs
new file mode 100644
index 0000000..b2f04f9
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs
@@ -0,0 +1,271 @@
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.Specialized;
31using System.Reflection;
32using System.IO;
33using System.Web;
34using Mono.Addins;
35using log4net;
36using Nini.Config;
37using OpenMetaverse;
38using OpenMetaverse.StructuredData;
39using OpenSim.Framework;
40using OpenSim.Framework.Servers;
41using OpenSim.Framework.Servers.HttpServer;
42using OpenSim.Region.Framework.Interfaces;
43using OpenSim.Region.Framework.Scenes;
44using OpenSim.Services.Interfaces;
45using Caps = OpenSim.Framework.Capabilities.Caps;
46using OpenSim.Framework.Capabilities;
47
48namespace OpenSim.Region.ClientStack.Linden
49{
50 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
51 public class NewFileAgentInventoryVariablePriceModule : INonSharedRegionModule
52 {
53// private static readonly ILog m_log =
54// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
55
56 private Scene m_scene;
57// private IAssetService m_assetService;
58 private bool m_dumpAssetsToFile = false;
59 private bool m_enabled = true;
60
61 #region IRegionModuleBase Members
62
63
64 public Type ReplaceableInterface
65 {
66 get { return null; }
67 }
68
69 public void Initialise(IConfigSource source)
70 {
71 IConfig meshConfig = source.Configs["Mesh"];
72 if (meshConfig == null)
73 return;
74
75 m_enabled = meshConfig.GetBoolean("AllowMeshUpload", true);
76 }
77
78 public void AddRegion(Scene pScene)
79 {
80 m_scene = pScene;
81 }
82
83 public void RemoveRegion(Scene scene)
84 {
85
86 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
87 m_scene = null;
88 }
89
90 public void RegionLoaded(Scene scene)
91 {
92
93// m_assetService = m_scene.RequestModuleInterface<IAssetService>();
94 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
95 }
96
97 #endregion
98
99
100 #region IRegionModule Members
101
102
103
104 public void Close() { }
105
106 public string Name { get { return "NewFileAgentInventoryVariablePriceModule"; } }
107
108
109 public void RegisterCaps(UUID agentID, Caps caps)
110 {
111 if(!m_enabled)
112 return;
113
114 UUID capID = UUID.Random();
115
116// m_log.Debug("[NEW FILE AGENT INVENTORY VARIABLE PRICE]: /CAPS/" + capID);
117 caps.RegisterHandler("NewFileAgentInventoryVariablePrice",
118
119 new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDNewFileAngentInventoryVariablePriceReplyResponse>("POST",
120 "/CAPS/" + capID.ToString(),
121 delegate(LLSDAssetUploadRequest req)
122 {
123 return NewAgentInventoryRequest(req,agentID);
124 }));
125
126 }
127
128 #endregion
129
130 public LLSDNewFileAngentInventoryVariablePriceReplyResponse NewAgentInventoryRequest(LLSDAssetUploadRequest llsdRequest, UUID agentID)
131 {
132
133 //TODO: The Mesh uploader uploads many types of content. If you're going to implement a Money based limit
134 // You need to be aware of this and
135
136
137 //if (llsdRequest.asset_type == "texture" ||
138 // llsdRequest.asset_type == "animation" ||
139 // llsdRequest.asset_type == "sound")
140 // {
141 IClientAPI client = null;
142
143
144 IMoneyModule mm = m_scene.RequestModuleInterface<IMoneyModule>();
145
146 if (mm != null)
147 {
148 if (m_scene.TryGetClient(agentID, out client))
149 {
150 if (!mm.UploadCovered(client, mm.UploadCharge))
151 {
152 if (client != null)
153 client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false);
154
155 LLSDNewFileAngentInventoryVariablePriceReplyResponse errorResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse();
156 errorResponse.rsvp = "";
157 errorResponse.state = "error";
158 return errorResponse;
159 }
160 }
161 }
162 // }
163
164 string assetName = llsdRequest.name;
165 string assetDes = llsdRequest.description;
166 string capsBase = "/CAPS/NewFileAgentInventoryVariablePrice/";
167 UUID newAsset = UUID.Random();
168 UUID newInvItem = UUID.Random();
169 UUID parentFolder = llsdRequest.folder_id;
170 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000") + "/";
171
172 AssetUploader uploader =
173 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type,
174 llsdRequest.asset_type, capsBase + uploaderPath, MainServer.Instance, m_dumpAssetsToFile);
175 MainServer.Instance.AddStreamHandler(
176 new BinaryStreamHandler("POST", capsBase + uploaderPath, uploader.uploaderCaps));
177
178 string protocol = "http://";
179
180 if (MainServer.Instance.UseSSL)
181 protocol = "https://";
182
183 string uploaderURL = protocol + m_scene.RegionInfo.ExternalHostName + ":" + MainServer.Instance.Port.ToString() + capsBase +
184 uploaderPath;
185
186
187 LLSDNewFileAngentInventoryVariablePriceReplyResponse uploadResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse();
188
189
190 uploadResponse.rsvp = uploaderURL;
191 uploadResponse.state = "upload";
192 uploadResponse.resource_cost = 0;
193 uploadResponse.upload_price = 0;
194
195 uploader.OnUpLoad += //UploadCompleteHandler;
196
197 delegate(
198 string passetName, string passetDescription, UUID passetID,
199 UUID pinventoryItem, UUID pparentFolder, byte[] pdata, string pinventoryType,
200 string passetType)
201 {
202 UploadCompleteHandler(passetName, passetDescription, passetID,
203 pinventoryItem, pparentFolder, pdata, pinventoryType,
204 passetType,agentID);
205 };
206 return uploadResponse;
207 }
208
209 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID,
210 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType,
211 string assetType,UUID AgentID)
212 {
213 sbyte assType = 0;
214 sbyte inType = 0;
215
216 if (inventoryType == "sound")
217 {
218 inType = 1;
219 assType = 1;
220 }
221 else if (inventoryType == "animation")
222 {
223 inType = 19;
224 assType = 20;
225 }
226 else if (inventoryType == "wearable")
227 {
228 inType = 18;
229 switch (assetType)
230 {
231 case "bodypart":
232 assType = 13;
233 break;
234 case "clothing":
235 assType = 5;
236 break;
237 }
238 }
239 else if (inventoryType == "mesh")
240 {
241 inType = (sbyte)InventoryType.Mesh;
242 assType = (sbyte)AssetType.Mesh;
243 }
244
245 AssetBase asset;
246 asset = new AssetBase(assetID, assetName, assType, AgentID.ToString());
247 asset.Data = data;
248
249 if (m_scene.AssetService != null)
250 m_scene.AssetService.Store(asset);
251
252 InventoryItemBase item = new InventoryItemBase();
253 item.Owner = AgentID;
254 item.CreatorId = AgentID.ToString();
255 item.ID = inventoryItem;
256 item.AssetID = asset.FullID;
257 item.Description = assetDescription;
258 item.Name = assetName;
259 item.AssetType = assType;
260 item.InvType = inType;
261 item.Folder = parentFolder;
262 item.CurrentPermissions = (uint)PermissionMask.All;
263 item.BasePermissions = (uint)PermissionMask.All;
264 item.EveryOnePermissions = 0;
265 item.NextPermissions = (uint)PermissionMask.All;
266 item.CreationDate = Util.UnixTimeSinceEpoch();
267 m_scene.AddInventoryItem(item);
268
269 }
270 }
271} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs
new file mode 100644
index 0000000..1c47f0e
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs
@@ -0,0 +1,368 @@
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.Reflection;
31using log4net;
32using Nini.Config;
33using OpenMetaverse;
34using OpenMetaverse.StructuredData;
35using OpenSim.Framework;
36using OpenSim.Framework.Servers;
37using OpenSim.Framework.Servers.HttpServer;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes;
40using Caps=OpenSim.Framework.Capabilities.Caps;
41
42namespace OpenSim.Region.ClientStack.Linden
43{
44 public class ObjectAdd : IRegionModule
45 {
46// private static readonly ILog m_log =
47// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48
49 private Scene m_scene;
50 #region IRegionModule Members
51
52 public void Initialise(Scene pScene, IConfigSource pSource)
53 {
54 m_scene = pScene;
55 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
56 }
57
58 public void PostInitialise()
59 {
60
61 }
62
63 public void RegisterCaps(UUID agentID, Caps caps)
64 {
65 UUID capuuid = UUID.Random();
66
67// m_log.InfoFormat("[OBJECTADD]: {0}", "/CAPS/OA/" + capuuid + "/");
68
69 caps.RegisterHandler("ObjectAdd",
70 new RestHTTPHandler("POST", "/CAPS/OA/" + capuuid + "/",
71 delegate(Hashtable m_dhttpMethod)
72 {
73 return ProcessAdd(m_dhttpMethod, agentID, caps);
74 }));
75 }
76
77 public Hashtable ProcessAdd(Hashtable request, UUID AgentId, Caps cap)
78 {
79 Hashtable responsedata = new Hashtable();
80 responsedata["int_response_code"] = 400; //501; //410; //404;
81 responsedata["content_type"] = "text/plain";
82 responsedata["keepalive"] = false;
83 responsedata["str_response_string"] = "Request wasn't what was expected";
84 ScenePresence avatar;
85
86 if (!m_scene.TryGetScenePresence(AgentId, out avatar))
87 return responsedata;
88
89
90 OSD r = OSDParser.DeserializeLLSDXml((string)request["requestbody"]);
91 //UUID session_id = UUID.Zero;
92 bool bypass_raycast = false;
93 uint everyone_mask = 0;
94 uint group_mask = 0;
95 uint next_owner_mask = 0;
96 uint flags = 0;
97 UUID group_id = UUID.Zero;
98 int hollow = 0;
99 int material = 0;
100 int p_code = 0;
101 int path_begin = 0;
102 int path_curve = 0;
103 int path_end = 0;
104 int path_radius_offset = 0;
105 int path_revolutions = 0;
106 int path_scale_x = 0;
107 int path_scale_y = 0;
108 int path_shear_x = 0;
109 int path_shear_y = 0;
110 int path_skew = 0;
111 int path_taper_x = 0;
112 int path_taper_y = 0;
113 int path_twist = 0;
114 int path_twist_begin = 0;
115 int profile_begin = 0;
116 int profile_curve = 0;
117 int profile_end = 0;
118 Vector3 ray_end = Vector3.Zero;
119 bool ray_end_is_intersection = false;
120 Vector3 ray_start = Vector3.Zero;
121 UUID ray_target_id = UUID.Zero;
122 Quaternion rotation = Quaternion.Identity;
123 Vector3 scale = Vector3.Zero;
124 int state = 0;
125
126 if (r.Type != OSDType.Map) // not a proper req
127 return responsedata;
128
129 OSDMap rm = (OSDMap)r;
130
131 if (rm.ContainsKey("ObjectData")) //v2
132 {
133 if (rm["ObjectData"].Type != OSDType.Map)
134 {
135 responsedata["str_response_string"] = "Has ObjectData key, but data not in expected format";
136 return responsedata;
137 }
138
139 OSDMap ObjMap = (OSDMap) rm["ObjectData"];
140
141 bypass_raycast = ObjMap["BypassRaycast"].AsBoolean();
142 everyone_mask = readuintval(ObjMap["EveryoneMask"]);
143 flags = readuintval(ObjMap["Flags"]);
144 group_mask = readuintval(ObjMap["GroupMask"]);
145 material = ObjMap["Material"].AsInteger();
146 next_owner_mask = readuintval(ObjMap["NextOwnerMask"]);
147 p_code = ObjMap["PCode"].AsInteger();
148
149 if (ObjMap.ContainsKey("Path"))
150 {
151 if (ObjMap["Path"].Type != OSDType.Map)
152 {
153 responsedata["str_response_string"] = "Has Path key, but data not in expected format";
154 return responsedata;
155 }
156
157 OSDMap PathMap = (OSDMap)ObjMap["Path"];
158 path_begin = PathMap["Begin"].AsInteger();
159 path_curve = PathMap["Curve"].AsInteger();
160 path_end = PathMap["End"].AsInteger();
161 path_radius_offset = PathMap["RadiusOffset"].AsInteger();
162 path_revolutions = PathMap["Revolutions"].AsInteger();
163 path_scale_x = PathMap["ScaleX"].AsInteger();
164 path_scale_y = PathMap["ScaleY"].AsInteger();
165 path_shear_x = PathMap["ShearX"].AsInteger();
166 path_shear_y = PathMap["ShearY"].AsInteger();
167 path_skew = PathMap["Skew"].AsInteger();
168 path_taper_x = PathMap["TaperX"].AsInteger();
169 path_taper_y = PathMap["TaperY"].AsInteger();
170 path_twist = PathMap["Twist"].AsInteger();
171 path_twist_begin = PathMap["TwistBegin"].AsInteger();
172
173 }
174
175 if (ObjMap.ContainsKey("Profile"))
176 {
177 if (ObjMap["Profile"].Type != OSDType.Map)
178 {
179 responsedata["str_response_string"] = "Has Profile key, but data not in expected format";
180 return responsedata;
181 }
182
183 OSDMap ProfileMap = (OSDMap)ObjMap["Profile"];
184
185 profile_begin = ProfileMap["Begin"].AsInteger();
186 profile_curve = ProfileMap["Curve"].AsInteger();
187 profile_end = ProfileMap["End"].AsInteger();
188 hollow = ProfileMap["Hollow"].AsInteger();
189 }
190 ray_end_is_intersection = ObjMap["RayEndIsIntersection"].AsBoolean();
191
192 ray_target_id = ObjMap["RayTargetId"].AsUUID();
193 state = ObjMap["State"].AsInteger();
194 try
195 {
196 ray_end = ((OSDArray) ObjMap["RayEnd"]).AsVector3();
197 ray_start = ((OSDArray) ObjMap["RayStart"]).AsVector3();
198 scale = ((OSDArray) ObjMap["Scale"]).AsVector3();
199 rotation = ((OSDArray)ObjMap["Rotation"]).AsQuaternion();
200 }
201 catch (Exception)
202 {
203 responsedata["str_response_string"] = "RayEnd, RayStart, Scale or Rotation wasn't in the expected format";
204 return responsedata;
205 }
206
207 if (rm.ContainsKey("AgentData"))
208 {
209 if (rm["AgentData"].Type != OSDType.Map)
210 {
211 responsedata["str_response_string"] = "Has AgentData key, but data not in expected format";
212 return responsedata;
213 }
214
215 OSDMap AgentDataMap = (OSDMap) rm["AgentData"];
216
217 //session_id = AgentDataMap["SessionId"].AsUUID();
218 group_id = AgentDataMap["GroupId"].AsUUID();
219 }
220
221 }
222 else
223 { //v1
224 bypass_raycast = rm["bypass_raycast"].AsBoolean();
225
226 everyone_mask = readuintval(rm["everyone_mask"]);
227 flags = readuintval(rm["flags"]);
228 group_id = rm["group_id"].AsUUID();
229 group_mask = readuintval(rm["group_mask"]);
230 hollow = rm["hollow"].AsInteger();
231 material = rm["material"].AsInteger();
232 next_owner_mask = readuintval(rm["next_owner_mask"]);
233 hollow = rm["hollow"].AsInteger();
234 p_code = rm["p_code"].AsInteger();
235 path_begin = rm["path_begin"].AsInteger();
236 path_curve = rm["path_curve"].AsInteger();
237 path_end = rm["path_end"].AsInteger();
238 path_radius_offset = rm["path_radius_offset"].AsInteger();
239 path_revolutions = rm["path_revolutions"].AsInteger();
240 path_scale_x = rm["path_scale_x"].AsInteger();
241 path_scale_y = rm["path_scale_y"].AsInteger();
242 path_shear_x = rm["path_shear_x"].AsInteger();
243 path_shear_y = rm["path_shear_y"].AsInteger();
244 path_skew = rm["path_skew"].AsInteger();
245 path_taper_x = rm["path_taper_x"].AsInteger();
246 path_taper_y = rm["path_taper_y"].AsInteger();
247 path_twist = rm["path_twist"].AsInteger();
248 path_twist_begin = rm["path_twist_begin"].AsInteger();
249 profile_begin = rm["profile_begin"].AsInteger();
250 profile_curve = rm["profile_curve"].AsInteger();
251 profile_end = rm["profile_end"].AsInteger();
252
253 ray_end_is_intersection = rm["ray_end_is_intersection"].AsBoolean();
254
255 ray_target_id = rm["ray_target_id"].AsUUID();
256
257
258 //session_id = rm["session_id"].AsUUID();
259 state = rm["state"].AsInteger();
260 try
261 {
262 ray_end = ((OSDArray)rm["ray_end"]).AsVector3();
263 ray_start = ((OSDArray)rm["ray_start"]).AsVector3();
264 rotation = ((OSDArray)rm["rotation"]).AsQuaternion();
265 scale = ((OSDArray)rm["scale"]).AsVector3();
266 }
267 catch (Exception)
268 {
269 responsedata["str_response_string"] = "RayEnd, RayStart, Scale or Rotation wasn't in the expected format";
270 return responsedata;
271 }
272 }
273
274
275
276 Vector3 pos = m_scene.GetNewRezLocation(ray_start, ray_end, ray_target_id, rotation, (bypass_raycast) ? (byte)1 : (byte)0, (ray_end_is_intersection) ? (byte)1 : (byte)0, true, scale, false);
277
278 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox();
279
280 pbs.PathBegin = (ushort)path_begin;
281 pbs.PathCurve = (byte)path_curve;
282 pbs.PathEnd = (ushort)path_end;
283 pbs.PathRadiusOffset = (sbyte)path_radius_offset;
284 pbs.PathRevolutions = (byte)path_revolutions;
285 pbs.PathScaleX = (byte)path_scale_x;
286 pbs.PathScaleY = (byte)path_scale_y;
287 pbs.PathShearX = (byte) path_shear_x;
288 pbs.PathShearY = (byte)path_shear_y;
289 pbs.PathSkew = (sbyte)path_skew;
290 pbs.PathTaperX = (sbyte)path_taper_x;
291 pbs.PathTaperY = (sbyte)path_taper_y;
292 pbs.PathTwist = (sbyte)path_twist;
293 pbs.PathTwistBegin = (sbyte)path_twist_begin;
294 pbs.HollowShape = (HollowShape) hollow;
295 pbs.PCode = (byte)p_code;
296 pbs.ProfileBegin = (ushort) profile_begin;
297 pbs.ProfileCurve = (byte) profile_curve;
298 pbs.ProfileEnd = (ushort)profile_end;
299 pbs.Scale = scale;
300 pbs.State = (byte)state;
301
302 SceneObjectGroup obj = null; ;
303
304 if (m_scene.Permissions.CanRezObject(1, avatar.UUID, pos))
305 {
306 // rez ON the ground, not IN the ground
307 // pos.Z += 0.25F;
308
309 obj = m_scene.AddNewPrim(avatar.UUID, group_id, pos, rotation, pbs);
310 }
311
312
313 if (obj == null)
314 return responsedata;
315
316 SceneObjectPart rootpart = obj.RootPart;
317 rootpart.Shape = pbs;
318 rootpart.Flags |= (PrimFlags)flags;
319 rootpart.EveryoneMask = everyone_mask;
320 rootpart.GroupID = group_id;
321 rootpart.GroupMask = group_mask;
322 rootpart.NextOwnerMask = next_owner_mask;
323 rootpart.Material = (byte)material;
324
325 m_scene.PhysicsScene.AddPhysicsActorTaint(rootpart.PhysActor);
326
327 responsedata["int_response_code"] = 200; //501; //410; //404;
328 responsedata["content_type"] = "text/plain";
329 responsedata["keepalive"] = false;
330 responsedata["str_response_string"] = String.Format("<llsd><map><key>local_id</key>{0}</map></llsd>",ConvertUintToBytes(obj.LocalId));
331
332 return responsedata;
333 }
334
335 private uint readuintval(OSD obj)
336 {
337 byte[] tmp = obj.AsBinary();
338 if (BitConverter.IsLittleEndian)
339 Array.Reverse(tmp);
340 return Utils.BytesToUInt(tmp);
341
342 }
343 private string ConvertUintToBytes(uint val)
344 {
345 byte[] resultbytes = Utils.UIntToBytes(val);
346 if (BitConverter.IsLittleEndian)
347 Array.Reverse(resultbytes);
348 return String.Format("<binary encoding=\"base64\">{0}</binary>",Convert.ToBase64String(resultbytes));
349 }
350
351 public void Close()
352 {
353
354 }
355
356 public string Name
357 {
358 get { return "ObjectAddModule"; }
359 }
360
361 public bool IsSharedModule
362 {
363 get { return false; }
364 }
365
366 #endregion
367 }
368}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs
new file mode 100644
index 0000000..e4bacd4
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs
@@ -0,0 +1,375 @@
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.Specialized;
31using System.Reflection;
32using System.IO;
33using System.Web;
34using Mono.Addins;
35using log4net;
36using Nini.Config;
37using OpenMetaverse;
38using OpenMetaverse.StructuredData;
39using OpenMetaverse.Messages.Linden;
40using OpenSim.Framework;
41using OpenSim.Framework.Servers;
42using OpenSim.Framework.Servers.HttpServer;
43using OpenSim.Region.Framework.Interfaces;
44using OpenSim.Region.Framework.Scenes;
45using OpenSim.Services.Interfaces;
46using Caps = OpenSim.Framework.Capabilities.Caps;
47using OSD = OpenMetaverse.StructuredData.OSD;
48using OSDMap = OpenMetaverse.StructuredData.OSDMap;
49using OpenSim.Framework.Capabilities;
50using ExtraParamType = OpenMetaverse.ExtraParamType;
51
52namespace OpenSim.Region.ClientStack.Linden
53{
54 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
55 public class UploadObjectAssetModule : INonSharedRegionModule
56 {
57 private static readonly ILog m_log =
58 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
59 private Scene m_scene;
60
61 #region IRegionModuleBase Members
62
63
64 public Type ReplaceableInterface
65 {
66 get { return null; }
67 }
68
69 public void Initialise(IConfigSource source)
70 {
71
72 }
73
74 public void AddRegion(Scene pScene)
75 {
76 m_scene = pScene;
77 }
78
79 public void RemoveRegion(Scene scene)
80 {
81
82 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
83 m_scene = null;
84 }
85
86 public void RegionLoaded(Scene scene)
87 {
88
89 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
90 }
91
92 #endregion
93
94
95 #region IRegionModule Members
96
97
98
99 public void Close() { }
100
101 public string Name { get { return "UploadObjectAssetModuleModule"; } }
102
103
104 public void RegisterCaps(UUID agentID, Caps caps)
105 {
106 UUID capID = UUID.Random();
107
108// m_log.Debug("[UPLOAD OBJECT ASSET MODULE]: /CAPS/" + capID);
109 caps.RegisterHandler("UploadObjectAsset",
110 new RestHTTPHandler("POST", "/CAPS/OA/" + capID + "/",
111 delegate(Hashtable m_dhttpMethod)
112 {
113 return ProcessAdd(m_dhttpMethod, agentID, caps);
114 }));
115 /*
116 caps.RegisterHandler("NewFileAgentInventoryVariablePrice",
117
118 new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDNewFileAngentInventoryVariablePriceReplyResponse>("POST",
119 "/CAPS/" + capID.ToString(),
120 delegate(LLSDAssetUploadRequest req)
121 {
122 return NewAgentInventoryRequest(req,agentID);
123 }));
124 */
125
126 }
127
128 #endregion
129
130
131 /// <summary>
132 /// Parses add request
133 /// </summary>
134 /// <param name="request"></param>
135 /// <param name="AgentId"></param>
136 /// <param name="cap"></param>
137 /// <returns></returns>
138 public Hashtable ProcessAdd(Hashtable request, UUID AgentId, Caps cap)
139 {
140 Hashtable responsedata = new Hashtable();
141 responsedata["int_response_code"] = 400; //501; //410; //404;
142 responsedata["content_type"] = "text/plain";
143 responsedata["keepalive"] = false;
144 responsedata["str_response_string"] = "Request wasn't what was expected";
145 ScenePresence avatar;
146
147 if (!m_scene.TryGetScenePresence(AgentId, out avatar))
148 return responsedata;
149
150 OSDMap r = (OSDMap)OSDParser.Deserialize((string)request["requestbody"]);
151 UploadObjectAssetMessage message = new UploadObjectAssetMessage();
152 try
153 {
154 message.Deserialize(r);
155
156 }
157 catch (Exception ex)
158 {
159 m_log.Error("[UPLOAD OBJECT ASSET MODULE]: Error deserializing message " + ex.ToString());
160 message = null;
161 }
162
163 if (message == null)
164 {
165 responsedata["int_response_code"] = 400; //501; //410; //404;
166 responsedata["content_type"] = "text/plain";
167 responsedata["keepalive"] = false;
168 responsedata["str_response_string"] =
169 "<llsd><map><key>error</key><string>Error parsing Object</string></map></llsd>";
170
171 return responsedata;
172 }
173
174 Vector3 pos = avatar.AbsolutePosition + (Vector3.UnitX * avatar.Rotation);
175 Quaternion rot = Quaternion.Identity;
176 Vector3 rootpos = Vector3.Zero;
177// Quaternion rootrot = Quaternion.Identity;
178
179 SceneObjectGroup rootGroup = null;
180 SceneObjectGroup[] allparts = new SceneObjectGroup[message.Objects.Length];
181 for (int i = 0; i < message.Objects.Length; i++)
182 {
183 UploadObjectAssetMessage.Object obj = message.Objects[i];
184 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox();
185
186 if (i == 0)
187 {
188 rootpos = obj.Position;
189// rootrot = obj.Rotation;
190 }
191
192 // Combine the extraparams data into it's ugly blob again....
193 //int bytelength = 0;
194 //for (int extparams = 0; extparams < obj.ExtraParams.Length; extparams++)
195 //{
196 // bytelength += obj.ExtraParams[extparams].ExtraParamData.Length;
197 //}
198 //byte[] extraparams = new byte[bytelength];
199 //int position = 0;
200
201
202
203 //for (int extparams = 0; extparams < obj.ExtraParams.Length; extparams++)
204 //{
205 // Buffer.BlockCopy(obj.ExtraParams[extparams].ExtraParamData, 0, extraparams, position,
206 // obj.ExtraParams[extparams].ExtraParamData.Length);
207 //
208 // position += obj.ExtraParams[extparams].ExtraParamData.Length;
209 // }
210
211 //pbs.ExtraParams = extraparams;
212 for (int extparams = 0; extparams < obj.ExtraParams.Length; extparams++)
213 {
214 UploadObjectAssetMessage.Object.ExtraParam extraParam = obj.ExtraParams[extparams];
215 switch ((ushort)extraParam.Type)
216 {
217 case (ushort)ExtraParamType.Sculpt:
218 Primitive.SculptData sculpt = new Primitive.SculptData(extraParam.ExtraParamData, 0);
219
220 pbs.SculptEntry = true;
221
222 pbs.SculptTexture = obj.SculptID;
223 pbs.SculptType = (byte)sculpt.Type;
224
225 break;
226 case (ushort)ExtraParamType.Flexible:
227 Primitive.FlexibleData flex = new Primitive.FlexibleData(extraParam.ExtraParamData, 0);
228 pbs.FlexiEntry = true;
229 pbs.FlexiDrag = flex.Drag;
230 pbs.FlexiForceX = flex.Force.X;
231 pbs.FlexiForceY = flex.Force.Y;
232 pbs.FlexiForceZ = flex.Force.Z;
233 pbs.FlexiGravity = flex.Gravity;
234 pbs.FlexiSoftness = flex.Softness;
235 pbs.FlexiTension = flex.Tension;
236 pbs.FlexiWind = flex.Wind;
237 break;
238 case (ushort)ExtraParamType.Light:
239 Primitive.LightData light = new Primitive.LightData(extraParam.ExtraParamData, 0);
240 pbs.LightColorA = light.Color.A;
241 pbs.LightColorB = light.Color.B;
242 pbs.LightColorG = light.Color.G;
243 pbs.LightColorR = light.Color.R;
244 pbs.LightCutoff = light.Cutoff;
245 pbs.LightEntry = true;
246 pbs.LightFalloff = light.Falloff;
247 pbs.LightIntensity = light.Intensity;
248 pbs.LightRadius = light.Radius;
249 break;
250 case 0x40:
251 pbs.ReadProjectionData(extraParam.ExtraParamData, 0);
252 break;
253 }
254 }
255
256 pbs.PathBegin = (ushort) obj.PathBegin;
257 pbs.PathCurve = (byte) obj.PathCurve;
258 pbs.PathEnd = (ushort) obj.PathEnd;
259 pbs.PathRadiusOffset = (sbyte) obj.RadiusOffset;
260 pbs.PathRevolutions = (byte) obj.Revolutions;
261 pbs.PathScaleX = (byte) obj.ScaleX;
262 pbs.PathScaleY = (byte) obj.ScaleY;
263 pbs.PathShearX = (byte) obj.ShearX;
264 pbs.PathShearY = (byte) obj.ShearY;
265 pbs.PathSkew = (sbyte) obj.Skew;
266 pbs.PathTaperX = (sbyte) obj.TaperX;
267 pbs.PathTaperY = (sbyte) obj.TaperY;
268 pbs.PathTwist = (sbyte) obj.Twist;
269 pbs.PathTwistBegin = (sbyte) obj.TwistBegin;
270 pbs.HollowShape = (HollowShape) obj.ProfileHollow;
271 pbs.PCode = (byte) PCode.Prim;
272 pbs.ProfileBegin = (ushort) obj.ProfileBegin;
273 pbs.ProfileCurve = (byte) obj.ProfileCurve;
274 pbs.ProfileEnd = (ushort) obj.ProfileEnd;
275 pbs.Scale = obj.Scale;
276 pbs.State = (byte) 0;
277 SceneObjectPart prim = new SceneObjectPart();
278 prim.UUID = UUID.Random();
279 prim.CreatorID = AgentId;
280 prim.OwnerID = AgentId;
281 prim.GroupID = obj.GroupID;
282 prim.LastOwnerID = prim.OwnerID;
283 prim.CreationDate = Util.UnixTimeSinceEpoch();
284 prim.Name = obj.Name;
285 prim.Description = "";
286
287 prim.PayPrice[0] = -2;
288 prim.PayPrice[1] = -2;
289 prim.PayPrice[2] = -2;
290 prim.PayPrice[3] = -2;
291 prim.PayPrice[4] = -2;
292 Primitive.TextureEntry tmp =
293 new Primitive.TextureEntry(UUID.Parse("89556747-24cb-43ed-920b-47caed15465f"));
294
295 for (int j = 0; j < obj.Faces.Length; j++)
296 {
297 UploadObjectAssetMessage.Object.Face face = obj.Faces[j];
298
299 Primitive.TextureEntryFace primFace = tmp.CreateFace((uint) j);
300
301 primFace.Bump = face.Bump;
302 primFace.RGBA = face.Color;
303 primFace.Fullbright = face.Fullbright;
304 primFace.Glow = face.Glow;
305 primFace.TextureID = face.ImageID;
306 primFace.Rotation = face.ImageRot;
307 primFace.MediaFlags = ((face.MediaFlags & 1) != 0);
308
309 primFace.OffsetU = face.OffsetS;
310 primFace.OffsetV = face.OffsetT;
311 primFace.RepeatU = face.ScaleS;
312 primFace.RepeatV = face.ScaleT;
313 primFace.TexMapType = (MappingType) (face.MediaFlags & 6);
314 }
315
316 pbs.TextureEntry = tmp.GetBytes();
317 prim.Shape = pbs;
318 prim.Scale = obj.Scale;
319
320 SceneObjectGroup grp = new SceneObjectGroup();
321
322 grp.SetRootPart(prim);
323 prim.ParentID = 0;
324 if (i == 0)
325 {
326 rootGroup = grp;
327
328 }
329 grp.AttachToScene(m_scene);
330 grp.AbsolutePosition = obj.Position;
331 prim.RotationOffset = obj.Rotation;
332
333 grp.IsAttachment = false;
334 // Required for linking
335 grp.RootPart.ClearUpdateSchedule();
336
337 if (m_scene.Permissions.CanRezObject(1, avatar.UUID, pos))
338 {
339 m_scene.AddSceneObject(grp);
340 grp.AbsolutePosition = obj.Position;
341 }
342
343 allparts[i] = grp;
344 }
345
346 for (int j = 1; j < allparts.Length; j++)
347 {
348 // Required for linking
349 rootGroup.RootPart.ClearUpdateSchedule();
350 allparts[j].RootPart.ClearUpdateSchedule();
351 rootGroup.LinkToGroup(allparts[j]);
352 }
353
354 rootGroup.ScheduleGroupForFullUpdate();
355 pos
356 = m_scene.GetNewRezLocation(
357 Vector3.Zero, rootpos, UUID.Zero, rot, (byte)1, 1, true, allparts[0].GroupScale, false);
358
359 responsedata["int_response_code"] = 200; //501; //410; //404;
360 responsedata["content_type"] = "text/plain";
361 responsedata["keepalive"] = false;
362 responsedata["str_response_string"] = String.Format("<llsd><map><key>local_id</key>{0}</map></llsd>", ConvertUintToBytes(allparts[0].LocalId));
363
364 return responsedata;
365 }
366
367 private string ConvertUintToBytes(uint val)
368 {
369 byte[] resultbytes = Utils.UIntToBytes(val);
370 if (BitConverter.IsLittleEndian)
371 Array.Reverse(resultbytes);
372 return String.Format("<binary encoding=\"base64\">{0}</binary>", Convert.ToBase64String(resultbytes));
373 }
374 }
375} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs
new file mode 100644
index 0000000..1dd8938
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs
@@ -0,0 +1,202 @@
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.Reflection;
31using log4net;
32using Nini.Config;
33using Mono.Addins;
34using OpenMetaverse;
35using OpenMetaverse.StructuredData;
36using OpenSim.Framework;
37using OpenSim.Framework.Servers.HttpServer;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Services.Interfaces;
41using Caps = OpenSim.Framework.Capabilities.Caps;
42
43namespace OpenSim.Region.ClientStack.Linden
44{
45 /// <summary>
46 /// SimulatorFeatures capability.
47 /// </summary>
48 /// <remarks>
49 /// This is required for uploading Mesh.
50 /// Since is accepts an open-ended response, we also send more information
51 /// for viewers that care to interpret it.
52 ///
53 /// NOTE: Part of this code was adapted from the Aurora project, specifically
54 /// the normal part of the response in the capability handler.
55 /// </remarks>
56 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
57 public class SimulatorFeaturesModule : ISharedRegionModule, ISimulatorFeaturesModule
58 {
59// private static readonly ILog m_log =
60// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
61
62 private Scene m_scene;
63
64 /// <summary>
65 /// Simulator features
66 /// </summary>
67 private OSDMap m_features = new OSDMap();
68
69 private string m_MapImageServerURL = string.Empty;
70 private string m_SearchURL = string.Empty;
71
72 #region ISharedRegionModule Members
73
74 public void Initialise(IConfigSource source)
75 {
76 IConfig config = source.Configs["SimulatorFeatures"];
77 if (config != null)
78 {
79 m_MapImageServerURL = config.GetString("MapImageServerURI", string.Empty);
80 if (m_MapImageServerURL != string.Empty)
81 {
82 m_MapImageServerURL = m_MapImageServerURL.Trim();
83 if (!m_MapImageServerURL.EndsWith("/"))
84 m_MapImageServerURL = m_MapImageServerURL + "/";
85 }
86
87 m_SearchURL = config.GetString("SearchServerURI", string.Empty);
88 }
89
90 AddDefaultFeatures();
91 }
92
93 public void AddRegion(Scene s)
94 {
95 m_scene = s;
96 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
97 }
98
99 public void RemoveRegion(Scene s)
100 {
101 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
102 }
103
104 public void RegionLoaded(Scene s)
105 {
106 }
107
108 public void PostInitialise()
109 {
110 }
111
112 public void Close() { }
113
114 public string Name { get { return "SimulatorFeaturesModule"; } }
115
116 public Type ReplaceableInterface
117 {
118 get { return null; }
119 }
120
121 #endregion
122
123 /// <summary>
124 /// Add default features
125 /// </summary>
126 /// <remarks>
127 /// TODO: These should be added from other modules rather than hardcoded.
128 /// </remarks>
129 private void AddDefaultFeatures()
130 {
131 lock (m_features)
132 {
133 m_features["MeshRezEnabled"] = true;
134 m_features["MeshUploadEnabled"] = true;
135 m_features["MeshXferEnabled"] = true;
136 m_features["PhysicsMaterialsEnabled"] = true;
137
138 OSDMap typesMap = new OSDMap();
139 typesMap["convex"] = true;
140 typesMap["none"] = true;
141 typesMap["prim"] = true;
142 m_features["PhysicsShapeTypes"] = typesMap;
143
144 // Extra information for viewers that want to use it
145 OSDMap gridServicesMap = new OSDMap();
146 if (m_MapImageServerURL != string.Empty)
147 gridServicesMap["map-server-url"] = m_MapImageServerURL;
148 if (m_SearchURL != string.Empty)
149 gridServicesMap["search"] = m_SearchURL;
150 m_features["GridServices"] = gridServicesMap;
151 }
152 }
153
154 public void RegisterCaps(UUID agentID, Caps caps)
155 {
156 IRequestHandler reqHandler
157 = new RestHTTPHandler("GET", "/CAPS/" + UUID.Random(), HandleSimulatorFeaturesRequest);
158
159 caps.RegisterHandler("SimulatorFeatures", reqHandler);
160 }
161
162 public void AddFeature(string name, OSD value)
163 {
164 lock (m_features)
165 m_features[name] = value;
166 }
167
168 public bool RemoveFeature(string name)
169 {
170 lock (m_features)
171 return m_features.Remove(name);
172 }
173
174 public bool TryGetFeature(string name, out OSD value)
175 {
176 lock (m_features)
177 return m_features.TryGetValue(name, out value);
178 }
179
180 public OSDMap GetFeatures()
181 {
182 lock (m_features)
183 return new OSDMap(m_features);
184 }
185
186 private Hashtable HandleSimulatorFeaturesRequest(Hashtable mDhttpMethod)
187 {
188// m_log.DebugFormat("[SIMULATOR FEATURES MODULE]: SimulatorFeatures request");
189
190 //Send back data
191 Hashtable responsedata = new Hashtable();
192 responsedata["int_response_code"] = 200;
193 responsedata["content_type"] = "text/plain";
194 responsedata["keepalive"] = false;
195
196 lock (m_features)
197 responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(m_features);
198
199 return responsedata;
200 }
201 }
202}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs
new file mode 100644
index 0000000..45d6071
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs
@@ -0,0 +1,112 @@
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.Specialized;
31using System.Drawing;
32using System.Drawing.Imaging;
33using System.Reflection;
34using System.IO;
35using System.Web;
36using log4net;
37using Nini.Config;
38using Mono.Addins;
39using OpenMetaverse;
40using OpenMetaverse.StructuredData;
41using OpenMetaverse.Imaging;
42using OpenSim.Framework;
43using OpenSim.Framework.Servers;
44using OpenSim.Framework.Servers.HttpServer;
45using OpenSim.Region.Framework.Interfaces;
46using OpenSim.Region.Framework.Scenes;
47using OpenSim.Services.Interfaces;
48using Caps = OpenSim.Framework.Capabilities.Caps;
49using OpenSim.Capabilities.Handlers;
50
51namespace OpenSim.Region.ClientStack.Linden
52{
53 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
54 public class UploadBakedTextureModule : INonSharedRegionModule
55 {
56// private static readonly ILog m_log =
57// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
58
59 /// <summary>
60 /// For historical reasons this is fixed, but there
61 /// </summary>
62 private static readonly string m_uploadBakedTexturePath = "0010/";// This is in the LandManagementModule.
63
64 private Scene m_scene;
65 private bool m_persistBakedTextures;
66
67 public void Initialise(IConfigSource source)
68 {
69 IConfig sconfig = source.Configs["Startup"];
70 if (sconfig != null)
71 m_persistBakedTextures = sconfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures);
72 }
73
74 public void AddRegion(Scene s)
75 {
76 m_scene = s;
77 }
78
79 public void RemoveRegion(Scene s)
80 {
81 }
82
83 public void RegionLoaded(Scene s)
84 {
85 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
86 }
87
88 public void PostInitialise()
89 {
90 }
91
92 public void Close() { }
93
94 public string Name { get { return "UploadBakedTextureModule"; } }
95
96 public Type ReplaceableInterface
97 {
98 get { return null; }
99 }
100
101 public void RegisterCaps(UUID agentID, Caps caps)
102 {
103 caps.RegisterHandler(
104 "UploadBakedTexture",
105 new RestStreamHandler(
106 "POST",
107 "/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath,
108 new UploadBakedTextureHandler(
109 caps, m_scene.AssetService, m_persistBakedTextures).UploadBakedTexture));
110 }
111 }
112} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
new file mode 100644
index 0000000..10f43d1
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
@@ -0,0 +1,163 @@
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.Reflection;
31using log4net;
32using Nini.Config;
33using Mono.Addins;
34using OpenMetaverse;
35using OpenSim.Framework;
36using OpenSim.Framework.Servers.HttpServer;
37using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Region.Framework.Scenes;
39using OpenSim.Services.Interfaces;
40using Caps = OpenSim.Framework.Capabilities.Caps;
41using OpenSim.Capabilities.Handlers;
42
43namespace OpenSim.Region.ClientStack.Linden
44{
45 /// <summary>
46 /// This module implements both WebFetchInventoryDescendents and FetchInventoryDescendents2 capabilities.
47 /// </summary>
48 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
49 public class WebFetchInvDescModule : INonSharedRegionModule
50 {
51// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
52
53 private Scene m_scene;
54
55 private IInventoryService m_InventoryService;
56 private ILibraryService m_LibraryService;
57
58 private bool m_Enabled;
59
60 private string m_fetchInventoryDescendents2Url;
61 private string m_webFetchInventoryDescendentsUrl;
62
63 private WebFetchInvDescHandler m_webFetchHandler;
64
65 #region ISharedRegionModule Members
66
67 public void Initialise(IConfigSource source)
68 {
69 IConfig config = source.Configs["ClientStack.LindenCaps"];
70 if (config == null)
71 return;
72
73 m_fetchInventoryDescendents2Url = config.GetString("Cap_FetchInventoryDescendents2", string.Empty);
74 m_webFetchInventoryDescendentsUrl = config.GetString("Cap_WebFetchInventoryDescendents", string.Empty);
75
76 if (m_fetchInventoryDescendents2Url != string.Empty || m_webFetchInventoryDescendentsUrl != string.Empty)
77 {
78 m_Enabled = true;
79 }
80 }
81
82 public void AddRegion(Scene s)
83 {
84 if (!m_Enabled)
85 return;
86
87 m_scene = s;
88 }
89
90 public void RemoveRegion(Scene s)
91 {
92 if (!m_Enabled)
93 return;
94
95 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
96 m_scene = null;
97 }
98
99 public void RegionLoaded(Scene s)
100 {
101 if (!m_Enabled)
102 return;
103
104 m_InventoryService = m_scene.InventoryService;
105 m_LibraryService = m_scene.LibraryService;
106
107 // We'll reuse the same handler for all requests.
108 if (m_fetchInventoryDescendents2Url == "localhost" || m_webFetchInventoryDescendentsUrl == "localhost")
109 m_webFetchHandler = new WebFetchInvDescHandler(m_InventoryService, m_LibraryService);
110
111 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
112 }
113
114 public void PostInitialise()
115 {
116 }
117
118 public void Close() { }
119
120 public string Name { get { return "WebFetchInvDescModule"; } }
121
122 public Type ReplaceableInterface
123 {
124 get { return null; }
125 }
126
127 #endregion
128
129 private void RegisterCaps(UUID agentID, Caps caps)
130 {
131 if (m_webFetchInventoryDescendentsUrl != "")
132 RegisterFetchCap(agentID, caps, "WebFetchInventoryDescendents", m_webFetchInventoryDescendentsUrl);
133
134 if (m_fetchInventoryDescendents2Url != "")
135 RegisterFetchCap(agentID, caps, "FetchInventoryDescendents2", m_fetchInventoryDescendents2Url);
136 }
137
138 private void RegisterFetchCap(UUID agentID, Caps caps, string capName, string url)
139 {
140 string capUrl;
141
142 if (url == "localhost")
143 {
144 capUrl = "/CAPS/" + UUID.Random();
145
146 IRequestHandler reqHandler
147 = new RestStreamHandler("POST", capUrl, m_webFetchHandler.FetchInventoryDescendentsRequest);
148
149 caps.RegisterHandler(capName, reqHandler);
150 }
151 else
152 {
153 capUrl = url;
154
155 caps.RegisterHandler(capName, capUrl);
156 }
157
158// m_log.DebugFormat(
159// "[WEB FETCH INV DESC MODULE]: Registered capability {0} at {1} in region {2} for {3}",
160// capName, capUrl, m_scene.RegionInfo.RegionName, agentID);
161 }
162 }
163}
diff --git a/OpenSim/Region/ClientStack/LindenUDP/IncomingPacket.cs b/OpenSim/Region/ClientStack/Linden/UDP/IncomingPacket.cs
index 90b3ede..90b3ede 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/IncomingPacket.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/IncomingPacket.cs
diff --git a/OpenSim/Region/ClientStack/LindenUDP/IncomingPacketHistoryCollection.cs b/OpenSim/Region/ClientStack/Linden/UDP/IncomingPacketHistoryCollection.cs
index 1f73a1d..1f73a1d 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/IncomingPacketHistoryCollection.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/IncomingPacketHistoryCollection.cs
diff --git a/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
index b53a2fb..9dd6663 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
@@ -31,7 +31,6 @@ using OpenMetaverse;
31using OpenMetaverse.Imaging; 31using OpenMetaverse.Imaging;
32using OpenSim.Framework; 32using OpenSim.Framework;
33using OpenSim.Region.Framework.Interfaces; 33using OpenSim.Region.Framework.Interfaces;
34using OpenSim.Region.Framework.Scenes.Hypergrid;
35using OpenSim.Services.Interfaces; 34using OpenSim.Services.Interfaces;
36using log4net; 35using log4net;
37using System.Reflection; 36using System.Reflection;
@@ -56,7 +55,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
56 public IJ2KDecoder J2KDecoder; 55 public IJ2KDecoder J2KDecoder;
57 public IAssetService AssetService; 56 public IAssetService AssetService;
58 public UUID AgentID; 57 public UUID AgentID;
59 public IHyperAssetService HyperAssets; 58 public IInventoryAccessModule InventoryAccessModule;
60 public OpenJPEG.J2KLayerInfo[] Layers; 59 public OpenJPEG.J2KLayerInfo[] Layers;
61 public bool IsDecoded; 60 public bool IsDecoded;
62 public bool HasAsset; 61 public bool HasAsset;
@@ -203,6 +202,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
203 m_stopPacket = TexturePacketCount(); 202 m_stopPacket = TexturePacketCount();
204 } 203 }
205 204
205 //Give them at least two packets, to play nice with some broken viewers (SL also behaves this way)
206 if (m_stopPacket == 1 && Layers[0].End > FIRST_PACKET_SIZE) m_stopPacket++;
207
206 m_currentPacket = StartPacket; 208 m_currentPacket = StartPacket;
207 } 209 }
208 } 210 }
@@ -376,14 +378,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
376 UUID assetID = UUID.Zero; 378 UUID assetID = UUID.Zero;
377 if (asset != null) 379 if (asset != null)
378 assetID = asset.FullID; 380 assetID = asset.FullID;
379 else if ((HyperAssets != null) && (sender != HyperAssets)) 381 else if ((InventoryAccessModule != null) && (sender != InventoryAccessModule))
380 { 382 {
381 // Try the user's inventory, but only if it's different from the regions' 383 // Unfortunately we need this here, there's no other way.
382 string userAssets = HyperAssets.GetUserAssetServer(AgentID); 384 // This is due to the fact that textures opened directly from the agent's inventory
383 if ((userAssets != string.Empty) && (userAssets != HyperAssets.GetSimAssetServer())) 385 // don't have any distinguishing feature. As such, in order to serve those when the
386 // foreign user is visiting, we need to try again after the first fail to the local
387 // asset service.
388 string assetServerURL = string.Empty;
389 if (InventoryAccessModule.IsForeignUser(AgentID, out assetServerURL))
384 { 390 {
385 m_log.DebugFormat("[J2KIMAGE]: texture {0} not found in local asset storage. Trying user's storage.", id); 391 m_log.DebugFormat("[J2KIMAGE]: texture {0} not found in local asset storage. Trying user's storage.", id);
386 AssetService.Get(userAssets + "/" + id, HyperAssets, AssetReceived); 392 AssetService.Get(assetServerURL + "/" + id, InventoryAccessModule, AssetReceived);
387 return; 393 return;
388 } 394 }
389 } 395 }
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
index 0e4a0d0..af68de6 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -37,59 +37,22 @@ using System.Xml;
37using log4net; 37using log4net;
38using OpenMetaverse; 38using OpenMetaverse;
39using OpenMetaverse.Packets; 39using OpenMetaverse.Packets;
40using OpenMetaverse.Messages.Linden;
40using OpenMetaverse.StructuredData; 41using OpenMetaverse.StructuredData;
41using OpenSim.Framework; 42using OpenSim.Framework;
42using OpenSim.Framework.Client; 43using OpenSim.Framework.Client;
43using OpenSim.Framework.Communications.Cache;
44using OpenSim.Framework.Statistics; 44using OpenSim.Framework.Statistics;
45using OpenSim.Region.Framework.Interfaces; 45using OpenSim.Region.Framework.Interfaces;
46using OpenSim.Region.Framework.Scenes; 46using OpenSim.Region.Framework.Scenes;
47using OpenSim.Region.Framework.Scenes.Hypergrid;
48using OpenSim.Services.Interfaces; 47using OpenSim.Services.Interfaces;
49using Timer = System.Timers.Timer; 48using Timer = System.Timers.Timer;
50using AssetLandmark = OpenSim.Framework.AssetLandmark; 49using AssetLandmark = OpenSim.Framework.AssetLandmark;
51using Nini.Config; 50using Nini.Config;
52 51
52using System.IO;
53
53namespace OpenSim.Region.ClientStack.LindenUDP 54namespace OpenSim.Region.ClientStack.LindenUDP
54{ 55{
55 #region Enums
56
57 /// <summary>
58 /// Specifies the fields that have been changed when sending a prim or
59 /// avatar update
60 /// </summary>
61 [Flags]
62 public enum PrimUpdateFlags : uint
63 {
64 None = 0,
65 AttachmentPoint = 1 << 0,
66 Material = 1 << 1,
67 ClickAction = 1 << 2,
68 Scale = 1 << 3,
69 ParentID = 1 << 4,
70 PrimFlags = 1 << 5,
71 PrimData = 1 << 6,
72 MediaURL = 1 << 7,
73 ScratchPad = 1 << 8,
74 Textures = 1 << 9,
75 TextureAnim = 1 << 10,
76 NameValue = 1 << 11,
77 Position = 1 << 12,
78 Rotation = 1 << 13,
79 Velocity = 1 << 14,
80 Acceleration = 1 << 15,
81 AngularVelocity = 1 << 16,
82 CollisionPlane = 1 << 17,
83 Text = 1 << 18,
84 Particles = 1 << 19,
85 ExtraData = 1 << 20,
86 Sound = 1 << 21,
87 Joint = 1 << 22,
88 FullUpdate = UInt32.MaxValue
89 }
90
91 #endregion Enums
92
93 public delegate bool PacketMethod(IClientAPI simClient, Packet packet); 56 public delegate bool PacketMethod(IClientAPI simClient, Packet packet);
94 57
95 /// <summary> 58 /// <summary>
@@ -99,10 +62,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
99 public class LLClientView : IClientAPI, IClientCore, IClientIM, IClientChat, IClientIPEndpoint, IStatsCollector 62 public class LLClientView : IClientAPI, IClientCore, IClientIM, IClientChat, IClientIPEndpoint, IStatsCollector
100 { 63 {
101 /// <value> 64 /// <value>
102 /// Debug packet level. At the moment, only 255 does anything (prints out all in and out packets). 65 /// Debug packet level. See OpenSim.RegisterConsoleCommands() for more details.
103 /// </value> 66 /// </value>
104 protected int m_debugPacketLevel = 0; 67 public int DebugPacketLevel { get; set; }
105 68
106 #region Events 69 #region Events
107 70
108 public event GenericMessage OnGenericMessage; 71 public event GenericMessage OnGenericMessage;
@@ -118,7 +81,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
118 public event DeRezObject OnDeRezObject; 81 public event DeRezObject OnDeRezObject;
119 public event ModifyTerrain OnModifyTerrain; 82 public event ModifyTerrain OnModifyTerrain;
120 public event Action<IClientAPI> OnRegionHandShakeReply; 83 public event Action<IClientAPI> OnRegionHandShakeReply;
121 public event GenericCall2 OnRequestWearables; 84 public event GenericCall1 OnRequestWearables;
122 public event SetAppearance OnSetAppearance; 85 public event SetAppearance OnSetAppearance;
123 public event AvatarNowWearing OnAvatarNowWearing; 86 public event AvatarNowWearing OnAvatarNowWearing;
124 public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv; 87 public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv;
@@ -127,7 +90,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
127 public event ObjectAttach OnObjectAttach; 90 public event ObjectAttach OnObjectAttach;
128 public event ObjectDeselect OnObjectDetach; 91 public event ObjectDeselect OnObjectDetach;
129 public event ObjectDrop OnObjectDrop; 92 public event ObjectDrop OnObjectDrop;
130 public event GenericCall2 OnCompleteMovementToRegion; 93 public event Action<IClientAPI, bool> OnCompleteMovementToRegion;
94 public event UpdateAgent OnPreAgentUpdate;
131 public event UpdateAgent OnAgentUpdate; 95 public event UpdateAgent OnAgentUpdate;
132 public event AgentRequestSit OnAgentRequestSit; 96 public event AgentRequestSit OnAgentRequestSit;
133 public event AgentSit OnAgentSit; 97 public event AgentSit OnAgentSit;
@@ -183,6 +147,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
183 public event TeleportLocationRequest OnSetStartLocationRequest; 147 public event TeleportLocationRequest OnSetStartLocationRequest;
184 public event UpdateAvatarProperties OnUpdateAvatarProperties; 148 public event UpdateAvatarProperties OnUpdateAvatarProperties;
185 public event CreateNewInventoryItem OnCreateNewInventoryItem; 149 public event CreateNewInventoryItem OnCreateNewInventoryItem;
150 public event LinkInventoryItem OnLinkInventoryItem;
186 public event CreateInventoryFolder OnCreateNewInventoryFolder; 151 public event CreateInventoryFolder OnCreateNewInventoryFolder;
187 public event UpdateInventoryFolder OnUpdateInventoryFolder; 152 public event UpdateInventoryFolder OnUpdateInventoryFolder;
188 public event MoveInventoryFolder OnMoveInventoryFolder; 153 public event MoveInventoryFolder OnMoveInventoryFolder;
@@ -192,6 +157,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
192 public event RequestTaskInventory OnRequestTaskInventory; 157 public event RequestTaskInventory OnRequestTaskInventory;
193 public event UpdateInventoryItem OnUpdateInventoryItem; 158 public event UpdateInventoryItem OnUpdateInventoryItem;
194 public event CopyInventoryItem OnCopyInventoryItem; 159 public event CopyInventoryItem OnCopyInventoryItem;
160 public event MoveItemsAndLeaveCopy OnMoveItemsAndLeaveCopy;
195 public event MoveInventoryItem OnMoveInventoryItem; 161 public event MoveInventoryItem OnMoveInventoryItem;
196 public event RemoveInventoryItem OnRemoveInventoryItem; 162 public event RemoveInventoryItem OnRemoveInventoryItem;
197 public event RemoveInventoryFolder OnRemoveInventoryFolder; 163 public event RemoveInventoryFolder OnRemoveInventoryFolder;
@@ -266,7 +232,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
266 public event ScriptReset OnScriptReset; 232 public event ScriptReset OnScriptReset;
267 public event GetScriptRunning OnGetScriptRunning; 233 public event GetScriptRunning OnGetScriptRunning;
268 public event SetScriptRunning OnSetScriptRunning; 234 public event SetScriptRunning OnSetScriptRunning;
269 public event UpdateVector OnAutoPilotGo; 235 public event Action<Vector3, bool, bool> OnAutoPilotGo;
270 public event TerrainUnacked OnUnackedTerrain; 236 public event TerrainUnacked OnUnackedTerrain;
271 public event ActivateGesture OnActivateGesture; 237 public event ActivateGesture OnActivateGesture;
272 public event DeactivateGesture OnDeactivateGesture; 238 public event DeactivateGesture OnDeactivateGesture;
@@ -289,7 +255,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
289 public event ClassifiedInfoRequest OnClassifiedInfoRequest; 255 public event ClassifiedInfoRequest OnClassifiedInfoRequest;
290 public event ClassifiedInfoUpdate OnClassifiedInfoUpdate; 256 public event ClassifiedInfoUpdate OnClassifiedInfoUpdate;
291 public event ClassifiedDelete OnClassifiedDelete; 257 public event ClassifiedDelete OnClassifiedDelete;
292 public event ClassifiedDelete OnClassifiedGodDelete; 258 public event ClassifiedGodDelete OnClassifiedGodDelete;
293 public event EventNotificationAddRequest OnEventNotificationAddRequest; 259 public event EventNotificationAddRequest OnEventNotificationAddRequest;
294 public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest; 260 public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest;
295 public event EventGodDelete OnEventGodDelete; 261 public event EventGodDelete OnEventGodDelete;
@@ -320,11 +286,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
320 public event GroupVoteHistoryRequest OnGroupVoteHistoryRequest; 286 public event GroupVoteHistoryRequest OnGroupVoteHistoryRequest;
321 public event SimWideDeletesDelegate OnSimWideDeletes; 287 public event SimWideDeletesDelegate OnSimWideDeletes;
322 public event SendPostcard OnSendPostcard; 288 public event SendPostcard OnSendPostcard;
289 public event ChangeInventoryItemFlags OnChangeInventoryItemFlags;
323 public event MuteListEntryUpdate OnUpdateMuteListEntry; 290 public event MuteListEntryUpdate OnUpdateMuteListEntry;
324 public event MuteListEntryRemove OnRemoveMuteListEntry; 291 public event MuteListEntryRemove OnRemoveMuteListEntry;
325 public event GodlikeMessage onGodlikeMessage; 292 public event GodlikeMessage onGodlikeMessage;
326 public event GodUpdateRegionInfoUpdate OnGodUpdateRegionInfoUpdate; 293 public event GodUpdateRegionInfoUpdate OnGodUpdateRegionInfoUpdate;
327
328 294
329 #endregion Events 295 #endregion Events
330 296
@@ -350,9 +316,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
350 private readonly IGroupsModule m_GroupsModule; 316 private readonly IGroupsModule m_GroupsModule;
351 317
352 private int m_cachedTextureSerial; 318 private int m_cachedTextureSerial;
353 protected PriorityQueue<double, ImprovedTerseObjectUpdatePacket.ObjectDataBlock> m_avatarTerseUpdates; 319 private PriorityQueue m_entityUpdates;
354 private PriorityQueue<double, ImprovedTerseObjectUpdatePacket.ObjectDataBlock> m_primTerseUpdates; 320 private PriorityQueue m_entityProps;
355 private PriorityQueue<double, ObjectUpdatePacket.ObjectDataBlock> m_primFullUpdates; 321 private Prioritizer m_prioritizer;
322 private bool m_disableFacelights = false;
356 323
357 /// <value> 324 /// <value>
358 /// List used in construction of data blocks for an object update packet. This is to stop us having to 325 /// List used in construction of data blocks for an object update packet. This is to stop us having to
@@ -365,19 +332,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
365 /// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an 332 /// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an
366 /// ownerless phantom. 333 /// ownerless phantom.
367 /// 334 ///
368 /// All manipulation of this set has to occur under a m_primFullUpdate.SyncRoot lock 335 /// All manipulation of this set has to occur under an m_entityUpdates.SyncRoot lock
369 /// 336 ///
370 /// </value> 337 /// </value>
371 protected HashSet<uint> m_killRecord; 338 protected HashSet<uint> m_killRecord;
372 339
373// protected HashSet<uint> m_attachmentsQueued; 340// protected HashSet<uint> m_attachmentsSent;
374// protected HashSet<uint> m_attachmentsSent; 341
375
376 private int m_moneyBalance; 342 private int m_moneyBalance;
343 private bool m_deliverPackets = true;
377 private int m_animationSequenceNumber = 1; 344 private int m_animationSequenceNumber = 1;
378 private bool m_SendLogoutPacketWhenClosing = true; 345 private bool m_SendLogoutPacketWhenClosing = true;
379 private AgentUpdateArgs lastarg; 346 private AgentUpdateArgs lastarg;
380 private bool m_IsActive = true; 347 private bool m_IsActive = true;
348 private bool m_IsLoggingOut = false;
381 349
382 protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>(); 350 protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>();
383 protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers 351 protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers
@@ -396,17 +364,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
396 protected uint m_agentFOVCounter; 364 protected uint m_agentFOVCounter;
397 365
398 protected IAssetService m_assetService; 366 protected IAssetService m_assetService;
399 private IHyperAssetService m_hyperAssets;
400 private const bool m_checkPackets = true; 367 private const bool m_checkPackets = true;
401 368
402 private Timer m_propertiesPacketTimer;
403 private List<ObjectPropertiesPacket.ObjectDataBlock> m_propertiesBlocks = new List<ObjectPropertiesPacket.ObjectDataBlock>();
404
405 #endregion Class Members 369 #endregion Class Members
406 370
407 #region Properties 371 #region Properties
408 372
409 public LLUDPClient UDPClient { get { return m_udpClient; } } 373 public LLUDPClient UDPClient { get { return m_udpClient; } }
374 public LLUDPServer UDPServer { get { return m_udpServer; } }
410 public IPEndPoint RemoteEndPoint { get { return m_udpClient.RemoteEndPoint; } } 375 public IPEndPoint RemoteEndPoint { get { return m_udpClient.RemoteEndPoint; } }
411 public UUID SecureSessionId { get { return m_secureSessionId; } } 376 public UUID SecureSessionId { get { return m_secureSessionId; } }
412 public IScene Scene { get { return m_scene; } } 377 public IScene Scene { get { return m_scene; } }
@@ -416,23 +381,41 @@ namespace OpenSim.Region.ClientStack.LindenUDP
416 get { return m_startpos; } 381 get { return m_startpos; }
417 set { m_startpos = value; } 382 set { m_startpos = value; }
418 } 383 }
384 public bool DeliverPackets
385 {
386 get { return m_deliverPackets; }
387 set {
388 m_deliverPackets = value;
389 m_udpClient.m_deliverPackets = value;
390 }
391 }
419 public UUID AgentId { get { return m_agentId; } } 392 public UUID AgentId { get { return m_agentId; } }
393 public ISceneAgent SceneAgent { get; private set; }
420 public UUID ActiveGroupId { get { return m_activeGroupID; } } 394 public UUID ActiveGroupId { get { return m_activeGroupID; } }
421 public string ActiveGroupName { get { return m_activeGroupName; } } 395 public string ActiveGroupName { get { return m_activeGroupName; } }
422 public ulong ActiveGroupPowers { get { return m_activeGroupPowers; } } 396 public ulong ActiveGroupPowers { get { return m_activeGroupPowers; } }
423 public bool IsGroupMember(UUID groupID) { return m_groupPowers.ContainsKey(groupID); } 397 public bool IsGroupMember(UUID groupID) { return m_groupPowers.ContainsKey(groupID); }
398
399 /// <summary>
400 /// Entity update queues
401 /// </summary>
402 public PriorityQueue EntityUpdateQueue { get { return m_entityUpdates; } }
403
424 /// <summary> 404 /// <summary>
425 /// First name of the agent/avatar represented by the client 405 /// First name of the agent/avatar represented by the client
426 /// </summary> 406 /// </summary>
427 public string FirstName { get { return m_firstName; } } 407 public string FirstName { get { return m_firstName; } }
408
428 /// <summary> 409 /// <summary>
429 /// Last name of the agent/avatar represented by the client 410 /// Last name of the agent/avatar represented by the client
430 /// </summary> 411 /// </summary>
431 public string LastName { get { return m_lastName; } } 412 public string LastName { get { return m_lastName; } }
413
432 /// <summary> 414 /// <summary>
433 /// Full name of the client (first name and last name) 415 /// Full name of the client (first name and last name)
434 /// </summary> 416 /// </summary>
435 public string Name { get { return FirstName + " " + LastName; } } 417 public string Name { get { return FirstName + " " + LastName; } }
418
436 public uint CircuitCode { get { return m_circuitCode; } } 419 public uint CircuitCode { get { return m_circuitCode; } }
437 public int MoneyBalance { get { return m_moneyBalance; } } 420 public int MoneyBalance { get { return m_moneyBalance; } }
438 public int NextAnimationSequenceNumber { get { return m_animationSequenceNumber++; } } 421 public int NextAnimationSequenceNumber { get { return m_animationSequenceNumber++; } }
@@ -441,10 +424,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
441 get { return m_IsActive; } 424 get { return m_IsActive; }
442 set { m_IsActive = value; } 425 set { m_IsActive = value; }
443 } 426 }
427 public bool IsLoggingOut
428 {
429 get { return m_IsLoggingOut; }
430 set { m_IsLoggingOut = value; }
431 }
432
433 public bool DisableFacelights
434 {
435 get { return m_disableFacelights; }
436 set { m_disableFacelights = value; }
437 }
438
444 public bool SendLogoutPacketWhenClosing { set { m_SendLogoutPacketWhenClosing = value; } } 439 public bool SendLogoutPacketWhenClosing { set { m_SendLogoutPacketWhenClosing = value; } }
445 440
446 #endregion Properties 441 #endregion Properties
447 442
443// ~LLClientView()
444// {
445// m_log.DebugFormat("[LLCLIENTVIEW]: Destructor called for {0}, circuit code {1}", Name, CircuitCode);
446// }
447
448 /// <summary> 448 /// <summary>
449 /// Constructor 449 /// Constructor
450 /// </summary> 450 /// </summary>
@@ -459,16 +459,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
459 459
460 m_scene = scene; 460 m_scene = scene;
461 461
462 m_avatarTerseUpdates = new PriorityQueue<double, ImprovedTerseObjectUpdatePacket.ObjectDataBlock>(); 462 m_entityUpdates = new PriorityQueue(m_scene.Entities.Count);
463 m_primTerseUpdates = new PriorityQueue<double, ImprovedTerseObjectUpdatePacket.ObjectDataBlock>(); 463 m_entityProps = new PriorityQueue(m_scene.Entities.Count);
464 m_primFullUpdates = new PriorityQueue<double, ObjectUpdatePacket.ObjectDataBlock>(m_scene.Entities.Count);
465 m_fullUpdateDataBlocksBuilder = new List<ObjectUpdatePacket.ObjectDataBlock>(); 464 m_fullUpdateDataBlocksBuilder = new List<ObjectUpdatePacket.ObjectDataBlock>();
466 m_killRecord = new HashSet<uint>(); 465 m_killRecord = new HashSet<uint>();
467// m_attachmentsQueued = new HashSet<uint>(); 466// m_attachmentsSent = new HashSet<uint>();
468// m_attachmentsSent = new HashSet<uint>();
469 467
470 m_assetService = m_scene.RequestModuleInterface<IAssetService>(); 468 m_assetService = m_scene.RequestModuleInterface<IAssetService>();
471 m_hyperAssets = m_scene.RequestModuleInterface<IHyperAssetService>();
472 m_GroupsModule = scene.RequestModuleInterface<IGroupsModule>(); 469 m_GroupsModule = scene.RequestModuleInterface<IGroupsModule>();
473 m_imageManager = new LLImageManager(this, m_assetService, Scene.RequestModuleInterface<IJ2KDecoder>()); 470 m_imageManager = new LLImageManager(this, m_assetService, Scene.RequestModuleInterface<IJ2KDecoder>());
474 m_channelVersion = Util.StringToBytes256(scene.GetSimulatorVersion()); 471 m_channelVersion = Util.StringToBytes256(scene.GetSimulatorVersion());
@@ -487,17 +484,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
487 m_udpClient.OnQueueEmpty += HandleQueueEmpty; 484 m_udpClient.OnQueueEmpty += HandleQueueEmpty;
488 m_udpClient.OnPacketStats += PopulateStats; 485 m_udpClient.OnPacketStats += PopulateStats;
489 486
490 m_propertiesPacketTimer = new Timer(100); 487 m_prioritizer = new Prioritizer(m_scene);
491 m_propertiesPacketTimer.Elapsed += ProcessObjectPropertiesPacket;
492 488
493 RegisterLocalPacketHandlers(); 489 RegisterLocalPacketHandlers();
494 } 490 }
495 491
496 public void SetDebugPacketLevel(int newDebug)
497 {
498 m_debugPacketLevel = newDebug;
499 }
500
501 #region Client Methods 492 #region Client Methods
502 493
503 494
@@ -540,7 +531,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
540 m_udpServer.Flush(m_udpClient); 531 m_udpServer.Flush(m_udpClient);
541 532
542 // Remove ourselves from the scene 533 // Remove ourselves from the scene
543 m_scene.RemoveClient(AgentId); 534 m_scene.RemoveClient(AgentId, true);
535 SceneAgent = null;
544 536
545 // We can't reach into other scenes and close the connection 537 // We can't reach into other scenes and close the connection
546 // We need to do this over grid communications 538 // We need to do this over grid communications
@@ -602,22 +594,42 @@ namespace OpenSim.Region.ClientStack.LindenUDP
602 return result; 594 return result;
603 } 595 }
604 596
597 /// <summary>
598 /// Add a handler for the given packet type.
599 /// </summary>
600 /// <remarks>The packet is handled on its own thread. If packets must be handled in the order in which thye
601 /// are received then please us ethe synchronous version of this method.</remarks>
602 /// <param name="packetType"></param>
603 /// <param name="handler"></param>
604 /// <returns>true if the handler was added. This is currently always the case.</returns>
605 public bool AddLocalPacketHandler(PacketType packetType, PacketMethod handler) 605 public bool AddLocalPacketHandler(PacketType packetType, PacketMethod handler)
606 { 606 {
607 return AddLocalPacketHandler(packetType, handler, true); 607 return AddLocalPacketHandler(packetType, handler, true);
608 } 608 }
609 609
610 public bool AddLocalPacketHandler(PacketType packetType, PacketMethod handler, bool async) 610 /// <summary>
611 /// Add a handler for the given packet type.
612 /// </summary>
613 /// <param name="packetType"></param>
614 /// <param name="handler"></param>
615 /// <param name="doAsync">
616 /// If true, when the packet is received it is handled on its own thread rather than on the main inward bound
617 /// packet handler thread. This vastly increases respnosiveness but some packets need to be handled
618 /// synchronously.
619 /// </param>
620 /// <returns>true if the handler was added. This is currently always the case.</returns>
621 public bool AddLocalPacketHandler(PacketType packetType, PacketMethod handler, bool doAsync)
611 { 622 {
612 bool result = false; 623 bool result = false;
613 lock (m_packetHandlers) 624 lock (m_packetHandlers)
614 { 625 {
615 if (!m_packetHandlers.ContainsKey(packetType)) 626 if (!m_packetHandlers.ContainsKey(packetType))
616 { 627 {
617 m_packetHandlers.Add(packetType, new PacketProcessor() { method = handler, Async = async }); 628 m_packetHandlers.Add(packetType, new PacketProcessor() { method = handler, Async = doAsync });
618 result = true; 629 result = true;
619 } 630 }
620 } 631 }
632
621 return result; 633 return result;
622 } 634 }
623 635
@@ -652,7 +664,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
652 if (pprocessor.Async) 664 if (pprocessor.Async)
653 { 665 {
654 object obj = new AsyncPacketProcess(this, pprocessor.method, packet); 666 object obj = new AsyncPacketProcess(this, pprocessor.method, packet);
655 Util.FireAndForget(ProcessSpecificPacketAsync,obj); 667 Util.FireAndForget(ProcessSpecificPacketAsync, obj);
656 result = true; 668 result = true;
657 } 669 }
658 else 670 else
@@ -680,7 +692,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
680 public void ProcessSpecificPacketAsync(object state) 692 public void ProcessSpecificPacketAsync(object state)
681 { 693 {
682 AsyncPacketProcess packetObject = (AsyncPacketProcess)state; 694 AsyncPacketProcess packetObject = (AsyncPacketProcess)state;
683 packetObject.result = packetObject.Method(packetObject.ClientView, packetObject.Pack); 695
696 try
697 {
698 packetObject.result = packetObject.Method(packetObject.ClientView, packetObject.Pack);
699 }
700 catch (Exception e)
701 {
702 // Make sure that we see any exception caused by the asynchronous operation.
703 m_log.ErrorFormat(
704 "[LLCLIENTVIEW]: Caught exception while processing {0} for {1}, {2} {3}",
705 packetObject.Pack, Name, e.Message, e.StackTrace);
706 }
684 } 707 }
685 708
686 #endregion Packet Handling 709 #endregion Packet Handling
@@ -689,7 +712,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
689 712
690 public virtual void Start() 713 public virtual void Start()
691 { 714 {
692 m_scene.AddNewClient(this); 715 SceneAgent = m_scene.AddNewClient(this, PresenceType.User);
693 716
694 RefreshGroupMembership(); 717 RefreshGroupMembership();
695 } 718 }
@@ -748,7 +771,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
748 handshake.RegionInfo3.CPURatio = 1; 771 handshake.RegionInfo3.CPURatio = 1;
749 772
750 handshake.RegionInfo3.ColoName = Utils.EmptyBytes; 773 handshake.RegionInfo3.ColoName = Utils.EmptyBytes;
751 handshake.RegionInfo3.ProductName = Utils.EmptyBytes; 774 handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType);
752 handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes; 775 handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes;
753 776
754 OutPacket(handshake, ThrottleOutPacketType.Task); 777 OutPacket(handshake, ThrottleOutPacketType.Task);
@@ -793,7 +816,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
793 reply.ChatData.OwnerID = fromAgentID; 816 reply.ChatData.OwnerID = fromAgentID;
794 reply.ChatData.SourceID = fromAgentID; 817 reply.ChatData.SourceID = fromAgentID;
795 818
796 OutPacket(reply, ThrottleOutPacketType.Task); 819 OutPacket(reply, ThrottleOutPacketType.Unknown);
797 } 820 }
798 821
799 /// <summary> 822 /// <summary>
@@ -855,6 +878,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
855 } 878 }
856 } 879 }
857 880
881 public void SendGenericMessage(string method, List<string> message)
882 {
883 GenericMessagePacket gmp = new GenericMessagePacket();
884 gmp.MethodData.Method = Util.StringToBytes256(method);
885 gmp.ParamList = new GenericMessagePacket.ParamListBlock[message.Count];
886 int i = 0;
887 foreach (string val in message)
888 {
889 gmp.ParamList[i] = new GenericMessagePacket.ParamListBlock();
890 gmp.ParamList[i++].Parameter = Util.StringToBytes256(val);
891 }
892
893 OutPacket(gmp, ThrottleOutPacketType.Task);
894 }
895
858 public void SendGenericMessage(string method, List<byte[]> message) 896 public void SendGenericMessage(string method, List<byte[]> message)
859 { 897 {
860 GenericMessagePacket gmp = new GenericMessagePacket(); 898 GenericMessagePacket gmp = new GenericMessagePacket();
@@ -866,6 +904,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
866 gmp.ParamList[i] = new GenericMessagePacket.ParamListBlock(); 904 gmp.ParamList[i] = new GenericMessagePacket.ParamListBlock();
867 gmp.ParamList[i++].Parameter = val; 905 gmp.ParamList[i++].Parameter = val;
868 } 906 }
907
869 OutPacket(gmp, ThrottleOutPacketType.Task); 908 OutPacket(gmp, ThrottleOutPacketType.Task);
870 } 909 }
871 910
@@ -875,7 +914,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
875 foreach (GroupActiveProposals Proposal in Proposals) 914 foreach (GroupActiveProposals Proposal in Proposals)
876 { 915 {
877 GroupActiveProposalItemReplyPacket GAPIRP = new GroupActiveProposalItemReplyPacket(); 916 GroupActiveProposalItemReplyPacket GAPIRP = new GroupActiveProposalItemReplyPacket();
878 917
879 GAPIRP.AgentData.AgentID = AgentId; 918 GAPIRP.AgentData.AgentID = AgentId;
880 GAPIRP.AgentData.GroupID = groupID; 919 GAPIRP.AgentData.GroupID = groupID;
881 GAPIRP.TransactionData.TransactionID = transactionID; 920 GAPIRP.TransactionData.TransactionID = transactionID;
@@ -899,7 +938,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
899 if (Proposals.Length == 0) 938 if (Proposals.Length == 0)
900 { 939 {
901 GroupActiveProposalItemReplyPacket GAPIRP = new GroupActiveProposalItemReplyPacket(); 940 GroupActiveProposalItemReplyPacket GAPIRP = new GroupActiveProposalItemReplyPacket();
902 941
903 GAPIRP.AgentData.AgentID = AgentId; 942 GAPIRP.AgentData.AgentID = AgentId;
904 GAPIRP.AgentData.GroupID = groupID; 943 GAPIRP.AgentData.GroupID = groupID;
905 GAPIRP.TransactionData.TransactionID = transactionID; 944 GAPIRP.TransactionData.TransactionID = transactionID;
@@ -954,7 +993,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
954 if (Votes.Length == 0) 993 if (Votes.Length == 0)
955 { 994 {
956 GroupVoteHistoryItemReplyPacket GVHIRP = new GroupVoteHistoryItemReplyPacket(); 995 GroupVoteHistoryItemReplyPacket GVHIRP = new GroupVoteHistoryItemReplyPacket();
957 996
958 GVHIRP.AgentData.AgentID = AgentId; 997 GVHIRP.AgentData.AgentID = AgentId;
959 GVHIRP.AgentData.GroupID = groupID; 998 GVHIRP.AgentData.GroupID = groupID;
960 GVHIRP.TransactionData.TransactionID = transactionID; 999 GVHIRP.TransactionData.TransactionID = transactionID;
@@ -978,7 +1017,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
978 OutPacket(GVHIRP, ThrottleOutPacketType.Task); 1017 OutPacket(GVHIRP, ThrottleOutPacketType.Task);
979 } 1018 }
980 } 1019 }
981 1020
982 public void SendGroupAccountingDetails(IClientAPI sender,UUID groupID, UUID transactionID, UUID sessionID, int amt) 1021 public void SendGroupAccountingDetails(IClientAPI sender,UUID groupID, UUID transactionID, UUID sessionID, int amt)
983 { 1022 {
984 GroupAccountDetailsReplyPacket GADRP = new GroupAccountDetailsReplyPacket(); 1023 GroupAccountDetailsReplyPacket GADRP = new GroupAccountDetailsReplyPacket();
@@ -997,13 +1036,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
997 GADRP.HistoryData[0] = History; 1036 GADRP.HistoryData[0] = History;
998 OutPacket(GADRP, ThrottleOutPacketType.Task); 1037 OutPacket(GADRP, ThrottleOutPacketType.Task);
999 } 1038 }
1000 1039
1001 public void SendGroupAccountingSummary(IClientAPI sender,UUID groupID, uint moneyAmt, int totalTier, int usedTier) 1040 public void SendGroupAccountingSummary(IClientAPI sender,UUID groupID, uint moneyAmt, int totalTier, int usedTier)
1002 { 1041 {
1003 GroupAccountSummaryReplyPacket GASRP = 1042 GroupAccountSummaryReplyPacket GASRP =
1004 (GroupAccountSummaryReplyPacket)PacketPool.Instance.GetPacket( 1043 (GroupAccountSummaryReplyPacket)PacketPool.Instance.GetPacket(
1005 PacketType.GroupAccountSummaryReply); 1044 PacketType.GroupAccountSummaryReply);
1006 1045
1007 GASRP.AgentData = new GroupAccountSummaryReplyPacket.AgentDataBlock(); 1046 GASRP.AgentData = new GroupAccountSummaryReplyPacket.AgentDataBlock();
1008 GASRP.AgentData.AgentID = sender.AgentId; 1047 GASRP.AgentData.AgentID = sender.AgentId;
1009 GASRP.AgentData.GroupID = groupID; 1048 GASRP.AgentData.GroupID = groupID;
@@ -1030,13 +1069,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1030 GASRP.MoneyData.LightTaxEstimate = 0; 1069 GASRP.MoneyData.LightTaxEstimate = 0;
1031 OutPacket(GASRP, ThrottleOutPacketType.Task); 1070 OutPacket(GASRP, ThrottleOutPacketType.Task);
1032 } 1071 }
1033 1072
1034 public void SendGroupTransactionsSummaryDetails(IClientAPI sender,UUID groupID, UUID transactionID, UUID sessionID, int amt) 1073 public void SendGroupTransactionsSummaryDetails(IClientAPI sender,UUID groupID, UUID transactionID, UUID sessionID, int amt)
1035 { 1074 {
1036 GroupAccountTransactionsReplyPacket GATRP = 1075 GroupAccountTransactionsReplyPacket GATRP =
1037 (GroupAccountTransactionsReplyPacket)PacketPool.Instance.GetPacket( 1076 (GroupAccountTransactionsReplyPacket)PacketPool.Instance.GetPacket(
1038 PacketType.GroupAccountTransactionsReply); 1077 PacketType.GroupAccountTransactionsReply);
1039 1078
1040 GATRP.AgentData = new GroupAccountTransactionsReplyPacket.AgentDataBlock(); 1079 GATRP.AgentData = new GroupAccountTransactionsReplyPacket.AgentDataBlock();
1041 GATRP.AgentData.AgentID = sender.AgentId; 1080 GATRP.AgentData.AgentID = sender.AgentId;
1042 GATRP.AgentData.GroupID = groupID; 1081 GATRP.AgentData.GroupID = groupID;
@@ -1354,7 +1393,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1354 1393
1355 public void SendMapBlock(List<MapBlockData> mapBlocks, uint flag) 1394 public void SendMapBlock(List<MapBlockData> mapBlocks, uint flag)
1356 { 1395 {
1357
1358 MapBlockData[] mapBlocks2 = mapBlocks.ToArray(); 1396 MapBlockData[] mapBlocks2 = mapBlocks.ToArray();
1359 1397
1360 int maxsend = 10; 1398 int maxsend = 10;
@@ -1432,16 +1470,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1432 /// <summary> 1470 /// <summary>
1433 /// 1471 ///
1434 /// </summary> 1472 /// </summary>
1435 public void SendTeleportLocationStart() 1473 public void SendTeleportStart(uint flags)
1436 { 1474 {
1437 //TeleportStartPacket tpStart = (TeleportStartPacket)PacketPool.Instance.GetPacket(PacketType.TeleportStart); 1475 TeleportStartPacket tpStart = (TeleportStartPacket)PacketPool.Instance.GetPacket(PacketType.TeleportStart);
1438 TeleportStartPacket tpStart = new TeleportStartPacket(); 1476 //TeleportStartPacket tpStart = new TeleportStartPacket();
1439 tpStart.Info.TeleportFlags = 16; // Teleport via location 1477 tpStart.Info.TeleportFlags = flags; //16; // Teleport via location
1440 1478
1441 // Hack to get this out immediately and skip throttles 1479 // Hack to get this out immediately and skip throttles
1442 OutPacket(tpStart, ThrottleOutPacketType.Unknown); 1480 OutPacket(tpStart, ThrottleOutPacketType.Unknown);
1443 } 1481 }
1444 1482
1483 public void SendTeleportProgress(uint flags, string message)
1484 {
1485 TeleportProgressPacket tpProgress = (TeleportProgressPacket)PacketPool.Instance.GetPacket(PacketType.TeleportProgress);
1486 tpProgress.AgentData.AgentID = this.AgentId;
1487 tpProgress.Info.TeleportFlags = flags;
1488 tpProgress.Info.Message = Util.StringToBytes256(message);
1489
1490 // Hack to get this out immediately and skip throttles
1491 OutPacket(tpProgress, ThrottleOutPacketType.Unknown);
1492 }
1493
1445 public void SendMoneyBalance(UUID transaction, bool success, byte[] description, int balance) 1494 public void SendMoneyBalance(UUID transaction, bool success, byte[] description, int balance)
1446 { 1495 {
1447 MoneyBalanceReplyPacket money = (MoneyBalanceReplyPacket)PacketPool.Instance.GetPacket(PacketType.MoneyBalanceReply); 1496 MoneyBalanceReplyPacket money = (MoneyBalanceReplyPacket)PacketPool.Instance.GetPacket(PacketType.MoneyBalanceReply);
@@ -1450,6 +1499,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1450 money.MoneyData.TransactionSuccess = success; 1499 money.MoneyData.TransactionSuccess = success;
1451 money.MoneyData.Description = description; 1500 money.MoneyData.Description = description;
1452 money.MoneyData.MoneyBalance = balance; 1501 money.MoneyData.MoneyBalance = balance;
1502 money.TransactionInfo.ItemDescription = Util.StringToBytes256("NONE");
1453 OutPacket(money, ThrottleOutPacketType.Task); 1503 OutPacket(money, ThrottleOutPacketType.Task);
1454 } 1504 }
1455 1505
@@ -1491,30 +1541,50 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1491 OutPacket(pc, ThrottleOutPacketType.Unknown); 1541 OutPacket(pc, ThrottleOutPacketType.Unknown);
1492 } 1542 }
1493 1543
1494 public void SendKillObject(ulong regionHandle, uint localID) 1544 public void SendKillObject(ulong regionHandle, List<uint> localIDs)
1495 { 1545 {
1496// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, localID, regionHandle); 1546// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, localID, regionHandle);
1497 1547
1498 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject); 1548 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject);
1499 // TODO: don't create new blocks if recycling an old packet 1549 // TODO: don't create new blocks if recycling an old packet
1500 kill.ObjectData = new KillObjectPacket.ObjectDataBlock[1]; 1550 kill.ObjectData = new KillObjectPacket.ObjectDataBlock[localIDs.Count];
1501 kill.ObjectData[0] = new KillObjectPacket.ObjectDataBlock(); 1551 for (int i = 0 ; i < localIDs.Count ; i++ )
1502 kill.ObjectData[0].ID = localID; 1552 {
1553 kill.ObjectData[i] = new KillObjectPacket.ObjectDataBlock();
1554 kill.ObjectData[i].ID = localIDs[i];
1555 }
1503 kill.Header.Reliable = true; 1556 kill.Header.Reliable = true;
1504 kill.Header.Zerocoded = true; 1557 kill.Header.Zerocoded = true;
1505 1558
1506 lock (m_primFullUpdates.SyncRoot) 1559 if (localIDs.Count == 1 && m_scene.GetScenePresence(localIDs[0]) != null)
1507 { 1560 {
1508 m_killRecord.Add(localID);
1509 OutPacket(kill, ThrottleOutPacketType.State); 1561 OutPacket(kill, ThrottleOutPacketType.State);
1510 } 1562 }
1563 else
1564 {
1565 // We MUST lock for both manipulating the kill record and sending the packet, in order to avoid a race
1566 // condition where a kill can be processed before an out-of-date update for the same object.
1567 // ProcessEntityUpdates() also takes the m_killRecord lock.
1568 lock (m_killRecord)
1569 {
1570 foreach (uint localID in localIDs)
1571 m_killRecord.Add(localID);
1572
1573 // The throttle queue used here must match that being used for updates. Otherwise, there is a
1574 // chance that a kill packet put on a separate queue will be sent to the client before an existing
1575 // update packet on another queue. Receiving updates after kills results in unowned and undeletable
1576 // scene objects in a viewer until that viewer is relogged in.
1577 OutPacket(kill, ThrottleOutPacketType.Task);
1578 }
1579 }
1511 } 1580 }
1512 1581
1513 /// <summary> 1582 /// <summary>
1514 /// Send information about the items contained in a folder to the client. 1583 /// Send information about the items contained in a folder to the client.
1515 ///
1516 /// XXX This method needs some refactoring loving
1517 /// </summary> 1584 /// </summary>
1585 /// <remarks>
1586 /// XXX This method needs some refactoring loving
1587 /// </remarks>
1518 /// <param name="ownerID">The owner of the folder</param> 1588 /// <param name="ownerID">The owner of the folder</param>
1519 /// <param name="folderID">The id of the folder</param> 1589 /// <param name="folderID">The id of the folder</param>
1520 /// <param name="items">The items contained in the folder identified by folderID</param> 1590 /// <param name="items">The items contained in the folder identified by folderID</param>
@@ -1578,14 +1648,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1578 currentPacket.ItemData[itemsSent % MAX_ITEMS_PER_PACKET] = CreateItemDataBlock(items[itemsSent++]); 1648 currentPacket.ItemData[itemsSent % MAX_ITEMS_PER_PACKET] = CreateItemDataBlock(items[itemsSent++]);
1579 else 1649 else
1580 { 1650 {
1651// m_log.DebugFormat(
1652// "[LLCLIENTVIEW]: Sending inventory folder details packet to {0} for folder {1}", Name, folderID);
1581 OutPacket(currentPacket, ThrottleOutPacketType.Asset, false); 1653 OutPacket(currentPacket, ThrottleOutPacketType.Asset, false);
1582 currentPacket = null; 1654 currentPacket = null;
1583 } 1655 }
1584
1585 } 1656 }
1586 1657
1587 if (currentPacket != null) 1658 if (currentPacket != null)
1659 {
1660// m_log.DebugFormat(
1661// "[LLCLIENTVIEW]: Sending inventory folder details packet to {0} for folder {1}", Name, folderID);
1588 OutPacket(currentPacket, ThrottleOutPacketType.Asset, false); 1662 OutPacket(currentPacket, ThrottleOutPacketType.Asset, false);
1663 }
1589 } 1664 }
1590 1665
1591 private InventoryDescendentsPacket.FolderDataBlock CreateFolderDataBlock(InventoryFolderBase folder) 1666 private InventoryDescendentsPacket.FolderDataBlock CreateFolderDataBlock(InventoryFolderBase folder)
@@ -1898,8 +1973,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1898 SendBulkUpdateInventoryItem((InventoryItemBase)node); 1973 SendBulkUpdateInventoryItem((InventoryItemBase)node);
1899 else if (node is InventoryFolderBase) 1974 else if (node is InventoryFolderBase)
1900 SendBulkUpdateInventoryFolder((InventoryFolderBase)node); 1975 SendBulkUpdateInventoryFolder((InventoryFolderBase)node);
1976 else if (node != null)
1977 m_log.ErrorFormat("[CLIENT]: {0} sent unknown inventory node named {1}", Name, node.Name);
1901 else 1978 else
1902 m_log.ErrorFormat("[CLIENT]: Client for {0} sent unknown inventory node named {1}", Name, node.Name); 1979 m_log.ErrorFormat("[CLIENT]: {0} sent null inventory node", Name);
1903 } 1980 }
1904 1981
1905 protected void SendBulkUpdateInventoryItem(InventoryItemBase item) 1982 protected void SendBulkUpdateInventoryItem(InventoryItemBase item)
@@ -2048,6 +2125,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2048 OutPacket(sendXfer, ThrottleOutPacketType.Asset); 2125 OutPacket(sendXfer, ThrottleOutPacketType.Asset);
2049 } 2126 }
2050 2127
2128 public void SendAbortXferPacket(ulong xferID)
2129 {
2130 AbortXferPacket xferItem = (AbortXferPacket)PacketPool.Instance.GetPacket(PacketType.AbortXfer);
2131 xferItem.XferID.ID = xferID;
2132 OutPacket(xferItem, ThrottleOutPacketType.Asset);
2133 }
2134
2051 public void SendEconomyData(float EnergyEfficiency, int ObjectCapacity, int ObjectCount, int PriceEnergyUnit, 2135 public void SendEconomyData(float EnergyEfficiency, int ObjectCapacity, int ObjectCount, int PriceEnergyUnit,
2052 int PriceGroupCreate, int PriceObjectClaim, float PriceObjectRent, float PriceObjectScaleFactor, 2136 int PriceGroupCreate, int PriceObjectClaim, float PriceObjectRent, float PriceObjectScaleFactor,
2053 int PriceParcelClaim, float PriceParcelClaimFactor, int PriceParcelRent, int PricePublicObjectDecay, 2137 int PriceParcelClaim, float PriceParcelClaimFactor, int PriceParcelRent, int PricePublicObjectDecay,
@@ -2167,7 +2251,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2167 OutPacket(loadURL, ThrottleOutPacketType.Task); 2251 OutPacket(loadURL, ThrottleOutPacketType.Task);
2168 } 2252 }
2169 2253
2170 public void SendDialog(string objectname, UUID objectID, string ownerFirstName, string ownerLastName, string msg, UUID textureID, int ch, string[] buttonlabels) 2254 public void SendDialog(
2255 string objectname, UUID objectID, UUID ownerID, string ownerFirstName, string ownerLastName, string msg,
2256 UUID textureID, int ch, string[] buttonlabels)
2171 { 2257 {
2172 ScriptDialogPacket dialog = (ScriptDialogPacket)PacketPool.Instance.GetPacket(PacketType.ScriptDialog); 2258 ScriptDialogPacket dialog = (ScriptDialogPacket)PacketPool.Instance.GetPacket(PacketType.ScriptDialog);
2173 dialog.Data.ObjectID = objectID; 2259 dialog.Data.ObjectID = objectID;
@@ -2185,6 +2271,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2185 buttons[i].ButtonLabel = Util.StringToBytes256(buttonlabels[i]); 2271 buttons[i].ButtonLabel = Util.StringToBytes256(buttonlabels[i]);
2186 } 2272 }
2187 dialog.Buttons = buttons; 2273 dialog.Buttons = buttons;
2274
2275 dialog.OwnerData = new ScriptDialogPacket.OwnerDataBlock[1];
2276 dialog.OwnerData[0] = new ScriptDialogPacket.OwnerDataBlock();
2277 dialog.OwnerData[0].OwnerID = ownerID;
2278
2188 OutPacket(dialog, ThrottleOutPacketType.Task); 2279 OutPacket(dialog, ThrottleOutPacketType.Task);
2189 } 2280 }
2190 2281
@@ -2213,6 +2304,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2213 OutPacket(sound, ThrottleOutPacketType.Task); 2304 OutPacket(sound, ThrottleOutPacketType.Task);
2214 } 2305 }
2215 2306
2307 public void SendTransferAbort(TransferRequestPacket transferRequest)
2308 {
2309 TransferAbortPacket abort = (TransferAbortPacket)PacketPool.Instance.GetPacket(PacketType.TransferAbort);
2310 abort.TransferInfo.TransferID = transferRequest.TransferInfo.TransferID;
2311 abort.TransferInfo.ChannelType = transferRequest.TransferInfo.ChannelType;
2312 m_log.Debug("[Assets] Aborting transfer; asset request failed");
2313 OutPacket(abort, ThrottleOutPacketType.Task);
2314 }
2315
2216 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain) 2316 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain)
2217 { 2317 {
2218 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger); 2318 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger);
@@ -2247,8 +2347,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2247 OrbitalPosition = (OrbitalPosition - m_sunPainDaHalfOrbitalCutoff) * 0.6666666667f + m_sunPainDaHalfOrbitalCutoff; 2347 OrbitalPosition = (OrbitalPosition - m_sunPainDaHalfOrbitalCutoff) * 0.6666666667f + m_sunPainDaHalfOrbitalCutoff;
2248 } 2348 }
2249 2349
2250
2251
2252 SimulatorViewerTimeMessagePacket viewertime = (SimulatorViewerTimeMessagePacket)PacketPool.Instance.GetPacket(PacketType.SimulatorViewerTimeMessage); 2350 SimulatorViewerTimeMessagePacket viewertime = (SimulatorViewerTimeMessagePacket)PacketPool.Instance.GetPacket(PacketType.SimulatorViewerTimeMessage);
2253 viewertime.TimeInfo.SunDirection = Position; 2351 viewertime.TimeInfo.SunDirection = Position;
2254 viewertime.TimeInfo.SunAngVelocity = Velocity; 2352 viewertime.TimeInfo.SunAngVelocity = Velocity;
@@ -2329,7 +2427,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2329 2427
2330 packet.Effect = effectBlocks; 2428 packet.Effect = effectBlocks;
2331 2429
2332 OutPacket(packet, ThrottleOutPacketType.State); 2430 // OutPacket(packet, ThrottleOutPacketType.State);
2431 OutPacket(packet, ThrottleOutPacketType.Task);
2333 } 2432 }
2334 2433
2335 public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] charterMember, 2434 public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] charterMember,
@@ -2558,6 +2657,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2558 2657
2559 public void SendAsset(AssetRequestToClient req) 2658 public void SendAsset(AssetRequestToClient req)
2560 { 2659 {
2660 if (req.AssetInf.Data == null)
2661 {
2662 m_log.ErrorFormat("Cannot send asset {0} ({1}), asset data is null",
2663 req.AssetInf.ID, req.AssetInf.Metadata.ContentType);
2664 return;
2665 }
2666
2561 //m_log.Debug("sending asset " + req.RequestAssetID); 2667 //m_log.Debug("sending asset " + req.RequestAssetID);
2562 TransferInfoPacket Transfer = new TransferInfoPacket(); 2668 TransferInfoPacket Transfer = new TransferInfoPacket();
2563 Transfer.TransferInfo.ChannelType = 2; 2669 Transfer.TransferInfo.ChannelType = 2;
@@ -2645,6 +2751,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2645 2751
2646 public void SendParcelInfo(RegionInfo info, LandData land, UUID parcelID, uint x, uint y) 2752 public void SendParcelInfo(RegionInfo info, LandData land, UUID parcelID, uint x, uint y)
2647 { 2753 {
2754 float dwell = 0.0f;
2755 IDwellModule dwellModule = m_scene.RequestModuleInterface<IDwellModule>();
2756 if (dwellModule != null)
2757 dwell = dwellModule.GetDwell(land.GlobalID);
2648 ParcelInfoReplyPacket reply = (ParcelInfoReplyPacket)PacketPool.Instance.GetPacket(PacketType.ParcelInfoReply); 2758 ParcelInfoReplyPacket reply = (ParcelInfoReplyPacket)PacketPool.Instance.GetPacket(PacketType.ParcelInfoReply);
2649 reply.AgentData.AgentID = m_agentId; 2759 reply.AgentData.AgentID = m_agentId;
2650 reply.Data.ParcelID = parcelID; 2760 reply.Data.ParcelID = parcelID;
@@ -2656,7 +2766,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2656 2766
2657 // Bit 0: Mature, bit 7: on sale, other bits: no idea 2767 // Bit 0: Mature, bit 7: on sale, other bits: no idea
2658 reply.Data.Flags = (byte)( 2768 reply.Data.Flags = (byte)(
2659 ((land.Flags & (uint)ParcelFlags.MaturePublish) != 0 ? (1 << 0) : 0) + 2769 (info.AccessLevel > 13 ? (1 << 0) : 0) +
2660 ((land.Flags & (uint)ParcelFlags.ForSale) != 0 ? (1 << 7) : 0)); 2770 ((land.Flags & (uint)ParcelFlags.ForSale) != 0 ? (1 << 7) : 0));
2661 2771
2662 Vector3 pos = land.UserLocation; 2772 Vector3 pos = land.UserLocation;
@@ -2664,12 +2774,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2664 { 2774 {
2665 pos = (land.AABBMax + land.AABBMin) * 0.5f; 2775 pos = (land.AABBMax + land.AABBMin) * 0.5f;
2666 } 2776 }
2667 reply.Data.GlobalX = info.RegionLocX * Constants.RegionSize + x; 2777 reply.Data.GlobalX = info.RegionLocX + x;
2668 reply.Data.GlobalY = info.RegionLocY * Constants.RegionSize + y; 2778 reply.Data.GlobalY = info.RegionLocY + y;
2669 reply.Data.GlobalZ = pos.Z; 2779 reply.Data.GlobalZ = pos.Z;
2670 reply.Data.SimName = Utils.StringToBytes(info.RegionName); 2780 reply.Data.SimName = Utils.StringToBytes(info.RegionName);
2671 reply.Data.SnapshotID = land.SnapshotID; 2781 reply.Data.SnapshotID = land.SnapshotID;
2672 reply.Data.Dwell = land.Dwell; 2782 reply.Data.Dwell = dwell;
2673 reply.Data.SalePrice = land.SalePrice; 2783 reply.Data.SalePrice = land.SalePrice;
2674 reply.Data.AuctionID = (int)land.AuctionID; 2784 reply.Data.AuctionID = (int)land.AuctionID;
2675 2785
@@ -2697,32 +2807,58 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2697 packet.QueryData = new DirPlacesReplyPacket.QueryDataBlock[1]; 2807 packet.QueryData = new DirPlacesReplyPacket.QueryDataBlock[1];
2698 packet.QueryData[0] = new DirPlacesReplyPacket.QueryDataBlock(); 2808 packet.QueryData[0] = new DirPlacesReplyPacket.QueryDataBlock();
2699 2809
2700 packet.QueryReplies =
2701 new DirPlacesReplyPacket.QueryRepliesBlock[data.Length];
2702
2703 packet.StatusData = new DirPlacesReplyPacket.StatusDataBlock[
2704 data.Length];
2705
2706 packet.AgentData.AgentID = AgentId; 2810 packet.AgentData.AgentID = AgentId;
2707 2811
2708 packet.QueryData[0].QueryID = queryID; 2812 packet.QueryData[0].QueryID = queryID;
2709 2813
2710 int i = 0; 2814 DirPlacesReplyPacket.QueryRepliesBlock[] replies =
2815 new DirPlacesReplyPacket.QueryRepliesBlock[0];
2816 DirPlacesReplyPacket.StatusDataBlock[] status =
2817 new DirPlacesReplyPacket.StatusDataBlock[0];
2818
2819 packet.QueryReplies = replies;
2820 packet.StatusData = status;
2821
2711 foreach (DirPlacesReplyData d in data) 2822 foreach (DirPlacesReplyData d in data)
2712 { 2823 {
2713 packet.QueryReplies[i] = 2824 int idx = replies.Length;
2714 new DirPlacesReplyPacket.QueryRepliesBlock(); 2825 Array.Resize(ref replies, idx + 1);
2715 packet.StatusData[i] = new DirPlacesReplyPacket.StatusDataBlock(); 2826 Array.Resize(ref status, idx + 1);
2716 packet.QueryReplies[i].ParcelID = d.parcelID; 2827
2717 packet.QueryReplies[i].Name = Utils.StringToBytes(d.name); 2828 replies[idx] = new DirPlacesReplyPacket.QueryRepliesBlock();
2718 packet.QueryReplies[i].ForSale = d.forSale; 2829 status[idx] = new DirPlacesReplyPacket.StatusDataBlock();
2719 packet.QueryReplies[i].Auction = d.auction; 2830 replies[idx].ParcelID = d.parcelID;
2720 packet.QueryReplies[i].Dwell = d.dwell; 2831 replies[idx].Name = Utils.StringToBytes(d.name);
2721 packet.StatusData[i].Status = d.Status; 2832 replies[idx].ForSale = d.forSale;
2722 i++; 2833 replies[idx].Auction = d.auction;
2834 replies[idx].Dwell = d.dwell;
2835 status[idx].Status = d.Status;
2836
2837 packet.QueryReplies = replies;
2838 packet.StatusData = status;
2839
2840 if (packet.Length >= 1000)
2841 {
2842 OutPacket(packet, ThrottleOutPacketType.Task);
2843
2844 packet = (DirPlacesReplyPacket)PacketPool.Instance.GetPacket(PacketType.DirPlacesReply);
2845
2846 packet.AgentData = new DirPlacesReplyPacket.AgentDataBlock();
2847
2848 packet.QueryData = new DirPlacesReplyPacket.QueryDataBlock[1];
2849 packet.QueryData[0] = new DirPlacesReplyPacket.QueryDataBlock();
2850
2851 packet.AgentData.AgentID = AgentId;
2852
2853 packet.QueryData[0].QueryID = queryID;
2854
2855 replies = new DirPlacesReplyPacket.QueryRepliesBlock[0];
2856 status = new DirPlacesReplyPacket.StatusDataBlock[0];
2857 }
2723 } 2858 }
2724 2859
2725 OutPacket(packet, ThrottleOutPacketType.Task); 2860 if (replies.Length > 0 || data.Length == 0)
2861 OutPacket(packet, ThrottleOutPacketType.Task);
2726 } 2862 }
2727 2863
2728 public void SendDirPeopleReply(UUID queryID, DirPeopleReplyData[] data) 2864 public void SendDirPeopleReply(UUID queryID, DirPeopleReplyData[] data)
@@ -3015,7 +3151,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3015 { 3151 {
3016 OSDMap GroupDataMap = new OSDMap(6); 3152 OSDMap GroupDataMap = new OSDMap(6);
3017 OSDMap NewGroupDataMap = new OSDMap(1); 3153 OSDMap NewGroupDataMap = new OSDMap(1);
3018 GroupDataMap.Add("GroupPowers", OSD.FromBinary(m.GroupPowers)); 3154 GroupDataMap.Add("GroupPowers", OSD.FromULong(m.GroupPowers));
3019 GroupDataMap.Add("AcceptNotices", OSD.FromBoolean(m.AcceptNotices)); 3155 GroupDataMap.Add("AcceptNotices", OSD.FromBoolean(m.AcceptNotices));
3020 GroupDataMap.Add("GroupTitle", OSD.FromString(m.GroupTitle)); 3156 GroupDataMap.Add("GroupTitle", OSD.FromString(m.GroupTitle));
3021 GroupDataMap.Add("GroupID", OSD.FromUUID(m.GroupID)); 3157 GroupDataMap.Add("GroupID", OSD.FromUUID(m.GroupID));
@@ -3323,20 +3459,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3323 aw.AgentData.SerialNum = (uint)serial; 3459 aw.AgentData.SerialNum = (uint)serial;
3324 aw.AgentData.SessionID = m_sessionId; 3460 aw.AgentData.SessionID = m_sessionId;
3325 3461
3462 int count = 0;
3463 for (int i = 0; i < wearables.Length; i++)
3464 count += wearables[i].Count;
3465
3326 // TODO: don't create new blocks if recycling an old packet 3466 // TODO: don't create new blocks if recycling an old packet
3327 aw.WearableData = new AgentWearablesUpdatePacket.WearableDataBlock[13]; 3467 aw.WearableData = new AgentWearablesUpdatePacket.WearableDataBlock[count];
3328 AgentWearablesUpdatePacket.WearableDataBlock awb; 3468 AgentWearablesUpdatePacket.WearableDataBlock awb;
3469 int idx = 0;
3329 for (int i = 0; i < wearables.Length; i++) 3470 for (int i = 0; i < wearables.Length; i++)
3330 { 3471 {
3331 awb = new AgentWearablesUpdatePacket.WearableDataBlock(); 3472 for (int j = 0; j < wearables[i].Count; j++)
3332 awb.WearableType = (byte)i; 3473 {
3333 awb.AssetID = wearables[i].AssetID; 3474 awb = new AgentWearablesUpdatePacket.WearableDataBlock();
3334 awb.ItemID = wearables[i].ItemID; 3475 awb.WearableType = (byte)i;
3335 aw.WearableData[i] = awb; 3476 awb.AssetID = wearables[i][j].AssetID;
3477 awb.ItemID = wearables[i][j].ItemID;
3478 aw.WearableData[idx] = awb;
3479 idx++;
3336 3480
3337// m_log.DebugFormat( 3481// m_log.DebugFormat(
3338// "[APPEARANCE]: Sending wearable item/asset {0} {1} (index {2}) for {3}", 3482// "[APPEARANCE]: Sending wearable item/asset {0} {1} (index {2}) for {3}",
3339// awb.ItemID, awb.AssetID, i, Name); 3483// awb.ItemID, awb.AssetID, i, Name);
3484 }
3340 } 3485 }
3341 3486
3342 OutPacket(aw, ThrottleOutPacketType.Task); 3487 OutPacket(aw, ThrottleOutPacketType.Task);
@@ -3359,6 +3504,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3359 3504
3360 avp.Sender.IsTrial = false; 3505 avp.Sender.IsTrial = false;
3361 avp.Sender.ID = agentID; 3506 avp.Sender.ID = agentID;
3507 //m_log.DebugFormat("[CLIENT]: Sending appearance for {0} to {1}", agentID.ToString(), AgentId.ToString());
3362 OutPacket(avp, ThrottleOutPacketType.Task); 3508 OutPacket(avp, ThrottleOutPacketType.Task);
3363 } 3509 }
3364 3510
@@ -3381,9 +3527,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3381 ani.AnimationList[i].AnimSequenceID = seqs[i]; 3527 ani.AnimationList[i].AnimSequenceID = seqs[i];
3382 3528
3383 ani.AnimationSourceList[i] = new AvatarAnimationPacket.AnimationSourceListBlock(); 3529 ani.AnimationSourceList[i] = new AvatarAnimationPacket.AnimationSourceListBlock();
3384 ani.AnimationSourceList[i].ObjectID = objectIDs[i]; 3530 if (objectIDs[i].Equals(sourceAgentId))
3385 if (objectIDs[i] == UUID.Zero) 3531 ani.AnimationSourceList[i].ObjectID = UUID.Zero;
3386 ani.AnimationSourceList[i].ObjectID = sourceAgentId; 3532 else
3533 ani.AnimationSourceList[i].ObjectID = objectIDs[i];
3387 } 3534 }
3388 ani.Header.Reliable = false; 3535 ani.Header.Reliable = false;
3389 OutPacket(ani, ThrottleOutPacketType.Task); 3536 OutPacket(ani, ThrottleOutPacketType.Task);
@@ -3396,70 +3543,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3396 /// <summary> 3543 /// <summary>
3397 /// Send an ObjectUpdate packet with information about an avatar 3544 /// Send an ObjectUpdate packet with information about an avatar
3398 /// </summary> 3545 /// </summary>
3399 public void SendAvatarData(SendAvatarData data) 3546 public void SendAvatarDataImmediate(ISceneEntity avatar)
3400 { 3547 {
3548 ScenePresence presence = avatar as ScenePresence;
3549 if (presence == null)
3550 return;
3551
3401 ObjectUpdatePacket objupdate = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate); 3552 ObjectUpdatePacket objupdate = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
3402 objupdate.Header.Zerocoded = true; 3553 objupdate.Header.Zerocoded = true;
3403 3554
3404 objupdate.RegionData.RegionHandle = data.RegionHandle; 3555 objupdate.RegionData.RegionHandle = presence.RegionHandle;
3405 objupdate.RegionData.TimeDilation = ushort.MaxValue; 3556 objupdate.RegionData.TimeDilation = ushort.MaxValue;
3406 3557
3407 objupdate.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1]; 3558 objupdate.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1];
3408 objupdate.ObjectData[0] = CreateAvatarUpdateBlock(data); 3559 objupdate.ObjectData[0] = CreateAvatarUpdateBlock(presence);
3409 OutPacket(objupdate, ThrottleOutPacketType.Task);
3410
3411 // We need to record the avatar local id since the root prim of an attachment points to this.
3412// m_attachmentsSent.Add(data.AvatarLocalID);
3413 }
3414
3415 /// <summary>
3416 /// Send a terse positional/rotation/velocity update about an avatar
3417 /// to the client. This avatar can be that of the client itself.
3418 /// </summary>
3419 public virtual void SendAvatarTerseUpdate(SendAvatarTerseData data)
3420 {
3421 if (data.Priority == double.NaN)
3422 {
3423 m_log.Error("[LLClientView] SendAvatarTerseUpdate received a NaN priority, dropping update");
3424 return;
3425 }
3426
3427 Quaternion rotation = data.Rotation;
3428 if (rotation.W == 0.0f && rotation.X == 0.0f && rotation.Y == 0.0f && rotation.Z == 0.0f)
3429 rotation = Quaternion.Identity;
3430
3431 ImprovedTerseObjectUpdatePacket.ObjectDataBlock terseBlock = CreateImprovedTerseBlock(data);
3432
3433 lock (m_avatarTerseUpdates.SyncRoot)
3434 m_avatarTerseUpdates.Enqueue(data.Priority, terseBlock, data.LocalID);
3435
3436 // If we received an update about our own avatar, process the avatar update priority queue immediately
3437 if (data.AgentID == m_agentId)
3438 ProcessAvatarTerseUpdates();
3439 }
3440
3441 protected void ProcessAvatarTerseUpdates()
3442 {
3443 ImprovedTerseObjectUpdatePacket terse = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate);
3444 terse.Header.Reliable = false;
3445 terse.Header.Zerocoded = true;
3446
3447 //terse.RegionData = new ImprovedTerseObjectUpdatePacket.RegionDataBlock();
3448 terse.RegionData.RegionHandle = Scene.RegionInfo.RegionHandle;
3449 terse.RegionData.TimeDilation = (ushort)(Scene.TimeDilation * ushort.MaxValue);
3450
3451 lock (m_avatarTerseUpdates.SyncRoot)
3452 {
3453 int count = Math.Min(m_avatarTerseUpdates.Count, m_udpServer.AvatarTerseUpdatesPerPacket);
3454 if (count == 0)
3455 return;
3456 3560
3457 terse.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[count]; 3561 OutPacket(objupdate, ThrottleOutPacketType.Task);
3458 for (int i = 0; i < count; i++)
3459 terse.ObjectData[i] = m_avatarTerseUpdates.Dequeue();
3460 }
3461 3562
3462 OutPacket(terse, ThrottleOutPacketType.State); 3563 // We need to record the avatar local id since the root prim of an attachment points to this.
3564// m_attachmentsSent.Add(avatar.LocalId);
3463 } 3565 }
3464 3566
3465 public void SendCoarseLocationUpdate(List<UUID> users, List<Vector3> CoarseLocations) 3567 public void SendCoarseLocationUpdate(List<UUID> users, List<Vector3> CoarseLocations)
@@ -3469,7 +3571,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3469 CoarseLocationUpdatePacket loc = (CoarseLocationUpdatePacket)PacketPool.Instance.GetPacket(PacketType.CoarseLocationUpdate); 3571 CoarseLocationUpdatePacket loc = (CoarseLocationUpdatePacket)PacketPool.Instance.GetPacket(PacketType.CoarseLocationUpdate);
3470 loc.Header.Reliable = false; 3572 loc.Header.Reliable = false;
3471 3573
3472 // Each packet can only hold around 62 avatar positions and the client clears the mini-map each time 3574 // Each packet can only hold around 60 avatar positions and the client clears the mini-map each time
3473 // a CoarseLocationUpdate packet is received. Oh well. 3575 // a CoarseLocationUpdate packet is received. Oh well.
3474 int total = Math.Min(CoarseLocations.Count, 60); 3576 int total = Math.Min(CoarseLocations.Count, 60);
3475 3577
@@ -3506,249 +3608,374 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3506 3608
3507 #region Primitive Packet/Data Sending Methods 3609 #region Primitive Packet/Data Sending Methods
3508 3610
3509 public void SendPrimitiveToClient(SendPrimitiveData data) 3611
3612 /// <summary>
3613 /// Generate one of the object update packets based on PrimUpdateFlags
3614 /// and broadcast the packet to clients
3615 /// </summary>
3616 public void SendEntityUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags)
3510 { 3617 {
3511// string text = data.text; 3618 if (entity is SceneObjectPart)
3512// if (text.IndexOf("\n") >= 0)
3513// text = text.Remove(text.IndexOf("\n"));
3514// m_log.DebugFormat(
3515// "[CLIENT]: Queueing send full info about prim {0}, attachment {1}, text {2} to client {3}",
3516// data.localID, data.attachment, text, Name);
3517
3518 if (data.priority == double.NaN)
3519 { 3619 {
3520 m_log.Error("[LLClientView] SendPrimitiveToClient received a NaN priority, dropping update"); 3620 SceneObjectPart e = (SceneObjectPart)entity;
3521 return; 3621 SceneObjectGroup g = e.ParentGroup;
3622 if (g.RootPart.Shape.State > 30) // HUD
3623 if (g.OwnerID != AgentId)
3624 return; // Don't send updates for other people's HUDs
3522 } 3625 }
3523 3626
3524 Quaternion rotation = data.rotation; 3627 uint priority = m_prioritizer.GetUpdatePriority(this, entity);
3525 if (rotation.W == 0.0f && rotation.X == 0.0f && rotation.Y == 0.0f && rotation.Z == 0.0f)
3526 rotation = Quaternion.Identity;
3527 3628
3528 if (data.AttachPoint > 30 && data.ownerID != AgentId) // Someone else's HUD 3629 lock (m_entityUpdates.SyncRoot)
3529 return; 3630 m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation));
3530 if (data.primShape.State != 0 && data.parentID == 0 && data.primShape.PCode == 9) 3631 }
3531 return;
3532 3632
3533 ObjectUpdatePacket.ObjectDataBlock objectData = CreatePrimUpdateBlock(data); 3633 /// <summary>
3534 3634 /// Requeue an EntityUpdate when it was not acknowledged by the client.
3535// if (data.attachment) 3635 /// We will update the priority and put it in the correct queue, merging update flags
3536// m_attachmentsQueued.Add(data.localID); 3636 /// with any other updates that may be queued for the same entity.
3537 3637 /// The original update time is used for the merged update.
3538 lock (m_primFullUpdates.SyncRoot) 3638 /// </summary>
3539 m_primFullUpdates.Enqueue(data.priority, objectData, data.localID); 3639 private void ResendPrimUpdate(EntityUpdate update)
3540 } 3640 {
3541 3641 // If the update exists in priority queue, it will be updated.
3542 void ProcessPrimFullUpdates() 3642 // If it does not exist then it will be added with the current (rather than its original) priority
3543 { 3643 uint priority = m_prioritizer.GetUpdatePriority(this, update.Entity);
3544 ObjectUpdatePacket outPacket = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
3545 outPacket.Header.Zerocoded = true;
3546
3547 outPacket.RegionData.RegionHandle = Scene.RegionInfo.RegionHandle;
3548 outPacket.RegionData.TimeDilation = (ushort)(Scene.TimeDilation * ushort.MaxValue);
3549
3550 lock (m_primFullUpdates.SyncRoot)
3551 {
3552 int count = Math.Min(m_primFullUpdates.Count, m_udpServer.PrimFullUpdatesPerPacket);
3553 if (count == 0)
3554 return;
3555
3556 m_fullUpdateDataBlocksBuilder.Clear();
3557
3558 for (int i = 0; i < count; i++)
3559 {
3560 ObjectUpdatePacket.ObjectDataBlock block = m_primFullUpdates.Dequeue();
3561
3562 if (!m_killRecord.Contains(block.ID))
3563 {
3564// if (m_attachmentsQueued.Contains(block.ID))
3565// {
3566// string text = Util.FieldToString(block.Text);
3567// if (text.IndexOf("\n") >= 0)
3568// text = text.Remove(text.IndexOf("\n"));
3569//
3570// if (m_attachmentsSent.Contains(block.ParentID))
3571// {
3572// m_log.DebugFormat(
3573// "[CLIENT]: Sending full info about attached prim {0} text {1}",
3574// block.ID, text);
3575//
3576// m_fullUpdateDataBlocksBuilder.Add(block);
3577//
3578// m_attachmentsSent.Add(block.ID);
3579// }
3580// else
3581// {
3582// m_log.DebugFormat(
3583// "[CLIENT]: Requeueing full update of prim {0} text {1} since we haven't sent its parent {2} yet",
3584// block.ID, text, block.ParentID);
3585//
3586// lock (m_primFullUpdates.SyncRoot)
3587// m_primFullUpdates.Enqueue(double.MaxValue, block, block.ID);
3588// }
3589// }
3590// else
3591// {
3592 m_fullUpdateDataBlocksBuilder.Add(block);
3593// }
3594 }
3595// else
3596// {
3597// m_log.WarnFormat(
3598// "[CLIENT]: Preventing full update for {0} after kill to {1}", block.ID, Name);
3599// }
3600 }
3601 3644
3602 outPacket.ObjectData = m_fullUpdateDataBlocksBuilder.ToArray(); 3645 lock (m_entityUpdates.SyncRoot)
3603 3646 m_entityUpdates.Enqueue(priority, update);
3604 OutPacket(outPacket, ThrottleOutPacketType.State);
3605 }
3606 } 3647 }
3607 3648
3608 public void SendPrimTerseUpdate(SendPrimitiveTerseData data) 3649 /// <summary>
3650 /// Requeue a list of EntityUpdates when they were not acknowledged by the client.
3651 /// We will update the priority and put it in the correct queue, merging update flags
3652 /// with any other updates that may be queued for the same entity.
3653 /// The original update time is used for the merged update.
3654 /// </summary>
3655 private void ResendPrimUpdates(List<EntityUpdate> updates, OutgoingPacket oPacket)
3609 { 3656 {
3610 if (data.Priority == double.NaN) 3657 // m_log.WarnFormat("[CLIENT] resending prim updates {0}, packet sequence number {1}", updates[0].UpdateTime, oPacket.SequenceNumber);
3611 {
3612 m_log.Error("[LLClientView] SendPrimTerseUpdate received a NaN priority, dropping update");
3613 return;
3614 }
3615 3658
3616 Quaternion rotation = data.Rotation; 3659 // Remove the update packet from the list of packets waiting for acknowledgement
3617 if (rotation.W == 0.0f && rotation.X == 0.0f && rotation.Y == 0.0f && rotation.Z == 0.0f) 3660 // because we are requeuing the list of updates. They will be resent in new packets
3618 rotation = Quaternion.Identity; 3661 // with the most recent state and priority.
3662 m_udpClient.NeedAcks.Remove(oPacket.SequenceNumber);
3619 3663
3620 if (data.AttachPoint > 30 && data.OwnerID != AgentId) // Someone else's HUD 3664 // Count this as a resent packet since we are going to requeue all of the updates contained in it
3621 return; 3665 Interlocked.Increment(ref m_udpClient.PacketsResent);
3622
3623 ImprovedTerseObjectUpdatePacket.ObjectDataBlock objectData = CreateImprovedTerseBlock(data);
3624 3666
3625 lock (m_primTerseUpdates.SyncRoot) 3667 foreach (EntityUpdate update in updates)
3626 m_primTerseUpdates.Enqueue(data.Priority, objectData, data.LocalID); 3668 ResendPrimUpdate(update);
3627 } 3669 }
3628 3670
3629 void ProcessPrimTerseUpdates() 3671 private void ProcessEntityUpdates(int maxUpdates)
3630 { 3672 {
3631 ImprovedTerseObjectUpdatePacket outPacket = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); 3673 OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>();
3632 outPacket.Header.Reliable = false; 3674 OpenSim.Framework.Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>> compressedUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>>();
3633 outPacket.Header.Zerocoded = true; 3675 OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();
3676 OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();
3634 3677
3635 outPacket.RegionData.RegionHandle = Scene.RegionInfo.RegionHandle; 3678 OpenSim.Framework.Lazy<List<EntityUpdate>> objectUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3636 outPacket.RegionData.TimeDilation = (ushort)(Scene.TimeDilation * ushort.MaxValue); 3679 OpenSim.Framework.Lazy<List<EntityUpdate>> compressedUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3680 OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3681 OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3637 3682
3638 lock (m_primTerseUpdates.SyncRoot) 3683 // Check to see if this is a flush
3684 if (maxUpdates <= 0)
3639 { 3685 {
3640 int count = Math.Min(m_primTerseUpdates.Count, m_udpServer.PrimTerseUpdatesPerPacket); 3686 maxUpdates = Int32.MaxValue;
3641 if (count == 0)
3642 return;
3643
3644 outPacket.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[count];
3645 for (int i = 0; i < count; i++)
3646 outPacket.ObjectData[i] = m_primTerseUpdates.Dequeue();
3647 } 3687 }
3648 3688
3649 OutPacket(outPacket, ThrottleOutPacketType.State); 3689 int updatesThisCall = 0;
3650 }
3651 3690
3652 public void ReprioritizeUpdates(StateUpdateTypes type, UpdatePriorityHandler handler) 3691 // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race
3653 { 3692 // condition where a kill can be processed before an out-of-date update for the same object.
3654 PriorityQueue<double, ImprovedTerseObjectUpdatePacket.ObjectDataBlock>.UpdatePriorityHandler terse_update_priority_handler = 3693 float avgTimeDilation = 1.0f;
3655 delegate(ref double priority, uint local_id) 3694 IEntityUpdate iupdate;
3695 Int32 timeinqueue; // this is just debugging code & can be dropped later
3696
3697 while (updatesThisCall < maxUpdates)
3698 {
3699 lock (m_entityUpdates.SyncRoot)
3700 if (!m_entityUpdates.TryDequeue(out iupdate, out timeinqueue))
3701 break;
3702
3703 EntityUpdate update = (EntityUpdate)iupdate;
3704
3705 avgTimeDilation += update.TimeDilation;
3706 avgTimeDilation *= 0.5f;
3707
3708 if (update.Entity is SceneObjectPart)
3709 {
3710 SceneObjectPart part = (SceneObjectPart)update.Entity;
3711
3712 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client
3713 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good
3714 // safety measure.
3715 //
3716 // If a Linden Lab 1.23.5 client (and possibly later and earlier) receives an object update
3717 // after a kill, it will keep displaying the deleted object until relog. OpenSim currently performs
3718 // updates and kills on different threads with different scheduling strategies, hence this protection.
3719 //
3720 // This doesn't appear to apply to child prims - a client will happily ignore these updates
3721 // after the root prim has been deleted.
3722 lock (m_killRecord)
3723 {
3724 if (m_killRecord.Contains(part.LocalId))
3725 continue;
3726 if (m_killRecord.Contains(part.ParentGroup.RootPart.LocalId))
3727 continue;
3728 }
3729
3730 if (part.ParentGroup.IsDeleted)
3731 continue;
3732
3733 if (part.ParentGroup.IsAttachment)
3734 { // Someone else's HUD, why are we getting these?
3735 if (part.ParentGroup.OwnerID != AgentId &&
3736 part.ParentGroup.RootPart.Shape.State >= 30)
3737 continue;
3738 ScenePresence sp;
3739 // Owner is not in the sim, don't update it to
3740 // anyone
3741 if (!m_scene.TryGetScenePresence(part.OwnerID, out sp))
3742 continue;
3743
3744 List<SceneObjectGroup> atts = sp.GetAttachments();
3745 bool found = false;
3746 foreach (SceneObjectGroup att in atts)
3747 {
3748 if (att == part.ParentGroup)
3749 {
3750 found = true;
3751 break;
3752 }
3753 }
3754
3755 // It's an attachment of a valid avatar, but
3756 // doesn't seem to be attached, skip
3757 if (!found)
3758 continue;
3759 }
3760 if (part.ParentGroup.IsAttachment && m_disableFacelights)
3761 {
3762 if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand &&
3763 part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand)
3764 {
3765 part.Shape.LightEntry = false;
3766 }
3767 }
3768 }
3769
3770 ++updatesThisCall;
3771
3772 #region UpdateFlags to packet type conversion
3773
3774 PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags;
3775
3776 bool canUseCompressed = true;
3777 bool canUseImproved = true;
3778
3779 // Compressed object updates only make sense for LL primitives
3780 if (!(update.Entity is SceneObjectPart))
3656 { 3781 {
3657 priority = handler(new UpdatePriorityData(priority, local_id)); 3782 canUseCompressed = false;
3658 return priority != double.NaN; 3783 }
3659 }; 3784
3660 PriorityQueue<double, ObjectUpdatePacket.ObjectDataBlock>.UpdatePriorityHandler update_priority_handler = 3785 if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate))
3661 delegate(ref double priority, uint local_id) 3786 {
3787 canUseCompressed = false;
3788 canUseImproved = false;
3789 }
3790 else
3662 { 3791 {
3663 priority = handler(new UpdatePriorityData(priority, local_id)); 3792 if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) ||
3664 return priority != double.NaN; 3793 updateFlags.HasFlag(PrimUpdateFlags.Acceleration) ||
3665 }; 3794 updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) ||
3795 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3796 {
3797 canUseCompressed = false;
3798 }
3666 3799
3667 if ((type & StateUpdateTypes.AvatarTerse) != 0) 3800 if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) ||
3668 { 3801 updateFlags.HasFlag(PrimUpdateFlags.ParentID) ||
3669 lock (m_avatarTerseUpdates.SyncRoot) 3802 updateFlags.HasFlag(PrimUpdateFlags.Scale) ||
3670 m_avatarTerseUpdates.Reprioritize(terse_update_priority_handler); 3803 updateFlags.HasFlag(PrimUpdateFlags.PrimData) ||
3671 } 3804 updateFlags.HasFlag(PrimUpdateFlags.Text) ||
3805 updateFlags.HasFlag(PrimUpdateFlags.NameValue) ||
3806 updateFlags.HasFlag(PrimUpdateFlags.ExtraData) ||
3807 updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) ||
3808 updateFlags.HasFlag(PrimUpdateFlags.Sound) ||
3809 updateFlags.HasFlag(PrimUpdateFlags.Particles) ||
3810 updateFlags.HasFlag(PrimUpdateFlags.Material) ||
3811 updateFlags.HasFlag(PrimUpdateFlags.ClickAction) ||
3812 updateFlags.HasFlag(PrimUpdateFlags.MediaURL) ||
3813 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3814 {
3815 canUseImproved = false;
3816 }
3817 }
3672 3818
3673 if ((type & StateUpdateTypes.PrimitiveFull) != 0) 3819 #endregion UpdateFlags to packet type conversion
3674 { 3820
3675 lock (m_primFullUpdates.SyncRoot) 3821 #region Block Construction
3676 m_primFullUpdates.Reprioritize(update_priority_handler); 3822
3823 // TODO: Remove this once we can build compressed updates
3824 canUseCompressed = false;
3825
3826 if (!canUseImproved && !canUseCompressed)
3827 {
3828 if (update.Entity is ScenePresence)
3829 {
3830 objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity));
3831 }
3832 else
3833 {
3834 objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId));
3835 }
3836 }
3837 else if (!canUseImproved)
3838 {
3839 compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags));
3840 }
3841 else
3842 {
3843 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId)
3844 // Self updates go into a special list
3845 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3846 else
3847 // Everything else goes here
3848 terseUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3849 }
3850
3851 #endregion Block Construction
3677 } 3852 }
3678 3853
3679 if ((type & StateUpdateTypes.PrimitiveTerse) != 0) 3854 #region Packet Sending
3855
3856 const float TIME_DILATION = 1.0f;
3857 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f);
3858
3859 if (terseAgentUpdateBlocks.IsValueCreated)
3680 { 3860 {
3681 lock (m_primTerseUpdates.SyncRoot) 3861 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value;
3682 m_primTerseUpdates.Reprioritize(terse_update_priority_handler); 3862
3863 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
3864 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3865 packet.RegionData.TimeDilation = timeDilation;
3866 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3867
3868 for (int i = 0; i < blocks.Count; i++)
3869 packet.ObjectData[i] = blocks[i];
3870
3871 OutPacket(packet, ThrottleOutPacketType.Unknown, true);
3683 } 3872 }
3684 }
3685 3873
3686 public void FlushPrimUpdates() 3874 if (objectUpdateBlocks.IsValueCreated)
3687 {
3688 while (m_primFullUpdates.Count > 0)
3689 { 3875 {
3690 ProcessPrimFullUpdates(); 3876 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value;
3877
3878 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
3879 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3880 packet.RegionData.TimeDilation = timeDilation;
3881 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3882
3883 for (int i = 0; i < blocks.Count; i++)
3884 packet.ObjectData[i] = blocks[i];
3885
3886 OutPacket(packet, ThrottleOutPacketType.Task, true);
3691 } 3887 }
3692 while (m_primTerseUpdates.Count > 0) 3888
3889 if (compressedUpdateBlocks.IsValueCreated)
3693 { 3890 {
3694 ProcessPrimTerseUpdates(); 3891 List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value;
3892
3893 ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
3894 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3895 packet.RegionData.TimeDilation = timeDilation;
3896 packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];
3897
3898 for (int i = 0; i < blocks.Count; i++)
3899 packet.ObjectData[i] = blocks[i];
3900
3901 OutPacket(packet, ThrottleOutPacketType.Task, true);
3695 } 3902 }
3696 while (m_avatarTerseUpdates.Count > 0) 3903
3904 if (terseUpdateBlocks.IsValueCreated)
3697 { 3905 {
3698 ProcessAvatarTerseUpdates(); 3906 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
3907
3908 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
3909 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3910 packet.RegionData.TimeDilation = timeDilation;
3911 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3912
3913 for (int i = 0; i < blocks.Count; i++)
3914 packet.ObjectData[i] = blocks[i];
3915
3916 OutPacket(packet, ThrottleOutPacketType.Task, true);
3699 } 3917 }
3918
3919 #endregion Packet Sending
3700 } 3920 }
3701 3921
3702 #endregion Primitive Packet/Data Sending Methods 3922 public void ReprioritizeUpdates()
3923 {
3924 lock (m_entityUpdates.SyncRoot)
3925 m_entityUpdates.Reprioritize(UpdatePriorityHandler);
3926 }
3703 3927
3704 /// <summary> 3928 private bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity)
3705 ///
3706 /// </summary>
3707 /// <param name="localID"></param>
3708 /// <param name="rotation"></param>
3709 /// <param name="attachPoint"></param>
3710 public void AttachObject(uint localID, Quaternion rotation, byte attachPoint, UUID ownerID)
3711 { 3929 {
3712 if (attachPoint > 30 && ownerID != AgentId) // Someone else's HUD 3930 if (entity != null)
3713 return; 3931 {
3932 priority = m_prioritizer.GetUpdatePriority(this, entity);
3933 return true;
3934 }
3714 3935
3715 ObjectAttachPacket attach = (ObjectAttachPacket)PacketPool.Instance.GetPacket(PacketType.ObjectAttach); 3936 return false;
3716 // TODO: don't create new blocks if recycling an old packet 3937 }
3717 attach.AgentData.AgentID = AgentId; 3938
3718 attach.AgentData.SessionID = m_sessionId; 3939 public void FlushPrimUpdates()
3719 attach.AgentData.AttachmentPoint = attachPoint; 3940 {
3720 attach.ObjectData = new ObjectAttachPacket.ObjectDataBlock[1]; 3941 m_log.WarnFormat("[CLIENT]: Flushing prim updates to " + m_firstName + " " + m_lastName);
3721 attach.ObjectData[0] = new ObjectAttachPacket.ObjectDataBlock(); 3942
3722 attach.ObjectData[0].ObjectLocalID = localID; 3943 while (m_entityUpdates.Count > 0)
3723 attach.ObjectData[0].Rotation = rotation; 3944 ProcessEntityUpdates(-1);
3724 attach.Header.Zerocoded = true;
3725 OutPacket(attach, ThrottleOutPacketType.Task);
3726 } 3945 }
3727 3946
3947 #endregion Primitive Packet/Data Sending Methods
3948
3949 // These are used to implement an adaptive backoff in the number
3950 // of updates converted to packets. Since we don't want packets
3951 // to sit in the queue with old data, only convert enough updates
3952 // to packets that can be sent in 200ms.
3953 private Int32 m_LastQueueFill = 0;
3954 private Int32 m_maxUpdates = 0;
3955
3728 void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories) 3956 void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories)
3729 { 3957 {
3730 if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) 3958 if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
3731 { 3959 {
3732 lock (m_avatarTerseUpdates.SyncRoot) 3960 if (m_maxUpdates == 0 || m_LastQueueFill == 0)
3733 { 3961 {
3734 if (m_avatarTerseUpdates.Count > 0) 3962 m_maxUpdates = m_udpServer.PrimUpdatesPerCallback;
3735 ProcessAvatarTerseUpdates();
3736 } 3963 }
3737 } 3964 else
3738
3739 if ((categories & ThrottleOutPacketTypeFlags.State) != 0)
3740 {
3741 lock (m_primFullUpdates.SyncRoot)
3742 { 3965 {
3743 if (m_primFullUpdates.Count > 0) 3966 if (Util.EnvironmentTickCountSubtract(m_LastQueueFill) < 200)
3744 ProcessPrimFullUpdates(); 3967 m_maxUpdates += 5;
3968 else
3969 m_maxUpdates = m_maxUpdates >> 1;
3745 } 3970 }
3971 m_maxUpdates = Util.Clamp<Int32>(m_maxUpdates,10,500);
3972 m_LastQueueFill = Util.EnvironmentTickCount();
3973
3974 if (m_entityUpdates.Count > 0)
3975 ProcessEntityUpdates(m_maxUpdates);
3746 3976
3747 lock (m_primTerseUpdates.SyncRoot) 3977 if (m_entityProps.Count > 0)
3748 { 3978 ProcessEntityPropertyRequests(m_maxUpdates);
3749 if (m_primTerseUpdates.Count > 0)
3750 ProcessPrimTerseUpdates();
3751 }
3752 } 3979 }
3753 3980
3754 if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0) 3981 if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0)
@@ -3862,135 +4089,250 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3862 OutPacket(pack, ThrottleOutPacketType.Task); 4089 OutPacket(pack, ThrottleOutPacketType.Task);
3863 } 4090 }
3864 4091
3865 public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, 4092 private class ObjectPropertyUpdate : IEntityUpdate
3866 uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask,
3867 uint NextOwnerMask, int OwnershipCost, byte SaleType, int SalePrice, uint Category,
3868 UUID LastOwnerID, string ObjectName, string Description)
3869 { 4093 {
3870 ObjectPropertiesFamilyPacket objPropFamilyPack = (ObjectPropertiesFamilyPacket)PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily); 4094 internal bool SendFamilyProps;
3871 // TODO: don't create new blocks if recycling an old packet 4095 internal bool SendObjectProps;
4096
4097 public ObjectPropertyUpdate(ISceneEntity entity, uint flags, bool sendfam, bool sendobj)
4098 : base(entity,flags)
4099 {
4100 SendFamilyProps = sendfam;
4101 SendObjectProps = sendobj;
4102 }
4103 public void Update(ObjectPropertyUpdate update)
4104 {
4105 SendFamilyProps = SendFamilyProps || update.SendFamilyProps;
4106 SendObjectProps = SendObjectProps || update.SendObjectProps;
4107 // other properties may need to be updated by base class
4108 base.Update(update);
4109 }
4110 }
4111
4112 public void SendObjectPropertiesFamilyData(ISceneEntity entity, uint requestFlags)
4113 {
4114 uint priority = 0; // time based ordering only
4115 lock (m_entityProps.SyncRoot)
4116 m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,requestFlags,true,false));
4117 }
3872 4118
3873 ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = new ObjectPropertiesFamilyPacket.ObjectDataBlock(); 4119 private void ResendPropertyUpdate(ObjectPropertyUpdate update)
3874 objPropDB.RequestFlags = RequestFlags; 4120 {
3875 objPropDB.ObjectID = ObjectUUID; 4121 uint priority = 0;
3876 if (OwnerID == GroupID) 4122 lock (m_entityProps.SyncRoot)
3877 objPropDB.OwnerID = UUID.Zero; 4123 m_entityProps.Enqueue(priority, update);
3878 else 4124 }
3879 objPropDB.OwnerID = OwnerID;
3880 objPropDB.GroupID = GroupID;
3881 objPropDB.BaseMask = BaseMask;
3882 objPropDB.OwnerMask = OwnerMask;
3883 objPropDB.GroupMask = GroupMask;
3884 objPropDB.EveryoneMask = EveryoneMask;
3885 objPropDB.NextOwnerMask = NextOwnerMask;
3886 4125
3887 // TODO: More properties are needed in SceneObjectPart! 4126 private void ResendPropertyUpdates(List<ObjectPropertyUpdate> updates, OutgoingPacket oPacket)
3888 objPropDB.OwnershipCost = OwnershipCost;
3889 objPropDB.SaleType = SaleType;
3890 objPropDB.SalePrice = SalePrice;
3891 objPropDB.Category = Category;
3892 objPropDB.LastOwnerID = LastOwnerID;
3893 objPropDB.Name = Util.StringToBytes256(ObjectName);
3894 objPropDB.Description = Util.StringToBytes256(Description);
3895 objPropFamilyPack.ObjectData = objPropDB;
3896 objPropFamilyPack.Header.Zerocoded = true;
3897 OutPacket(objPropFamilyPack, ThrottleOutPacketType.Task);
3898 }
3899
3900 public void SendObjectPropertiesReply(
3901 UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID,
3902 UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID,
3903 UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName,
3904 string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask,
3905 uint BaseMask, byte saleType, int salePrice)
3906 { 4127 {
3907 //ObjectPropertiesPacket proper = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); 4128 // m_log.WarnFormat("[CLIENT] resending object property {0}",updates[0].UpdateTime);
3908 // TODO: don't create new blocks if recycling an old packet
3909 4129
3910 ObjectPropertiesPacket.ObjectDataBlock block = 4130 // Remove the update packet from the list of packets waiting for acknowledgement
3911 new ObjectPropertiesPacket.ObjectDataBlock(); 4131 // because we are requeuing the list of updates. They will be resent in new packets
4132 // with the most recent state.
4133 m_udpClient.NeedAcks.Remove(oPacket.SequenceNumber);
3912 4134
3913 block.ItemID = ItemID; 4135 // Count this as a resent packet since we are going to requeue all of the updates contained in it
3914 block.CreationDate = CreationDate; 4136 Interlocked.Increment(ref m_udpClient.PacketsResent);
3915 block.CreatorID = CreatorUUID;
3916 block.FolderID = FolderUUID;
3917 block.FromTaskID = FromTaskUUID;
3918 block.GroupID = GroupUUID;
3919 block.InventorySerial = InventorySerial;
3920 4137
3921 block.LastOwnerID = LastOwnerUUID; 4138 foreach (ObjectPropertyUpdate update in updates)
3922 // proper.ObjectData[0].LastOwnerID = UUID.Zero; 4139 ResendPropertyUpdate(update);
4140 }
4141
4142 public void SendObjectPropertiesReply(ISceneEntity entity)
4143 {
4144 uint priority = 0; // time based ordering only
4145 lock (m_entityProps.SyncRoot)
4146 m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,0,false,true));
4147 }
3923 4148
3924 block.ObjectID = ObjectUUID; 4149 private void ProcessEntityPropertyRequests(int maxUpdates)
3925 if (OwnerUUID == GroupUUID) 4150 {
3926 block.OwnerID = UUID.Zero; 4151 OpenSim.Framework.Lazy<List<ObjectPropertiesFamilyPacket.ObjectDataBlock>> objectFamilyBlocks =
3927 else 4152 new OpenSim.Framework.Lazy<List<ObjectPropertiesFamilyPacket.ObjectDataBlock>>();
3928 block.OwnerID = OwnerUUID; 4153
3929 block.TouchName = Util.StringToBytes256(TouchTitle); 4154 OpenSim.Framework.Lazy<List<ObjectPropertiesPacket.ObjectDataBlock>> objectPropertiesBlocks =
3930 block.TextureID = TextureID; 4155 new OpenSim.Framework.Lazy<List<ObjectPropertiesPacket.ObjectDataBlock>>();
3931 block.SitName = Util.StringToBytes256(SitTitle); 4156
3932 block.Name = Util.StringToBytes256(ItemName); 4157 OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>> familyUpdates =
3933 block.Description = Util.StringToBytes256(ItemDescription); 4158 new OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>>();
3934 block.OwnerMask = OwnerMask; 4159
3935 block.NextOwnerMask = NextOwnerMask; 4160 OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>> propertyUpdates =
3936 block.GroupMask = GroupMask; 4161 new OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>>();
3937 block.EveryoneMask = EveryoneMask; 4162
3938 block.BaseMask = BaseMask; 4163 IEntityUpdate iupdate;
3939 // proper.ObjectData[0].AggregatePerms = 53; 4164 Int32 timeinqueue; // this is just debugging code & can be dropped later
3940 // proper.ObjectData[0].AggregatePermTextures = 0; 4165
3941 // proper.ObjectData[0].AggregatePermTexturesOwner = 0; 4166 int updatesThisCall = 0;
3942 block.SaleType = saleType; 4167 while (updatesThisCall < m_maxUpdates)
3943 block.SalePrice = salePrice; 4168 {
3944 4169 lock (m_entityProps.SyncRoot)
3945 lock (m_propertiesPacketTimer) 4170 if (!m_entityProps.TryDequeue(out iupdate, out timeinqueue))
3946 { 4171 break;
3947 m_propertiesBlocks.Add(block); 4172
3948 4173 ObjectPropertyUpdate update = (ObjectPropertyUpdate)iupdate;
3949 int length = 0; 4174 if (update.SendFamilyProps)
3950 foreach (ObjectPropertiesPacket.ObjectDataBlock b in m_propertiesBlocks) 4175 {
3951 { 4176 if (update.Entity is SceneObjectPart)
3952 length += b.Length; 4177 {
3953 } 4178 SceneObjectPart sop = (SceneObjectPart)update.Entity;
3954 if (length > 1100) // FIXME: use real MTU 4179 ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesFamilyBlock(sop,update.Flags);
3955 { 4180 objectFamilyBlocks.Value.Add(objPropDB);
3956 ProcessObjectPropertiesPacket(null, null); 4181 familyUpdates.Value.Add(update);
3957 m_propertiesPacketTimer.Stop(); 4182 }
3958 return;
3959 } 4183 }
3960 4184
3961 m_propertiesPacketTimer.Stop(); 4185 if (update.SendObjectProps)
3962 m_propertiesPacketTimer.Start(); 4186 {
4187 if (update.Entity is SceneObjectPart)
4188 {
4189 SceneObjectPart sop = (SceneObjectPart)update.Entity;
4190 ObjectPropertiesPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesBlock(sop);
4191 objectPropertiesBlocks.Value.Add(objPropDB);
4192 propertyUpdates.Value.Add(update);
4193 }
4194 }
4195
4196 updatesThisCall++;
3963 } 4197 }
4198
3964 4199
3965 //proper.Header.Zerocoded = true; 4200 // Int32 ppcnt = 0;
3966 //OutPacket(proper, ThrottleOutPacketType.Task); 4201 // Int32 pbcnt = 0;
4202
4203 if (objectPropertiesBlocks.IsValueCreated)
4204 {
4205 List<ObjectPropertiesPacket.ObjectDataBlock> blocks = objectPropertiesBlocks.Value;
4206 List<ObjectPropertyUpdate> updates = propertyUpdates.Value;
4207
4208 ObjectPropertiesPacket packet = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties);
4209 packet.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[blocks.Count];
4210 for (int i = 0; i < blocks.Count; i++)
4211 packet.ObjectData[i] = blocks[i];
4212
4213 packet.Header.Zerocoded = true;
4214
4215 // Pass in the delegate so that if this packet needs to be resent, we send the current properties
4216 // of the object rather than the properties when the packet was created
4217 // HACK : Remove intelligent resending until it's fixed in core
4218 //OutPacket(packet, ThrottleOutPacketType.Task, true,
4219 // delegate(OutgoingPacket oPacket)
4220 // {
4221 // ResendPropertyUpdates(updates, oPacket);
4222 // });
4223 OutPacket(packet, ThrottleOutPacketType.Task, true);
4224
4225 // pbcnt += blocks.Count;
4226 // ppcnt++;
4227 }
4228
4229 // Int32 fpcnt = 0;
4230 // Int32 fbcnt = 0;
4231
4232 if (objectFamilyBlocks.IsValueCreated)
4233 {
4234 List<ObjectPropertiesFamilyPacket.ObjectDataBlock> blocks = objectFamilyBlocks.Value;
4235
4236 // one packet per object block... uggh...
4237 for (int i = 0; i < blocks.Count; i++)
4238 {
4239 ObjectPropertiesFamilyPacket packet =
4240 (ObjectPropertiesFamilyPacket)PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily);
4241
4242 packet.ObjectData = blocks[i];
4243 packet.Header.Zerocoded = true;
4244
4245 // Pass in the delegate so that if this packet needs to be resent, we send the current properties
4246 // of the object rather than the properties when the packet was created
4247 List<ObjectPropertyUpdate> updates = new List<ObjectPropertyUpdate>();
4248 updates.Add(familyUpdates.Value[i]);
4249 // HACK : Remove intelligent resending until it's fixed in core
4250 //OutPacket(packet, ThrottleOutPacketType.Task, true,
4251 // delegate(OutgoingPacket oPacket)
4252 // {
4253 // ResendPropertyUpdates(updates, oPacket);
4254 // });
4255 OutPacket(packet, ThrottleOutPacketType.Task, true);
4256
4257 // fpcnt++;
4258 // fbcnt++;
4259 }
4260
4261 }
4262
4263 // m_log.WarnFormat("[PACKETCOUNTS] queued {0} property packets with {1} blocks",ppcnt,pbcnt);
4264 // m_log.WarnFormat("[PACKETCOUNTS] queued {0} family property packets with {1} blocks",fpcnt,fbcnt);
3967 } 4265 }
3968 4266
3969 private void ProcessObjectPropertiesPacket(Object sender, ElapsedEventArgs e) 4267 private ObjectPropertiesFamilyPacket.ObjectDataBlock CreateObjectPropertiesFamilyBlock(SceneObjectPart sop, uint requestFlags)
3970 { 4268 {
3971 ObjectPropertiesPacket proper = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); 4269 ObjectPropertiesFamilyPacket.ObjectDataBlock block = new ObjectPropertiesFamilyPacket.ObjectDataBlock();
3972 4270
3973 lock (m_propertiesPacketTimer) 4271 block.RequestFlags = requestFlags;
3974 { 4272 block.ObjectID = sop.UUID;
3975 m_propertiesPacketTimer.Stop(); 4273 if (sop.OwnerID == sop.GroupID)
4274 block.OwnerID = UUID.Zero;
4275 else
4276 block.OwnerID = sop.OwnerID;
4277 block.GroupID = sop.GroupID;
4278 block.BaseMask = sop.BaseMask;
4279 block.OwnerMask = sop.OwnerMask;
4280 block.GroupMask = sop.GroupMask;
4281 block.EveryoneMask = sop.EveryoneMask;
4282 block.NextOwnerMask = sop.NextOwnerMask;
3976 4283
3977 if (m_propertiesBlocks.Count == 0) 4284 // TODO: More properties are needed in SceneObjectPart!
3978 return; 4285 block.OwnershipCost = sop.OwnershipCost;
4286 block.SaleType = sop.ObjectSaleType;
4287 block.SalePrice = sop.SalePrice;
4288 block.Category = sop.Category;
4289 block.LastOwnerID = sop.CreatorID; // copied from old SOG call... is this right?
4290 block.Name = Util.StringToBytes256(sop.Name);
4291 block.Description = Util.StringToBytes256(sop.Description);
3979 4292
3980 proper.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[m_propertiesBlocks.Count]; 4293 return block;
4294 }
4295
4296 private ObjectPropertiesPacket.ObjectDataBlock CreateObjectPropertiesBlock(SceneObjectPart sop)
4297 {
4298 //ObjectPropertiesPacket proper = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties);
4299 // TODO: don't create new blocks if recycling an old packet
3981 4300
3982 int index = 0; 4301 ObjectPropertiesPacket.ObjectDataBlock block =
4302 new ObjectPropertiesPacket.ObjectDataBlock();
3983 4303
3984 foreach (ObjectPropertiesPacket.ObjectDataBlock b in m_propertiesBlocks) 4304 block.ObjectID = sop.UUID;
3985 { 4305 block.Name = Util.StringToBytes256(sop.Name);
3986 proper.ObjectData[index++] = b; 4306 block.Description = Util.StringToBytes256(sop.Description);
3987 }
3988 4307
3989 m_propertiesBlocks.Clear(); 4308 block.CreationDate = (ulong)sop.CreationDate * 1000000; // viewer wants date in microseconds
3990 } 4309 block.CreatorID = sop.CreatorID;
4310 block.GroupID = sop.GroupID;
4311 block.LastOwnerID = sop.LastOwnerID;
4312 if (sop.OwnerID == sop.GroupID)
4313 block.OwnerID = UUID.Zero;
4314 else
4315 block.OwnerID = sop.OwnerID;
3991 4316
3992 proper.Header.Zerocoded = true; 4317 block.ItemID = sop.FromUserInventoryItemID;
3993 OutPacket(proper, ThrottleOutPacketType.Task); 4318 block.FolderID = UUID.Zero; // sop.FromFolderID ??
4319 block.FromTaskID = UUID.Zero; // ???
4320 block.InventorySerial = (short)sop.InventorySerial;
4321
4322 SceneObjectPart root = sop.ParentGroup.RootPart;
4323
4324 block.TouchName = Util.StringToBytes256(root.TouchName);
4325 block.TextureID = new byte[0]; // TextureID ???
4326 block.SitName = Util.StringToBytes256(root.SitName);
4327 block.OwnerMask = root.OwnerMask;
4328 block.NextOwnerMask = root.NextOwnerMask;
4329 block.GroupMask = root.GroupMask;
4330 block.EveryoneMask = root.EveryoneMask;
4331 block.BaseMask = root.BaseMask;
4332 block.SaleType = root.ObjectSaleType;
4333 block.SalePrice = root.SalePrice;
4334
4335 return block;
3994 } 4336 }
3995 4337
3996 #region Estate Data Sending Methods 4338 #region Estate Data Sending Methods
@@ -4059,37 +4401,44 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4059 if (bl[i].BannedUserID == UUID.Zero) 4401 if (bl[i].BannedUserID == UUID.Zero)
4060 continue; 4402 continue;
4061 BannedUsers.Add(bl[i].BannedUserID); 4403 BannedUsers.Add(bl[i].BannedUserID);
4062 }
4063 4404
4064 EstateOwnerMessagePacket packet = new EstateOwnerMessagePacket(); 4405 if (BannedUsers.Count >= 50 || (i == (bl.Length - 1) && BannedUsers.Count > 0))
4065 packet.AgentData.TransactionID = UUID.Random(); 4406 {
4066 packet.AgentData.AgentID = AgentId; 4407 EstateOwnerMessagePacket packet = new EstateOwnerMessagePacket();
4067 packet.AgentData.SessionID = SessionId; 4408 packet.AgentData.TransactionID = UUID.Random();
4068 packet.MethodData.Invoice = invoice; 4409 packet.AgentData.AgentID = AgentId;
4069 packet.MethodData.Method = Utils.StringToBytes("setaccess"); 4410 packet.AgentData.SessionID = SessionId;
4411 packet.MethodData.Invoice = invoice;
4412 packet.MethodData.Method = Utils.StringToBytes("setaccess");
4070 4413
4071 EstateOwnerMessagePacket.ParamListBlock[] returnblock = new EstateOwnerMessagePacket.ParamListBlock[6 + BannedUsers.Count]; 4414 EstateOwnerMessagePacket.ParamListBlock[] returnblock = new EstateOwnerMessagePacket.ParamListBlock[6 + BannedUsers.Count];
4072 4415
4073 for (int i = 0; i < (6 + BannedUsers.Count); i++) 4416 int j;
4074 { 4417 for (j = 0; j < (6 + BannedUsers.Count); j++)
4075 returnblock[i] = new EstateOwnerMessagePacket.ParamListBlock(); 4418 {
4076 } 4419 returnblock[j] = new EstateOwnerMessagePacket.ParamListBlock();
4077 int j = 0; 4420 }
4421 j = 0;
4078 4422
4079 returnblock[j].Parameter = Utils.StringToBytes(estateID.ToString()); j++; 4423 returnblock[j].Parameter = Utils.StringToBytes(estateID.ToString()); j++;
4080 returnblock[j].Parameter = Utils.StringToBytes(((int)Constants.EstateAccessCodex.EstateBans).ToString()); j++; 4424 returnblock[j].Parameter = Utils.StringToBytes(((int)Constants.EstateAccessCodex.EstateBans).ToString()); j++;
4081 returnblock[j].Parameter = Utils.StringToBytes("0"); j++; 4425 returnblock[j].Parameter = Utils.StringToBytes("0"); j++;
4082 returnblock[j].Parameter = Utils.StringToBytes("0"); j++; 4426 returnblock[j].Parameter = Utils.StringToBytes("0"); j++;
4083 returnblock[j].Parameter = Utils.StringToBytes(BannedUsers.Count.ToString()); j++; 4427 returnblock[j].Parameter = Utils.StringToBytes(BannedUsers.Count.ToString()); j++;
4084 returnblock[j].Parameter = Utils.StringToBytes("0"); j++; 4428 returnblock[j].Parameter = Utils.StringToBytes("0"); j++;
4085 4429
4086 foreach (UUID banned in BannedUsers) 4430 foreach (UUID banned in BannedUsers)
4087 { 4431 {
4088 returnblock[j].Parameter = banned.GetBytes(); j++; 4432 returnblock[j].Parameter = banned.GetBytes(); j++;
4433 }
4434 packet.ParamList = returnblock;
4435 packet.Header.Reliable = true;
4436 OutPacket(packet, ThrottleOutPacketType.Task);
4437
4438 BannedUsers.Clear();
4439 }
4089 } 4440 }
4090 packet.ParamList = returnblock; 4441
4091 packet.Header.Reliable = false;
4092 OutPacket(packet, ThrottleOutPacketType.Task);
4093 } 4442 }
4094 4443
4095 public void SendRegionInfoToEstateMenu(RegionInfoForEstateMenuArgs args) 4444 public void SendRegionInfoToEstateMenu(RegionInfoForEstateMenuArgs args)
@@ -4119,7 +4468,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4119 rinfopack.RegionInfo2.HardMaxAgents = uint.MaxValue; 4468 rinfopack.RegionInfo2.HardMaxAgents = uint.MaxValue;
4120 rinfopack.RegionInfo2.HardMaxObjects = uint.MaxValue; 4469 rinfopack.RegionInfo2.HardMaxObjects = uint.MaxValue;
4121 rinfopack.RegionInfo2.MaxAgents32 = uint.MaxValue; 4470 rinfopack.RegionInfo2.MaxAgents32 = uint.MaxValue;
4122 rinfopack.RegionInfo2.ProductName = Utils.EmptyBytes; 4471 rinfopack.RegionInfo2.ProductName = Util.StringToBytes256(args.regionType);
4123 rinfopack.RegionInfo2.ProductSKU = Utils.EmptyBytes; 4472 rinfopack.RegionInfo2.ProductSKU = Utils.EmptyBytes;
4124 4473
4125 rinfopack.HasVariableBlocks = true; 4474 rinfopack.HasVariableBlocks = true;
@@ -4134,21 +4483,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4134 4483
4135 public void SendEstateCovenantInformation(UUID covenant) 4484 public void SendEstateCovenantInformation(UUID covenant)
4136 { 4485 {
4486// m_log.DebugFormat("[LLCLIENTVIEW]: Sending estate covenant asset id of {0} to {1}", covenant, Name);
4487
4137 EstateCovenantReplyPacket einfopack = new EstateCovenantReplyPacket(); 4488 EstateCovenantReplyPacket einfopack = new EstateCovenantReplyPacket();
4138 EstateCovenantReplyPacket.DataBlock edata = new EstateCovenantReplyPacket.DataBlock(); 4489 EstateCovenantReplyPacket.DataBlock edata = new EstateCovenantReplyPacket.DataBlock();
4139 edata.CovenantID = covenant; 4490 edata.CovenantID = covenant;
4140 edata.CovenantTimestamp = 0; 4491 edata.CovenantTimestamp = 0;
4141 if (m_scene.RegionInfo.EstateSettings.EstateOwner != UUID.Zero) 4492 edata.EstateOwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
4142 edata.EstateOwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
4143 else
4144 edata.EstateOwnerID = m_scene.RegionInfo.MasterAvatarAssignedUUID;
4145 edata.EstateName = Utils.StringToBytes(m_scene.RegionInfo.EstateSettings.EstateName); 4493 edata.EstateName = Utils.StringToBytes(m_scene.RegionInfo.EstateSettings.EstateName);
4146 einfopack.Data = edata; 4494 einfopack.Data = edata;
4147 OutPacket(einfopack, ThrottleOutPacketType.Task); 4495 OutPacket(einfopack, ThrottleOutPacketType.Task);
4148 } 4496 }
4149 4497
4150 public void SendDetailedEstateData(UUID invoice, string estateName, uint estateID, uint parentEstate, uint estateFlags, uint sunPosition, UUID covenant, string abuseEmail, UUID estateOwner) 4498 public void SendDetailedEstateData(
4499 UUID invoice, string estateName, uint estateID, uint parentEstate, uint estateFlags, uint sunPosition,
4500 UUID covenant, string abuseEmail, UUID estateOwner)
4151 { 4501 {
4502// m_log.DebugFormat(
4503// "[LLCLIENTVIEW]: Sending detailed estate data to {0} with covenant asset id {1}", Name, covenant);
4504
4152 EstateOwnerMessagePacket packet = new EstateOwnerMessagePacket(); 4505 EstateOwnerMessagePacket packet = new EstateOwnerMessagePacket();
4153 packet.MethodData.Invoice = invoice; 4506 packet.MethodData.Invoice = invoice;
4154 packet.AgentData.TransactionID = UUID.Random(); 4507 packet.AgentData.TransactionID = UUID.Random();
@@ -4162,8 +4515,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4162 4515
4163 //Sending Estate Settings 4516 //Sending Estate Settings
4164 returnblock[0].Parameter = Utils.StringToBytes(estateName); 4517 returnblock[0].Parameter = Utils.StringToBytes(estateName);
4165 // TODO: remove this cruft once MasterAvatar is fully deprecated
4166 //
4167 returnblock[1].Parameter = Utils.StringToBytes(estateOwner.ToString()); 4518 returnblock[1].Parameter = Utils.StringToBytes(estateOwner.ToString());
4168 returnblock[2].Parameter = Utils.StringToBytes(estateID.ToString()); 4519 returnblock[2].Parameter = Utils.StringToBytes(estateID.ToString());
4169 4520
@@ -4194,96 +4545,116 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4194 OutPacket(packet, ThrottleOutPacketType.Task); 4545 OutPacket(packet, ThrottleOutPacketType.Task);
4195 } 4546 }
4196 4547
4197 public void SendLandProperties(int sequence_id, bool snap_selection, int request_result, LandData landData, float simObjectBonusFactor, int parcelObjectCapacity, int simObjectCapacity, uint regionFlags) 4548 public void SendLandProperties(
4549 int sequence_id, bool snap_selection, int request_result, ILandObject lo,
4550 float simObjectBonusFactor, int parcelObjectCapacity, int simObjectCapacity, uint regionFlags)
4198 { 4551 {
4199 ParcelPropertiesPacket updatePacket = (ParcelPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ParcelProperties); 4552// m_log.DebugFormat("[LLCLIENTVIEW]: Sending land properties for {0} to {1}", lo.LandData.GlobalID, Name);
4200 // TODO: don't create new blocks if recycling an old packet 4553
4201 4554 LandData landData = lo.LandData;
4202 updatePacket.ParcelData.AABBMax = landData.AABBMax; 4555
4203 updatePacket.ParcelData.AABBMin = landData.AABBMin; 4556 ParcelPropertiesMessage updateMessage = new ParcelPropertiesMessage();
4204 updatePacket.ParcelData.Area = landData.Area; 4557
4205 updatePacket.ParcelData.AuctionID = landData.AuctionID; 4558 updateMessage.AABBMax = landData.AABBMax;
4206 updatePacket.ParcelData.AuthBuyerID = landData.AuthBuyerID; 4559 updateMessage.AABBMin = landData.AABBMin;
4207 4560 updateMessage.Area = landData.Area;
4208 updatePacket.ParcelData.Bitmap = landData.Bitmap; 4561 updateMessage.AuctionID = landData.AuctionID;
4209 4562 updateMessage.AuthBuyerID = landData.AuthBuyerID;
4210 updatePacket.ParcelData.Desc = Utils.StringToBytes(landData.Description); 4563 updateMessage.Bitmap = landData.Bitmap;
4211 updatePacket.ParcelData.Category = (byte)landData.Category; 4564 updateMessage.Desc = landData.Description;
4212 updatePacket.ParcelData.ClaimDate = landData.ClaimDate; 4565 updateMessage.Category = landData.Category;
4213 updatePacket.ParcelData.ClaimPrice = landData.ClaimPrice; 4566 updateMessage.ClaimDate = Util.ToDateTime(landData.ClaimDate);
4214 updatePacket.ParcelData.GroupID = landData.GroupID; 4567 updateMessage.ClaimPrice = landData.ClaimPrice;
4215 updatePacket.ParcelData.GroupPrims = landData.GroupPrims; 4568 updateMessage.GroupID = landData.GroupID;
4216 updatePacket.ParcelData.IsGroupOwned = landData.IsGroupOwned; 4569 updateMessage.IsGroupOwned = landData.IsGroupOwned;
4217 updatePacket.ParcelData.LandingType = landData.LandingType; 4570 updateMessage.LandingType = (LandingType) landData.LandingType;
4218 updatePacket.ParcelData.LocalID = landData.LocalID; 4571 updateMessage.LocalID = landData.LocalID;
4219 4572
4220 if (landData.Area > 0) 4573 if (landData.Area > 0)
4221 { 4574 {
4222 updatePacket.ParcelData.MaxPrims = parcelObjectCapacity; 4575 updateMessage.MaxPrims = parcelObjectCapacity;
4223 } 4576 }
4224 else 4577 else
4225 { 4578 {
4226 updatePacket.ParcelData.MaxPrims = 0; 4579 updateMessage.MaxPrims = 0;
4227 } 4580 }
4228 4581
4229 updatePacket.ParcelData.MediaAutoScale = landData.MediaAutoScale; 4582 updateMessage.MediaAutoScale = Convert.ToBoolean(landData.MediaAutoScale);
4230 updatePacket.ParcelData.MediaID = landData.MediaID; 4583 updateMessage.MediaID = landData.MediaID;
4231 updatePacket.ParcelData.MediaURL = Util.StringToBytes256(landData.MediaURL); 4584 updateMessage.MediaURL = landData.MediaURL;
4232 updatePacket.ParcelData.MusicURL = Util.StringToBytes256(landData.MusicURL); 4585 updateMessage.MusicURL = landData.MusicURL;
4233 updatePacket.ParcelData.Name = Util.StringToBytes256(landData.Name); 4586 updateMessage.Name = landData.Name;
4234 updatePacket.ParcelData.OtherCleanTime = landData.OtherCleanTime; 4587 updateMessage.OtherCleanTime = landData.OtherCleanTime;
4235 updatePacket.ParcelData.OtherCount = 0; //TODO: Unimplemented 4588 updateMessage.OtherCount = 0; //TODO: Unimplemented
4236 updatePacket.ParcelData.OtherPrims = landData.OtherPrims; 4589 updateMessage.OwnerID = landData.OwnerID;
4237 updatePacket.ParcelData.OwnerID = landData.OwnerID; 4590 updateMessage.ParcelFlags = (ParcelFlags) landData.Flags;
4238 updatePacket.ParcelData.OwnerPrims = landData.OwnerPrims; 4591 updateMessage.ParcelPrimBonus = simObjectBonusFactor;
4239 updatePacket.ParcelData.ParcelFlags = landData.Flags; 4592 updateMessage.PassHours = landData.PassHours;
4240 updatePacket.ParcelData.ParcelPrimBonus = simObjectBonusFactor; 4593 updateMessage.PassPrice = landData.PassPrice;
4241 updatePacket.ParcelData.PassHours = landData.PassHours; 4594 updateMessage.PublicCount = 0; //TODO: Unimplemented
4242 updatePacket.ParcelData.PassPrice = landData.PassPrice; 4595
4243 updatePacket.ParcelData.PublicCount = 0; //TODO: Unimplemented 4596 updateMessage.RegionPushOverride = (regionFlags & (uint)RegionFlags.RestrictPushObject) > 0;
4244 4597 updateMessage.RegionDenyAnonymous = (regionFlags & (uint)RegionFlags.DenyAnonymous) > 0;
4245 updatePacket.ParcelData.RegionDenyAnonymous = (regionFlags & (uint)RegionFlags.DenyAnonymous) > 0; 4598
4246 updatePacket.ParcelData.RegionDenyIdentified = (regionFlags & (uint)RegionFlags.DenyIdentified) > 0; 4599 //updateMessage.RegionDenyIdentified = (regionFlags & (uint)RegionFlags.DenyIdentified) > 0;
4247 updatePacket.ParcelData.RegionDenyTransacted = (regionFlags & (uint)RegionFlags.DenyTransacted) > 0; 4600 //updateMessage.RegionDenyTransacted = (regionFlags & (uint)RegionFlags.DenyTransacted) > 0;
4248 updatePacket.ParcelData.RegionPushOverride = (regionFlags & (uint)RegionFlags.RestrictPushObject) > 0; 4601
4249 4602 updateMessage.RentPrice = 0;
4250 updatePacket.ParcelData.RentPrice = 0; 4603 updateMessage.RequestResult = (ParcelResult) request_result;
4251 updatePacket.ParcelData.RequestResult = request_result; 4604 updateMessage.SalePrice = landData.SalePrice;
4252 updatePacket.ParcelData.SalePrice = landData.SalePrice; 4605 updateMessage.SelfCount = 0; //TODO: Unimplemented
4253 updatePacket.ParcelData.SelectedPrims = landData.SelectedPrims; 4606 updateMessage.SequenceID = sequence_id;
4254 updatePacket.ParcelData.SelfCount = 0; //TODO: Unimplemented 4607
4255 updatePacket.ParcelData.SequenceID = sequence_id;
4256 if (landData.SimwideArea > 0) 4608 if (landData.SimwideArea > 0)
4257 { 4609 {
4258 updatePacket.ParcelData.SimWideMaxPrims = parcelObjectCapacity; 4610 int simulatorCapacity = (int)((double)(landData.SimwideArea * m_scene.RegionInfo.ObjectCapacity) * m_scene.RegionInfo.RegionSettings.ObjectBonus) / 65536;
4611 // Never report more than sim total capacity
4612 if (simulatorCapacity > m_scene.RegionInfo.ObjectCapacity)
4613 simulatorCapacity = m_scene.RegionInfo.ObjectCapacity;
4614 updateMessage.SimWideMaxPrims = simulatorCapacity;
4259 } 4615 }
4260 else 4616 else
4261 { 4617 {
4262 updatePacket.ParcelData.SimWideMaxPrims = 0; 4618 updateMessage.SimWideMaxPrims = 0;
4263 } 4619 }
4264 updatePacket.ParcelData.SimWideTotalPrims = landData.SimwidePrims; 4620
4265 updatePacket.ParcelData.SnapSelection = snap_selection; 4621 updateMessage.SnapSelection = snap_selection;
4266 updatePacket.ParcelData.SnapshotID = landData.SnapshotID; 4622 updateMessage.SnapshotID = landData.SnapshotID;
4267 updatePacket.ParcelData.Status = (byte)landData.Status; 4623 updateMessage.Status = (ParcelStatus) landData.Status;
4268 updatePacket.ParcelData.TotalPrims = landData.OwnerPrims + landData.GroupPrims + landData.OtherPrims + 4624 updateMessage.UserLocation = landData.UserLocation;
4269 landData.SelectedPrims; 4625 updateMessage.UserLookAt = landData.UserLookAt;
4270 updatePacket.ParcelData.UserLocation = landData.UserLocation; 4626
4271 updatePacket.ParcelData.UserLookAt = landData.UserLookAt; 4627 updateMessage.MediaType = landData.MediaType;
4272 updatePacket.Header.Zerocoded = true; 4628 updateMessage.MediaDesc = landData.MediaDescription;
4629 updateMessage.MediaWidth = landData.MediaWidth;
4630 updateMessage.MediaHeight = landData.MediaHeight;
4631 updateMessage.MediaLoop = landData.MediaLoop;
4632 updateMessage.ObscureMusic = landData.ObscureMusic;
4633 updateMessage.ObscureMedia = landData.ObscureMedia;
4634
4635 IPrimCounts pc = lo.PrimCounts;
4636 updateMessage.OwnerPrims = pc.Owner;
4637 updateMessage.GroupPrims = pc.Group;
4638 updateMessage.OtherPrims = pc.Others;
4639 updateMessage.SelectedPrims = pc.Selected;
4640 updateMessage.TotalPrims = pc.Total;
4641 updateMessage.SimWideTotalPrims = pc.Simulator;
4273 4642
4274 try 4643 try
4275 { 4644 {
4276 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>(); 4645 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>();
4277 if (eq != null) 4646 if (eq != null)
4278 { 4647 {
4279 eq.ParcelProperties(updatePacket, this.AgentId); 4648 eq.ParcelProperties(updateMessage, this.AgentId);
4649 }
4650 else
4651 {
4652 m_log.Warn("[LLCLIENTVIEW]: No EQ Interface when sending parcel data.");
4280 } 4653 }
4281 } 4654 }
4282 catch (Exception ex) 4655 catch (Exception ex)
4283 { 4656 {
4284 m_log.Error("Unable to send parcel data via eventqueue - exception: " + ex.ToString()); 4657 m_log.Error("[LLCLIENTVIEW]: Unable to send parcel data via eventqueue - exception: " + ex.ToString());
4285 m_log.Warn("sending parcel data via UDP");
4286 OutPacket(updatePacket, ThrottleOutPacketType.Task);
4287 } 4658 }
4288 } 4659 }
4289 4660
@@ -4312,6 +4683,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4312 4683
4313 public void SendForceClientSelectObjects(List<uint> ObjectIDs) 4684 public void SendForceClientSelectObjects(List<uint> ObjectIDs)
4314 { 4685 {
4686 m_log.WarnFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count);
4687
4315 bool firstCall = true; 4688 bool firstCall = true;
4316 const int MAX_OBJECTS_PER_PACKET = 251; 4689 const int MAX_OBJECTS_PER_PACKET = 251;
4317 ForceObjectSelectPacket pack = (ForceObjectSelectPacket)PacketPool.Instance.GetPacket(PacketType.ForceObjectSelect); 4690 ForceObjectSelectPacket pack = (ForceObjectSelectPacket)PacketPool.Instance.GetPacket(PacketType.ForceObjectSelect);
@@ -4361,21 +4734,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4361 4734
4362 public void SendLandObjectOwners(LandData land, List<UUID> groups, Dictionary<UUID, int> ownersAndCount) 4735 public void SendLandObjectOwners(LandData land, List<UUID> groups, Dictionary<UUID, int> ownersAndCount)
4363 { 4736 {
4364
4365
4366 int notifyCount = ownersAndCount.Count; 4737 int notifyCount = ownersAndCount.Count;
4367 ParcelObjectOwnersReplyPacket pack = (ParcelObjectOwnersReplyPacket)PacketPool.Instance.GetPacket(PacketType.ParcelObjectOwnersReply); 4738 ParcelObjectOwnersReplyPacket pack = (ParcelObjectOwnersReplyPacket)PacketPool.Instance.GetPacket(PacketType.ParcelObjectOwnersReply);
4368 4739
4369 if (notifyCount > 0) 4740 if (notifyCount > 0)
4370 { 4741 {
4371 if (notifyCount > 32) 4742// if (notifyCount > 32)
4372 { 4743// {
4373 m_log.InfoFormat( 4744// m_log.InfoFormat(
4374 "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}" 4745// "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}"
4375 + " - a developer might want to investigate whether this is a hard limit", 32); 4746// + " - a developer might want to investigate whether this is a hard limit", 32);
4376 4747//
4377 notifyCount = 32; 4748// notifyCount = 32;
4378 } 4749// }
4379 4750
4380 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock 4751 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock
4381 = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount]; 4752 = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount];
@@ -4414,22 +4785,66 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4414 4785
4415 #region Helper Methods 4786 #region Helper Methods
4416 4787
4417 protected ImprovedTerseObjectUpdatePacket.ObjectDataBlock CreateImprovedTerseBlock(SendAvatarTerseData data) 4788 protected ImprovedTerseObjectUpdatePacket.ObjectDataBlock CreateImprovedTerseBlock(ISceneEntity entity, bool sendTexture)
4418 { 4789 {
4419 return CreateImprovedTerseBlock(true, data.LocalID, 0, data.CollisionPlane, data.Position, data.Velocity, 4790 #region ScenePresence/SOP Handling
4420 data.Acceleration, data.Rotation, Vector3.Zero, data.TextureEntry);
4421 }
4422 4791
4423 protected ImprovedTerseObjectUpdatePacket.ObjectDataBlock CreateImprovedTerseBlock(SendPrimitiveTerseData data) 4792 bool avatar = (entity is ScenePresence);
4424 { 4793 uint localID = entity.LocalId;
4425 return CreateImprovedTerseBlock(false, data.LocalID, data.AttachPoint, Vector4.Zero, data.Position, data.Velocity, 4794 uint attachPoint;
4426 data.Acceleration, data.Rotation, data.AngularVelocity, data.TextureEntry); 4795 Vector4 collisionPlane;
4427 } 4796 Vector3 position, velocity, acceleration, angularVelocity;
4797 Quaternion rotation;
4798 byte[] textureEntry;
4799
4800 if (entity is ScenePresence)
4801 {
4802 ScenePresence presence = (ScenePresence)entity;
4803
4804 attachPoint = 0;
4805 collisionPlane = presence.CollisionPlane;
4806 position = presence.OffsetPosition;
4807 velocity = presence.Velocity;
4808 acceleration = Vector3.Zero;
4809
4810 // Interestingly, sending this to non-zero will cause the client's avatar to start moving & accelerating
4811 // in that direction, even though we don't model this on the server. Implementing this in the future
4812 // may improve movement smoothness.
4813// acceleration = new Vector3(1, 0, 0);
4814
4815 angularVelocity = Vector3.Zero;
4816 rotation = presence.Rotation;
4817
4818 if (sendTexture)
4819 textureEntry = presence.Appearance.Texture.GetBytes();
4820 else
4821 textureEntry = null;
4822 }
4823 else
4824 {
4825 SceneObjectPart part = (SceneObjectPart)entity;
4826
4827 attachPoint = part.ParentGroup.AttachmentPoint;
4828
4829// m_log.DebugFormat(
4830// "[LLCLIENTVIEW]: Sending attachPoint {0} for {1} {2} to {3}",
4831// attachPoint, part.Name, part.LocalId, Name);
4832
4833 collisionPlane = Vector4.Zero;
4834 position = part.RelativePosition;
4835 velocity = part.Velocity;
4836 acceleration = part.Acceleration;
4837 angularVelocity = part.AngularVelocity;
4838 rotation = part.RotationOffset;
4839
4840 if (sendTexture)
4841 textureEntry = part.Shape.TextureEntry;
4842 else
4843 textureEntry = null;
4844 }
4845
4846 #endregion ScenePresence/SOP Handling
4428 4847
4429 protected ImprovedTerseObjectUpdatePacket.ObjectDataBlock CreateImprovedTerseBlock(bool avatar, uint localID, int attachPoint,
4430 Vector4 collisionPlane, Vector3 position, Vector3 velocity, Vector3 acceleration, Quaternion rotation,
4431 Vector3 angularVelocity, byte[] textureEntry)
4432 {
4433 int pos = 0; 4848 int pos = 0;
4434 byte[] data = new byte[(avatar ? 60 : 44)]; 4849 byte[] data = new byte[(avatar ? 60 : 44)];
4435 4850
@@ -4501,14 +4916,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4501 return block; 4916 return block;
4502 } 4917 }
4503 4918
4504 protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(SendAvatarData data) 4919 protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(ScenePresence data)
4505 { 4920 {
4506 byte[] objectData = new byte[76]; 4921 byte[] objectData = new byte[76];
4507 4922
4508 Vector4.UnitW.ToBytes(objectData, 0); // TODO: Collision plane support 4923 data.CollisionPlane.ToBytes(objectData, 0);
4509 data.Position.ToBytes(objectData, 16); 4924 data.OffsetPosition.ToBytes(objectData, 16);
4510 //data.Velocity.ToBytes(objectData, 28); 4925// data.Velocity.ToBytes(objectData, 28);
4511 //data.Acceleration.ToBytes(objectData, 40); 4926// data.Acceleration.ToBytes(objectData, 40);
4512 data.Rotation.ToBytes(objectData, 52); 4927 data.Rotation.ToBytes(objectData, 52);
4513 //data.AngularVelocity.ToBytes(objectData, 64); 4928 //data.AngularVelocity.ToBytes(objectData, 64);
4514 4929
@@ -4516,12 +4931,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4516 4931
4517 update.Data = Utils.EmptyBytes; 4932 update.Data = Utils.EmptyBytes;
4518 update.ExtraParams = new byte[1]; 4933 update.ExtraParams = new byte[1];
4519 update.FullID = data.AvatarID; 4934 update.FullID = data.UUID;
4520 update.ID = data.AvatarLocalID; 4935 update.ID = data.LocalId;
4521 update.Material = (byte)Material.Flesh; 4936 update.Material = (byte)Material.Flesh;
4522 update.MediaURL = Utils.EmptyBytes; 4937 update.MediaURL = Utils.EmptyBytes;
4523 update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.FirstName + "\nLastName STRING RW SV " + 4938 update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " +
4524 data.LastName + "\nTitle STRING RW SV " + data.GroupTitle); 4939 data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle);
4525 update.ObjectData = objectData; 4940 update.ObjectData = objectData;
4526 update.ParentID = data.ParentID; 4941 update.ParentID = data.ParentID;
4527 update.PathCurve = 16; 4942 update.PathCurve = 16;
@@ -4530,107 +4945,136 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4530 update.PCode = (byte)PCode.Avatar; 4945 update.PCode = (byte)PCode.Avatar;
4531 update.ProfileCurve = 1; 4946 update.ProfileCurve = 1;
4532 update.PSBlock = Utils.EmptyBytes; 4947 update.PSBlock = Utils.EmptyBytes;
4533 update.Scale = new Vector3(0.45f,0.6f,1.9f); 4948 update.Scale = new Vector3(0.45f, 0.6f, 1.9f);
4534 update.Text = Utils.EmptyBytes; 4949 update.Text = Utils.EmptyBytes;
4535 update.TextColor = new byte[4]; 4950 update.TextColor = new byte[4];
4536 update.TextureAnim = Utils.EmptyBytes; 4951 update.TextureAnim = Utils.EmptyBytes;
4537 update.TextureEntry = data.TextureEntry ?? Utils.EmptyBytes; 4952 update.TextureEntry = (data.Appearance.Texture != null) ? data.Appearance.Texture.GetBytes() : Utils.EmptyBytes;
4538 update.UpdateFlags = (uint)(PrimFlags.Physics | PrimFlags.ObjectModify | PrimFlags.ObjectCopy | PrimFlags.ObjectAnyOwner | PrimFlags.ObjectYouOwner | PrimFlags.ObjectMove | PrimFlags.InventoryEmpty | PrimFlags.ObjectTransfer | PrimFlags.ObjectOwnerModify);//61 + (9 << 8) + (130 << 16) + (16 << 24); // TODO: Replace these numbers with PrimFlags 4953 update.UpdateFlags = (uint)(
4954 PrimFlags.Physics | PrimFlags.ObjectModify | PrimFlags.ObjectCopy | PrimFlags.ObjectAnyOwner |
4955 PrimFlags.ObjectYouOwner | PrimFlags.ObjectMove | PrimFlags.InventoryEmpty | PrimFlags.ObjectTransfer |
4956 PrimFlags.ObjectOwnerModify);
4539 4957
4540 return update; 4958 return update;
4541 } 4959 }
4542 4960
4543 protected ObjectUpdatePacket.ObjectDataBlock CreatePrimUpdateBlock(SendPrimitiveData data) 4961 protected ObjectUpdatePacket.ObjectDataBlock CreatePrimUpdateBlock(SceneObjectPart data, UUID recipientID)
4544 { 4962 {
4545// if (data.attachment)
4546// m_log.DebugFormat(
4547// "[LLCLIENTVIEW]: Creating prim update block for {0}, parent {1}, priority {2}",
4548// data.localID, data.parentID, data.priority);
4549
4550 byte[] objectData = new byte[60]; 4963 byte[] objectData = new byte[60];
4551 data.pos.ToBytes(objectData, 0); 4964 data.RelativePosition.ToBytes(objectData, 0);
4552 data.vel.ToBytes(objectData, 12); 4965 data.Velocity.ToBytes(objectData, 12);
4553 data.acc.ToBytes(objectData, 24); 4966 data.Acceleration.ToBytes(objectData, 24);
4554 data.rotation.ToBytes(objectData, 36); 4967 try
4555 data.rvel.ToBytes(objectData, 48); 4968 {
4969 data.RotationOffset.ToBytes(objectData, 36);
4970 }
4971 catch (Exception e)
4972 {
4973 m_log.Warn("[LLClientView]: exception converting quaternion to bytes, using Quaternion.Identity. Exception: " + e.ToString());
4974 OpenMetaverse.Quaternion.Identity.ToBytes(objectData, 36);
4975 }
4976 data.AngularVelocity.ToBytes(objectData, 48);
4556 4977
4557 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); 4978 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock();
4558 update.ClickAction = (byte)data.clickAction; 4979 update.ClickAction = (byte)data.ClickAction;
4559 update.CRC = 0; 4980 update.CRC = 0;
4560 update.ExtraParams = data.primShape.ExtraParams ?? Utils.EmptyBytes; 4981 update.ExtraParams = data.Shape.ExtraParams ?? Utils.EmptyBytes;
4561 update.FullID = data.objectID; 4982 update.FullID = data.UUID;
4562 update.ID = data.localID; 4983 update.ID = data.LocalId;
4563 //update.JointAxisOrAnchor = Vector3.Zero; // These are deprecated 4984 //update.JointAxisOrAnchor = Vector3.Zero; // These are deprecated
4564 //update.JointPivot = Vector3.Zero; 4985 //update.JointPivot = Vector3.Zero;
4565 //update.JointType = 0; 4986 //update.JointType = 0;
4566 update.Material = data.material; 4987 update.Material = data.Material;
4567 update.MediaURL = Utils.EmptyBytes; // FIXME: Support this in OpenSim 4988 update.MediaURL = Utils.EmptyBytes; // FIXME: Support this in OpenSim
4568 if (data.attachment) 4989 if (data.ParentGroup.IsAttachment)
4569 { 4990 {
4570 update.NameValue = Util.StringToBytes256("AttachItemID STRING RW SV " + data.AssetId); 4991 update.NameValue = Util.StringToBytes256("AttachItemID STRING RW SV " + data.FromItemID);
4571 update.State = (byte)((data.AttachPoint % 16) * 16 + (data.AttachPoint / 16)); 4992 update.State = (byte)((data.ParentGroup.AttachmentPoint % 16) * 16 + (data.ParentGroup.AttachmentPoint / 16));
4572 } 4993 }
4573 else 4994 else
4574 { 4995 {
4575 update.NameValue = Utils.EmptyBytes; 4996 update.NameValue = Utils.EmptyBytes;
4576 update.State = data.primShape.State; 4997
4998 // The root part state is the canonical state for all parts of the object. The other part states in the
4999 // case for attachments may contain conflicting values that can end up crashing the viewer.
5000 update.State = data.ParentGroup.RootPart.Shape.State;
4577 } 5001 }
5002
5003// m_log.DebugFormat(
5004// "[LLCLIENTVIEW]: Sending state {0} for {1} {2} to {3}",
5005// update.State, data.Name, data.LocalId, Name);
5006
4578 update.ObjectData = objectData; 5007 update.ObjectData = objectData;
4579 update.ParentID = data.parentID; 5008 update.ParentID = data.ParentID;
4580 update.PathBegin = data.primShape.PathBegin; 5009 update.PathBegin = data.Shape.PathBegin;
4581 update.PathCurve = data.primShape.PathCurve; 5010 update.PathCurve = data.Shape.PathCurve;
4582 update.PathEnd = data.primShape.PathEnd; 5011 update.PathEnd = data.Shape.PathEnd;
4583 update.PathRadiusOffset = data.primShape.PathRadiusOffset; 5012 update.PathRadiusOffset = data.Shape.PathRadiusOffset;
4584 update.PathRevolutions = data.primShape.PathRevolutions; 5013 update.PathRevolutions = data.Shape.PathRevolutions;
4585 update.PathScaleX = data.primShape.PathScaleX; 5014 update.PathScaleX = data.Shape.PathScaleX;
4586 update.PathScaleY = data.primShape.PathScaleY; 5015 update.PathScaleY = data.Shape.PathScaleY;
4587 update.PathShearX = data.primShape.PathShearX; 5016 update.PathShearX = data.Shape.PathShearX;
4588 update.PathShearY = data.primShape.PathShearY; 5017 update.PathShearY = data.Shape.PathShearY;
4589 update.PathSkew = data.primShape.PathSkew; 5018 update.PathSkew = data.Shape.PathSkew;
4590 update.PathTaperX = data.primShape.PathTaperX; 5019 update.PathTaperX = data.Shape.PathTaperX;
4591 update.PathTaperY = data.primShape.PathTaperY; 5020 update.PathTaperY = data.Shape.PathTaperY;
4592 update.PathTwist = data.primShape.PathTwist; 5021 update.PathTwist = data.Shape.PathTwist;
4593 update.PathTwistBegin = data.primShape.PathTwistBegin; 5022 update.PathTwistBegin = data.Shape.PathTwistBegin;
4594 update.PCode = data.primShape.PCode; 5023 update.PCode = data.Shape.PCode;
4595 update.ProfileBegin = data.primShape.ProfileBegin; 5024 update.ProfileBegin = data.Shape.ProfileBegin;
4596 update.ProfileCurve = data.primShape.ProfileCurve; 5025 update.ProfileCurve = data.Shape.ProfileCurve;
4597 update.ProfileEnd = data.primShape.ProfileEnd; 5026 update.ProfileEnd = data.Shape.ProfileEnd;
4598 update.ProfileHollow = data.primShape.ProfileHollow; 5027 update.ProfileHollow = data.Shape.ProfileHollow;
4599 update.PSBlock = data.particleSystem ?? Utils.EmptyBytes; 5028 update.PSBlock = data.ParticleSystem ?? Utils.EmptyBytes;
4600 update.TextColor = data.color ?? Color4.Black.GetBytes(true); 5029 update.TextColor = data.GetTextColor().GetBytes(false);
4601 update.TextureAnim = data.textureanim ?? Utils.EmptyBytes; 5030 update.TextureAnim = data.TextureAnimation ?? Utils.EmptyBytes;
4602 update.TextureEntry = data.primShape.TextureEntry ?? Utils.EmptyBytes; 5031 update.TextureEntry = data.Shape.TextureEntry ?? Utils.EmptyBytes;
4603 update.Scale = data.primShape.Scale; 5032 update.Scale = data.Shape.Scale;
4604 update.Text = Util.StringToBytes256(data.text); 5033 update.Text = Util.StringToBytes256(data.Text);
4605 update.UpdateFlags = (uint)data.flags; 5034 update.MediaURL = Util.StringToBytes256(data.MediaUrl);
4606 5035
4607 if (data.SoundId != UUID.Zero) 5036 #region PrimFlags
4608 { 5037
4609 update.Sound = data.SoundId; 5038 PrimFlags flags = (PrimFlags)m_scene.Permissions.GenerateClientFlags(recipientID, data.UUID);
4610 update.OwnerID = data.ownerID; 5039
4611 update.Gain = (float)data.SoundVolume; 5040 // Don't send the CreateSelected flag to everyone
5041 flags &= ~PrimFlags.CreateSelected;
5042
5043 if (recipientID == data.OwnerID)
5044 {
5045 if (data.CreateSelected)
5046 {
5047 // Only send this flag once, then unset it
5048 flags |= PrimFlags.CreateSelected;
5049 data.CreateSelected = false;
5050 }
5051 }
5052
5053// m_log.DebugFormat(
5054// "[LLCLIENTVIEW]: Constructing client update for part {0} {1} with flags {2}, localId {3}",
5055// data.Name, update.FullID, flags, update.ID);
5056
5057 update.UpdateFlags = (uint)flags;
5058
5059 #endregion PrimFlags
5060
5061 if (data.Sound != UUID.Zero)
5062 {
5063 update.Sound = data.Sound;
5064 update.OwnerID = data.OwnerID;
5065 update.Gain = (float)data.SoundGain;
4612 update.Radius = (float)data.SoundRadius; 5066 update.Radius = (float)data.SoundRadius;
4613 update.Flags = data.SoundFlags; 5067 update.Flags = data.SoundFlags;
4614 } 5068 }
4615 5069
4616 switch ((PCode)data.primShape.PCode) 5070 switch ((PCode)data.Shape.PCode)
4617 { 5071 {
4618 case PCode.Grass: 5072 case PCode.Grass:
4619 case PCode.Tree: 5073 case PCode.Tree:
4620 case PCode.NewTree: 5074 case PCode.NewTree:
4621 update.Data = new byte[] { data.primShape.State }; 5075 update.Data = new byte[] { data.Shape.State };
4622 break; 5076 break;
4623 default: 5077 default:
4624 // TODO: Support ScratchPad
4625 //if (prim.ScratchPad != null)
4626 //{
4627 // update.Data = new byte[prim.ScratchPad.Length];
4628 // Buffer.BlockCopy(prim.ScratchPad, 0, update.Data, 0, update.Data.Length);
4629 //}
4630 //else
4631 //{
4632 // update.Data = Utils.EmptyBytes;
4633 //}
4634 update.Data = Utils.EmptyBytes; 5078 update.Data = Utils.EmptyBytes;
4635 break; 5079 break;
4636 } 5080 }
@@ -4638,6 +5082,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4638 return update; 5082 return update;
4639 } 5083 }
4640 5084
5085 protected ObjectUpdateCompressedPacket.ObjectDataBlock CreateCompressedUpdateBlock(SceneObjectPart part, PrimUpdateFlags updateFlags)
5086 {
5087 // TODO: Implement this
5088 return null;
5089 }
5090
4641 public void SendNameReply(UUID profileId, string firstname, string lastname) 5091 public void SendNameReply(UUID profileId, string firstname, string lastname)
4642 { 5092 {
4643 UUIDNameReplyPacket packet = (UUIDNameReplyPacket)PacketPool.Instance.GetPacket(PacketType.UUIDNameReply); 5093 UUIDNameReplyPacket packet = (UUIDNameReplyPacket)PacketPool.Instance.GetPacket(PacketType.UUIDNameReply);
@@ -4736,7 +5186,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4736 AddLocalPacketHandler(PacketType.ObjectScale, HandleObjectScale); 5186 AddLocalPacketHandler(PacketType.ObjectScale, HandleObjectScale);
4737 AddLocalPacketHandler(PacketType.ObjectRotation, HandleObjectRotation); 5187 AddLocalPacketHandler(PacketType.ObjectRotation, HandleObjectRotation);
4738 AddLocalPacketHandler(PacketType.ObjectFlagUpdate, HandleObjectFlagUpdate); 5188 AddLocalPacketHandler(PacketType.ObjectFlagUpdate, HandleObjectFlagUpdate);
4739 AddLocalPacketHandler(PacketType.ObjectImage, HandleObjectImage); 5189
5190 // Handle ObjectImage (TextureEntry) updates synchronously, since when updating multiple prim faces at once,
5191 // some clients will send out a separate ObjectImage packet for each face
5192 AddLocalPacketHandler(PacketType.ObjectImage, HandleObjectImage, false);
5193
4740 AddLocalPacketHandler(PacketType.ObjectGrab, HandleObjectGrab, false); 5194 AddLocalPacketHandler(PacketType.ObjectGrab, HandleObjectGrab, false);
4741 AddLocalPacketHandler(PacketType.ObjectGrabUpdate, HandleObjectGrabUpdate, false); 5195 AddLocalPacketHandler(PacketType.ObjectGrabUpdate, HandleObjectGrabUpdate, false);
4742 AddLocalPacketHandler(PacketType.ObjectDeGrab, HandleObjectDeGrab); 5196 AddLocalPacketHandler(PacketType.ObjectDeGrab, HandleObjectDeGrab);
@@ -4766,6 +5220,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4766 AddLocalPacketHandler(PacketType.UpdateInventoryFolder, HandleUpdateInventoryFolder); 5220 AddLocalPacketHandler(PacketType.UpdateInventoryFolder, HandleUpdateInventoryFolder);
4767 AddLocalPacketHandler(PacketType.MoveInventoryFolder, HandleMoveInventoryFolder); 5221 AddLocalPacketHandler(PacketType.MoveInventoryFolder, HandleMoveInventoryFolder);
4768 AddLocalPacketHandler(PacketType.CreateInventoryItem, HandleCreateInventoryItem); 5222 AddLocalPacketHandler(PacketType.CreateInventoryItem, HandleCreateInventoryItem);
5223 AddLocalPacketHandler(PacketType.LinkInventoryItem, HandleLinkInventoryItem);
4769 AddLocalPacketHandler(PacketType.FetchInventory, HandleFetchInventory); 5224 AddLocalPacketHandler(PacketType.FetchInventory, HandleFetchInventory);
4770 AddLocalPacketHandler(PacketType.FetchInventoryDescendents, HandleFetchInventoryDescendents); 5225 AddLocalPacketHandler(PacketType.FetchInventoryDescendents, HandleFetchInventoryDescendents);
4771 AddLocalPacketHandler(PacketType.PurgeInventoryDescendents, HandlePurgeInventoryDescendents); 5226 AddLocalPacketHandler(PacketType.PurgeInventoryDescendents, HandlePurgeInventoryDescendents);
@@ -4787,7 +5242,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4787 AddLocalPacketHandler(PacketType.TeleportLocationRequest, HandleTeleportLocationRequest); 5242 AddLocalPacketHandler(PacketType.TeleportLocationRequest, HandleTeleportLocationRequest);
4788 AddLocalPacketHandler(PacketType.UUIDNameRequest, HandleUUIDNameRequest, false); 5243 AddLocalPacketHandler(PacketType.UUIDNameRequest, HandleUUIDNameRequest, false);
4789 AddLocalPacketHandler(PacketType.RegionHandleRequest, HandleRegionHandleRequest); 5244 AddLocalPacketHandler(PacketType.RegionHandleRequest, HandleRegionHandleRequest);
4790 AddLocalPacketHandler(PacketType.ParcelInfoRequest, HandleParcelInfoRequest, false); 5245 AddLocalPacketHandler(PacketType.ParcelInfoRequest, HandleParcelInfoRequest);
4791 AddLocalPacketHandler(PacketType.ParcelAccessListRequest, HandleParcelAccessListRequest, false); 5246 AddLocalPacketHandler(PacketType.ParcelAccessListRequest, HandleParcelAccessListRequest, false);
4792 AddLocalPacketHandler(PacketType.ParcelAccessListUpdate, HandleParcelAccessListUpdate, false); 5247 AddLocalPacketHandler(PacketType.ParcelAccessListUpdate, HandleParcelAccessListUpdate, false);
4793 AddLocalPacketHandler(PacketType.ParcelPropertiesRequest, HandleParcelPropertiesRequest, false); 5248 AddLocalPacketHandler(PacketType.ParcelPropertiesRequest, HandleParcelPropertiesRequest, false);
@@ -4825,6 +5280,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4825 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false); 5280 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false);
4826 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false); 5281 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false);
4827 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode); 5282 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode);
5283 AddLocalPacketHandler(PacketType.CreateNewOutfitAttachments, HandleCreateNewOutfitAttachments);
4828 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false); 5284 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false);
4829 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents); 5285 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents);
4830 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery); 5286 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery);
@@ -4891,6 +5347,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4891 AddLocalPacketHandler(PacketType.GroupVoteHistoryRequest, HandleGroupVoteHistoryRequest); 5347 AddLocalPacketHandler(PacketType.GroupVoteHistoryRequest, HandleGroupVoteHistoryRequest);
4892 AddLocalPacketHandler(PacketType.SimWideDeletes, HandleSimWideDeletes); 5348 AddLocalPacketHandler(PacketType.SimWideDeletes, HandleSimWideDeletes);
4893 AddLocalPacketHandler(PacketType.SendPostcard, HandleSendPostcard); 5349 AddLocalPacketHandler(PacketType.SendPostcard, HandleSendPostcard);
5350 AddLocalPacketHandler(PacketType.ChangeInventoryItemFlags, HandleChangeInventoryItemFlags);
5351
5352 AddGenericPacketHandler("autopilot", HandleAutopilot);
4894 } 5353 }
4895 5354
4896 #region Packet Handlers 5355 #region Packet Handlers
@@ -4934,7 +5393,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4934 ); 5393 );
4935 } 5394 }
4936 else 5395 else
5396 {
4937 update = true; 5397 update = true;
5398 }
4938 5399
4939 // These should be ordered from most-likely to 5400 // These should be ordered from most-likely to
4940 // least likely to change. I've made an initial 5401 // least likely to change. I've made an initial
@@ -4942,6 +5403,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4942 5403
4943 if (update) 5404 if (update)
4944 { 5405 {
5406// m_log.DebugFormat("[LLCLIENTVIEW]: Triggered AgentUpdate for {0}", sener.Name);
5407
4945 AgentUpdateArgs arg = new AgentUpdateArgs(); 5408 AgentUpdateArgs arg = new AgentUpdateArgs();
4946 arg.AgentID = x.AgentID; 5409 arg.AgentID = x.AgentID;
4947 arg.BodyRotation = x.BodyRotation; 5410 arg.BodyRotation = x.BodyRotation;
@@ -4956,11 +5419,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4956 arg.SessionID = x.SessionID; 5419 arg.SessionID = x.SessionID;
4957 arg.State = x.State; 5420 arg.State = x.State;
4958 UpdateAgent handlerAgentUpdate = OnAgentUpdate; 5421 UpdateAgent handlerAgentUpdate = OnAgentUpdate;
5422 UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate;
4959 lastarg = arg; // save this set of arguments for nexttime 5423 lastarg = arg; // save this set of arguments for nexttime
5424 if (handlerPreAgentUpdate != null)
5425 OnPreAgentUpdate(this, arg);
4960 if (handlerAgentUpdate != null) 5426 if (handlerAgentUpdate != null)
4961 OnAgentUpdate(this, arg); 5427 OnAgentUpdate(this, arg);
4962 5428
4963 handlerAgentUpdate = null; 5429 handlerAgentUpdate = null;
5430 handlerPreAgentUpdate = null;
4964 } 5431 }
4965 } 5432 }
4966 5433
@@ -4987,12 +5454,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4987 5454
4988 return false; 5455 return false;
4989 } 5456 }
4990 5457
4991 private bool HandleParcelGodMarkAsContent(IClientAPI client, Packet Packet) 5458 private bool HandleParcelGodMarkAsContent(IClientAPI client, Packet Packet)
4992 { 5459 {
4993 ParcelGodMarkAsContentPacket ParcelGodMarkAsContent = 5460 ParcelGodMarkAsContentPacket ParcelGodMarkAsContent =
4994 (ParcelGodMarkAsContentPacket)Packet; 5461 (ParcelGodMarkAsContentPacket)Packet;
4995 5462
4996 ParcelGodMark ParcelGodMarkAsContentHandler = OnParcelGodMark; 5463 ParcelGodMark ParcelGodMarkAsContentHandler = OnParcelGodMark;
4997 if (ParcelGodMarkAsContentHandler != null) 5464 if (ParcelGodMarkAsContentHandler != null)
4998 { 5465 {
@@ -5003,11 +5470,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5003 } 5470 }
5004 return false; 5471 return false;
5005 } 5472 }
5006 5473
5007 private bool HandleFreezeUser(IClientAPI client, Packet Packet) 5474 private bool HandleFreezeUser(IClientAPI client, Packet Packet)
5008 { 5475 {
5009 FreezeUserPacket FreezeUser = (FreezeUserPacket)Packet; 5476 FreezeUserPacket FreezeUser = (FreezeUserPacket)Packet;
5010 5477
5011 FreezeUserUpdate FreezeUserHandler = OnParcelFreezeUser; 5478 FreezeUserUpdate FreezeUserHandler = OnParcelFreezeUser;
5012 if (FreezeUserHandler != null) 5479 if (FreezeUserHandler != null)
5013 { 5480 {
@@ -5019,12 +5486,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5019 } 5486 }
5020 return false; 5487 return false;
5021 } 5488 }
5022 5489
5023 private bool HandleEjectUser(IClientAPI client, Packet Packet) 5490 private bool HandleEjectUser(IClientAPI client, Packet Packet)
5024 { 5491 {
5025 EjectUserPacket EjectUser = 5492 EjectUserPacket EjectUser =
5026 (EjectUserPacket)Packet; 5493 (EjectUserPacket)Packet;
5027 5494
5028 EjectUserUpdate EjectUserHandler = OnParcelEjectUser; 5495 EjectUserUpdate EjectUserHandler = OnParcelEjectUser;
5029 if (EjectUserHandler != null) 5496 if (EjectUserHandler != null)
5030 { 5497 {
@@ -5036,12 +5503,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5036 } 5503 }
5037 return false; 5504 return false;
5038 } 5505 }
5039 5506
5040 private bool HandleParcelBuyPass(IClientAPI client, Packet Packet) 5507 private bool HandleParcelBuyPass(IClientAPI client, Packet Packet)
5041 { 5508 {
5042 ParcelBuyPassPacket ParcelBuyPass = 5509 ParcelBuyPassPacket ParcelBuyPass =
5043 (ParcelBuyPassPacket)Packet; 5510 (ParcelBuyPassPacket)Packet;
5044 5511
5045 ParcelBuyPass ParcelBuyPassHandler = OnParcelBuyPass; 5512 ParcelBuyPass ParcelBuyPassHandler = OnParcelBuyPass;
5046 if (ParcelBuyPassHandler != null) 5513 if (ParcelBuyPassHandler != null)
5047 { 5514 {
@@ -5052,7 +5519,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5052 } 5519 }
5053 return false; 5520 return false;
5054 } 5521 }
5055 5522
5056 private bool HandleParcelBuyRequest(IClientAPI sender, Packet Pack) 5523 private bool HandleParcelBuyRequest(IClientAPI sender, Packet Pack)
5057 { 5524 {
5058 ParcelBuyPacket parcel = (ParcelBuyPacket)Pack; 5525 ParcelBuyPacket parcel = (ParcelBuyPacket)Pack;
@@ -5122,11 +5589,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5122 } 5589 }
5123 catch (Exception e) 5590 catch (Exception e)
5124 { 5591 {
5125 m_log.Error("[GENERICMESSAGE] " + e); 5592 m_log.ErrorFormat(
5593 "[LLCLIENTVIEW]: Exeception when handling generic message {0}{1}", e.Message, e.StackTrace);
5126 } 5594 }
5127 } 5595 }
5128 } 5596 }
5129 m_log.Error("[GENERICMESSAGE] Not handling GenericMessage with method-type of: " + method); 5597
5598 //m_log.Debug("[LLCLIENTVIEW]: Not handling GenericMessage with method-type of: " + method);
5130 return false; 5599 return false;
5131 } 5600 }
5132 5601
@@ -5274,7 +5743,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5274 ScriptDialogReplyPacket rdialog = (ScriptDialogReplyPacket)Pack; 5743 ScriptDialogReplyPacket rdialog = (ScriptDialogReplyPacket)Pack;
5275 5744
5276 //m_log.DebugFormat("[CLIENT]: Received ScriptDialogReply from {0}", rdialog.Data.ObjectID); 5745 //m_log.DebugFormat("[CLIENT]: Received ScriptDialogReply from {0}", rdialog.Data.ObjectID);
5277 5746
5278 #region Packet Session and User Check 5747 #region Packet Session and User Check
5279 if (m_checkPackets) 5748 if (m_checkPackets)
5280 { 5749 {
@@ -5420,12 +5889,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5420 } 5889 }
5421 return true; 5890 return true;
5422 } 5891 }
5423 5892
5424 private bool HandleFindAgent(IClientAPI client, Packet Packet) 5893 private bool HandleFindAgent(IClientAPI client, Packet Packet)
5425 { 5894 {
5426 FindAgentPacket FindAgent = 5895 FindAgentPacket FindAgent =
5427 (FindAgentPacket)Packet; 5896 (FindAgentPacket)Packet;
5428 5897
5429 FindAgentUpdate FindAgentHandler = OnFindAgent; 5898 FindAgentUpdate FindAgentHandler = OnFindAgent;
5430 if (FindAgentHandler != null) 5899 if (FindAgentHandler != null)
5431 { 5900 {
@@ -5434,12 +5903,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5434 } 5903 }
5435 return false; 5904 return false;
5436 } 5905 }
5437 5906
5438 private bool HandleTrackAgent(IClientAPI client, Packet Packet) 5907 private bool HandleTrackAgent(IClientAPI client, Packet Packet)
5439 { 5908 {
5440 TrackAgentPacket TrackAgent = 5909 TrackAgentPacket TrackAgent =
5441 (TrackAgentPacket)Packet; 5910 (TrackAgentPacket)Packet;
5442 5911
5443 TrackAgentUpdate TrackAgentHandler = OnTrackAgent; 5912 TrackAgentUpdate TrackAgentHandler = OnTrackAgent;
5444 if (TrackAgentHandler != null) 5913 if (TrackAgentHandler != null)
5445 { 5914 {
@@ -5450,7 +5919,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5450 } 5919 }
5451 return false; 5920 return false;
5452 } 5921 }
5453 5922
5454 private bool HandlerRezObject(IClientAPI sender, Packet Pack) 5923 private bool HandlerRezObject(IClientAPI sender, Packet Pack)
5455 { 5924 {
5456 RezObjectPacket rezPacket = (RezObjectPacket)Pack; 5925 RezObjectPacket rezPacket = (RezObjectPacket)Pack;
@@ -5559,11 +6028,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5559 6028
5560 private bool HandlerAgentWearablesRequest(IClientAPI sender, Packet Pack) 6029 private bool HandlerAgentWearablesRequest(IClientAPI sender, Packet Pack)
5561 { 6030 {
5562 GenericCall2 handlerRequestWearables = OnRequestWearables; 6031 GenericCall1 handlerRequestWearables = OnRequestWearables;
5563 6032
5564 if (handlerRequestWearables != null) 6033 if (handlerRequestWearables != null)
5565 { 6034 {
5566 handlerRequestWearables(); 6035 handlerRequestWearables(sender);
5567 } 6036 }
5568 6037
5569 Action<IClientAPI> handlerRequestAvatarsData = OnRequestAvatarsData; 6038 Action<IClientAPI> handlerRequestAvatarsData = OnRequestAvatarsData;
@@ -5597,6 +6066,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5597 // for the client session anyway, in order to protect ourselves against bad code in plugins 6066 // for the client session anyway, in order to protect ourselves against bad code in plugins
5598 try 6067 try
5599 { 6068 {
6069
5600 byte[] visualparams = new byte[appear.VisualParam.Length]; 6070 byte[] visualparams = new byte[appear.VisualParam.Length];
5601 for (int i = 0; i < appear.VisualParam.Length; i++) 6071 for (int i = 0; i < appear.VisualParam.Length; i++)
5602 visualparams[i] = appear.VisualParam[i].ParamValue; 6072 visualparams[i] = appear.VisualParam[i].ParamValue;
@@ -5605,7 +6075,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5605 if (appear.ObjectData.TextureEntry.Length > 1) 6075 if (appear.ObjectData.TextureEntry.Length > 1)
5606 te = new Primitive.TextureEntry(appear.ObjectData.TextureEntry, 0, appear.ObjectData.TextureEntry.Length); 6076 te = new Primitive.TextureEntry(appear.ObjectData.TextureEntry, 0, appear.ObjectData.TextureEntry.Length);
5607 6077
5608 handlerSetAppearance(te, visualparams); 6078 handlerSetAppearance(sender, te, visualparams);
5609 } 6079 }
5610 catch (Exception e) 6080 catch (Exception e)
5611 { 6081 {
@@ -5636,6 +6106,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5636 AvatarWearingArgs wearingArgs = new AvatarWearingArgs(); 6106 AvatarWearingArgs wearingArgs = new AvatarWearingArgs();
5637 for (int i = 0; i < nowWearing.WearableData.Length; i++) 6107 for (int i = 0; i < nowWearing.WearableData.Length; i++)
5638 { 6108 {
6109 //m_log.DebugFormat("[XXX]: Wearable type {0} item {1}", nowWearing.WearableData[i].WearableType, nowWearing.WearableData[i].ItemID);
5639 AvatarWearingArgs.Wearable wearable = 6110 AvatarWearingArgs.Wearable wearable =
5640 new AvatarWearingArgs.Wearable(nowWearing.WearableData[i].ItemID, 6111 new AvatarWearingArgs.Wearable(nowWearing.WearableData[i].ItemID,
5641 nowWearing.WearableData[i].WearableType); 6112 nowWearing.WearableData[i].WearableType);
@@ -5679,9 +6150,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5679 RezMultipleAttachmentsFromInv handlerRezMultipleAttachments = OnRezMultipleAttachmentsFromInv; 6150 RezMultipleAttachmentsFromInv handlerRezMultipleAttachments = OnRezMultipleAttachmentsFromInv;
5680 if (handlerRezMultipleAttachments != null) 6151 if (handlerRezMultipleAttachments != null)
5681 { 6152 {
5682 RezMultipleAttachmentsFromInvPacket rez = (RezMultipleAttachmentsFromInvPacket)Pack; 6153 List<KeyValuePair<UUID, uint>> rezlist = new List<KeyValuePair<UUID, uint>>();
5683 handlerRezMultipleAttachments(this, rez.HeaderData, 6154 foreach (RezMultipleAttachmentsFromInvPacket.ObjectDataBlock obj in ((RezMultipleAttachmentsFromInvPacket)Pack).ObjectData)
5684 rez.ObjectData); 6155 rezlist.Add(new KeyValuePair<UUID, uint>(obj.ItemID, obj.AttachmentPt));
6156 handlerRezMultipleAttachments(this, rezlist);
5685 } 6157 }
5686 6158
5687 return true; 6159 return true;
@@ -5727,7 +6199,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5727 { 6199 {
5728 if (att.ObjectData.Length > 0) 6200 if (att.ObjectData.Length > 0)
5729 { 6201 {
5730 handlerObjectAttach(this, att.ObjectData[0].ObjectLocalID, att.AgentData.AttachmentPoint, att.ObjectData[0].Rotation, false); 6202 handlerObjectAttach(this, att.ObjectData[0].ObjectLocalID, att.AgentData.AttachmentPoint, false);
5731 } 6203 }
5732 } 6204 }
5733 } 6205 }
@@ -5807,10 +6279,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5807 6279
5808 private bool HandleCompleteAgentMovement(IClientAPI sender, Packet Pack) 6280 private bool HandleCompleteAgentMovement(IClientAPI sender, Packet Pack)
5809 { 6281 {
5810 GenericCall2 handlerCompleteMovementToRegion = OnCompleteMovementToRegion; 6282 Action<IClientAPI, bool> handlerCompleteMovementToRegion = OnCompleteMovementToRegion;
5811 if (handlerCompleteMovementToRegion != null) 6283 if (handlerCompleteMovementToRegion != null)
5812 { 6284 {
5813 handlerCompleteMovementToRegion(); 6285 handlerCompleteMovementToRegion(sender, true);
5814 } 6286 }
5815 handlerCompleteMovementToRegion = null; 6287 handlerCompleteMovementToRegion = null;
5816 6288
@@ -5916,8 +6388,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5916 SoundTrigger handlerSoundTrigger = OnSoundTrigger; 6388 SoundTrigger handlerSoundTrigger = OnSoundTrigger;
5917 if (handlerSoundTrigger != null) 6389 if (handlerSoundTrigger != null)
5918 { 6390 {
5919 handlerSoundTrigger(soundTriggerPacket.SoundData.SoundID, soundTriggerPacket.SoundData.OwnerID, 6391 // UUIDS are sent as zeroes by the client, substitute agent's id
5920 soundTriggerPacket.SoundData.ObjectID, soundTriggerPacket.SoundData.ParentID, 6392 handlerSoundTrigger(soundTriggerPacket.SoundData.SoundID, AgentId,
6393 AgentId, AgentId,
5921 soundTriggerPacket.SoundData.Gain, soundTriggerPacket.SoundData.Position, 6394 soundTriggerPacket.SoundData.Gain, soundTriggerPacket.SoundData.Position,
5922 soundTriggerPacket.SoundData.Handle, 0); 6395 soundTriggerPacket.SoundData.Handle, 0);
5923 6396
@@ -6038,7 +6511,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6038 || avSetStartLocationRequestPacket.StartLocationData.LocationPos.Y == 255.5f) 6511 || avSetStartLocationRequestPacket.StartLocationData.LocationPos.Y == 255.5f)
6039 { 6512 {
6040 ScenePresence avatar = null; 6513 ScenePresence avatar = null;
6041 if (((Scene)m_scene).TryGetAvatar(AgentId, out avatar)) 6514 if (((Scene)m_scene).TryGetScenePresence(AgentId, out avatar))
6042 { 6515 {
6043 if (avSetStartLocationRequestPacket.StartLocationData.LocationPos.X == 255.5f) 6516 if (avSetStartLocationRequestPacket.StartLocationData.LocationPos.X == 255.5f)
6044 { 6517 {
@@ -6287,7 +6760,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6287 } 6760 }
6288 #endregion 6761 #endregion
6289 6762
6290 ObjectDuplicatePacket.AgentDataBlock AgentandGroupData = dupe.AgentData; 6763// ObjectDuplicatePacket.AgentDataBlock AgentandGroupData = dupe.AgentData;
6291 6764
6292 ObjectDuplicate handlerObjectDuplicate = null; 6765 ObjectDuplicate handlerObjectDuplicate = null;
6293 6766
@@ -6297,8 +6770,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6297 if (handlerObjectDuplicate != null) 6770 if (handlerObjectDuplicate != null)
6298 { 6771 {
6299 handlerObjectDuplicate(dupe.ObjectData[i].ObjectLocalID, dupe.SharedData.Offset, 6772 handlerObjectDuplicate(dupe.ObjectData[i].ObjectLocalID, dupe.SharedData.Offset,
6300 dupe.SharedData.DuplicateFlags, AgentandGroupData.AgentID, 6773 dupe.SharedData.DuplicateFlags, AgentId,
6301 AgentandGroupData.GroupID); 6774 m_activeGroupID);
6302 } 6775 }
6303 } 6776 }
6304 6777
@@ -6888,7 +7361,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6888 if (handlerObjectDuplicateOnRay != null) 7361 if (handlerObjectDuplicateOnRay != null)
6889 { 7362 {
6890 handlerObjectDuplicateOnRay(dupeOnRay.ObjectData[i].ObjectLocalID, dupeOnRay.AgentData.DuplicateFlags, 7363 handlerObjectDuplicateOnRay(dupeOnRay.ObjectData[i].ObjectLocalID, dupeOnRay.AgentData.DuplicateFlags,
6891 dupeOnRay.AgentData.AgentID, dupeOnRay.AgentData.GroupID, dupeOnRay.AgentData.RayTargetID, dupeOnRay.AgentData.RayEnd, 7364 AgentId, m_activeGroupID, dupeOnRay.AgentData.RayTargetID, dupeOnRay.AgentData.RayEnd,
6892 dupeOnRay.AgentData.RayStart, dupeOnRay.AgentData.BypassRaycast, dupeOnRay.AgentData.RayEndIsIntersection, 7365 dupeOnRay.AgentData.RayStart, dupeOnRay.AgentData.BypassRaycast, dupeOnRay.AgentData.RayEndIsIntersection,
6893 dupeOnRay.AgentData.CopyCenters, dupeOnRay.AgentData.CopyRotates); 7366 dupeOnRay.AgentData.CopyCenters, dupeOnRay.AgentData.CopyRotates);
6894 } 7367 }
@@ -7048,39 +7521,38 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7048 //handlerTextureRequest = null; 7521 //handlerTextureRequest = null;
7049 for (int i = 0; i < imageRequest.RequestImage.Length; i++) 7522 for (int i = 0; i < imageRequest.RequestImage.Length; i++)
7050 { 7523 {
7051 if (OnRequestTexture != null) 7524 TextureRequestArgs args = new TextureRequestArgs();
7052 {
7053 TextureRequestArgs args = new TextureRequestArgs();
7054
7055 RequestImagePacket.RequestImageBlock block = imageRequest.RequestImage[i];
7056
7057 args.RequestedAssetID = block.Image;
7058 args.DiscardLevel = block.DiscardLevel;
7059 args.PacketNumber = block.Packet;
7060 args.Priority = block.DownloadPriority;
7061 args.requestSequence = imageRequest.Header.Sequence;
7062 7525
7063 // NOTE: This is not a built in part of the LLUDP protocol, but we double the 7526 RequestImagePacket.RequestImageBlock block = imageRequest.RequestImage[i];
7064 // priority of avatar textures to get avatars rezzing in faster than the
7065 // surrounding scene
7066 if ((ImageType)block.Type == ImageType.Baked)
7067 args.Priority *= 2.0f;
7068 7527
7069 //handlerTextureRequest = OnRequestTexture; 7528 args.RequestedAssetID = block.Image;
7529 args.DiscardLevel = block.DiscardLevel;
7530 args.PacketNumber = block.Packet;
7531 args.Priority = block.DownloadPriority;
7532 args.requestSequence = imageRequest.Header.Sequence;
7070 7533
7071 //if (handlerTextureRequest != null) 7534 // NOTE: This is not a built in part of the LLUDP protocol, but we double the
7072 //OnRequestTexture(this, args); 7535 // priority of avatar textures to get avatars rezzing in faster than the
7536 // surrounding scene
7537 if ((ImageType)block.Type == ImageType.Baked)
7538 args.Priority *= 2.0f;
7073 7539
7074 // in the end, we null this, so we have to check if it's null 7540 // in the end, we null this, so we have to check if it's null
7075 if (m_imageManager != null) 7541 if (m_imageManager != null)
7076 { 7542 {
7077 m_imageManager.EnqueueReq(args); 7543 m_imageManager.EnqueueReq(args);
7078 }
7079 } 7544 }
7080 } 7545 }
7081 return true; 7546 return true;
7082 } 7547 }
7083 7548
7549 /// <summary>
7550 /// This is the entry point for the UDP route by which the client can retrieve asset data. If the request
7551 /// is successful then a TransferInfo packet will be sent back, followed by one or more TransferPackets
7552 /// </summary>
7553 /// <param name="sender"></param>
7554 /// <param name="Pack"></param>
7555 /// <returns>This parameter may be ignored since we appear to return true whatever happens</returns>
7084 private bool HandleTransferRequest(IClientAPI sender, Packet Pack) 7556 private bool HandleTransferRequest(IClientAPI sender, Packet Pack)
7085 { 7557 {
7086 //m_log.Debug("ClientView.ProcessPackets.cs:ProcessInPacket() - Got transfer request"); 7558 //m_log.Debug("ClientView.ProcessPackets.cs:ProcessInPacket() - Got transfer request");
@@ -7091,14 +7563,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7091 // Has to be done here, because AssetCache can't do it 7563 // Has to be done here, because AssetCache can't do it
7092 // 7564 //
7093 UUID taskID = UUID.Zero; 7565 UUID taskID = UUID.Zero;
7094 if (transfer.TransferInfo.SourceType == 3) 7566 if (transfer.TransferInfo.SourceType == (int)SourceType.SimInventoryItem)
7095 { 7567 {
7096 taskID = new UUID(transfer.TransferInfo.Params, 48); 7568 taskID = new UUID(transfer.TransferInfo.Params, 48);
7097 UUID itemID = new UUID(transfer.TransferInfo.Params, 64); 7569 UUID itemID = new UUID(transfer.TransferInfo.Params, 64);
7098 UUID requestID = new UUID(transfer.TransferInfo.Params, 80); 7570 UUID requestID = new UUID(transfer.TransferInfo.Params, 80);
7099 7571
7100// m_log.DebugFormat( 7572// m_log.DebugFormat(
7101// "[CLIENT]: Got request for asset {0} from item {1} in prim {2} by {3}", 7573// "[CLIENT]: Got request for asset {0} from item {1} in prim {2} by {3}",
7102// requestID, itemID, taskID, Name); 7574// requestID, itemID, taskID, Name);
7103 7575
7104 if (!(((Scene)m_scene).Permissions.BypassPermissions())) 7576 if (!(((Scene)m_scene).Permissions.BypassPermissions()))
@@ -7106,10 +7578,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7106 if (taskID != UUID.Zero) // Prim 7578 if (taskID != UUID.Zero) // Prim
7107 { 7579 {
7108 SceneObjectPart part = ((Scene)m_scene).GetSceneObjectPart(taskID); 7580 SceneObjectPart part = ((Scene)m_scene).GetSceneObjectPart(taskID);
7581
7109 if (part == null) 7582 if (part == null)
7110 { 7583 {
7111 m_log.WarnFormat( 7584 m_log.WarnFormat(
7112 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but prim does not exist", 7585 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but prim does not exist",
7113 Name, requestID, itemID, taskID); 7586 Name, requestID, itemID, taskID);
7114 return true; 7587 return true;
7115 } 7588 }
@@ -7118,11 +7591,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7118 if (tii == null) 7591 if (tii == null)
7119 { 7592 {
7120 m_log.WarnFormat( 7593 m_log.WarnFormat(
7121 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item does not exist", 7594 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item does not exist",
7122 Name, requestID, itemID, taskID); 7595 Name, requestID, itemID, taskID);
7123 return true; 7596 return true;
7124 } 7597 }
7125 7598
7126 if (tii.Type == (int)AssetType.LSLText) 7599 if (tii.Type == (int)AssetType.LSLText)
7127 { 7600 {
7128 if (!((Scene)m_scene).Permissions.CanEditScript(itemID, taskID, AgentId)) 7601 if (!((Scene)m_scene).Permissions.CanEditScript(itemID, taskID, AgentId))
@@ -7136,103 +7609,68 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7136 else 7609 else
7137 { 7610 {
7138 // TODO: Change this code to allow items other than notecards and scripts to be successfully 7611 // TODO: Change this code to allow items other than notecards and scripts to be successfully
7139 // shared with group. In fact, all this permissions checking should move to an IPermissionsModule 7612 // shared with group. In fact, this whole block of permissions checking should move to an IPermissionsModule
7140 if (part.OwnerID != AgentId) 7613 if (part.OwnerID != AgentId)
7141 { 7614 {
7142 m_log.WarnFormat( 7615 m_log.WarnFormat(
7143 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the prim is owned by {4}", 7616 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the prim is owned by {4}",
7144 Name, requestID, itemID, taskID, part.OwnerID); 7617 Name, requestID, itemID, taskID, part.OwnerID);
7145 return true; 7618 return true;
7146 } 7619 }
7147 7620
7148 if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0) 7621 if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0)
7149 { 7622 {
7150 m_log.WarnFormat( 7623 m_log.WarnFormat(
7151 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but modify permissions are not set", 7624 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but modify permissions are not set",
7152 Name, requestID, itemID, taskID); 7625 Name, requestID, itemID, taskID);
7153 return true; 7626 return true;
7154 } 7627 }
7155 7628
7156 if (tii.OwnerID != AgentId) 7629 if (tii.OwnerID != AgentId)
7157 { 7630 {
7158 m_log.WarnFormat( 7631 m_log.WarnFormat(
7159 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the item is owned by {4}", 7632 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the item is owned by {4}",
7160 Name, requestID, itemID, taskID, tii.OwnerID); 7633 Name, requestID, itemID, taskID, tii.OwnerID);
7161 return true; 7634 return true;
7162 } 7635 }
7163 7636
7164 if (( 7637 if ((
7165 tii.CurrentPermissions & ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) 7638 tii.CurrentPermissions & ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer))
7166 != ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) 7639 != ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer))
7167 { 7640 {
7168 m_log.WarnFormat( 7641 m_log.WarnFormat(
7169 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item permissions are not modify/copy/transfer", 7642 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item permissions are not modify/copy/transfer",
7170 Name, requestID, itemID, taskID); 7643 Name, requestID, itemID, taskID);
7171 return true; 7644 return true;
7172 } 7645 }
7173 7646
7174 if (tii.AssetID != requestID) 7647 if (tii.AssetID != requestID)
7175 { 7648 {
7176 m_log.WarnFormat( 7649 m_log.WarnFormat(
7177 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but this does not match item's asset {4}", 7650 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but this does not match item's asset {4}",
7178 Name, requestID, itemID, taskID, tii.AssetID); 7651 Name, requestID, itemID, taskID, tii.AssetID);
7179 return true; 7652 return true;
7180 } 7653 }
7181 } 7654 }
7182 } 7655 }
7183 else // Agent 7656 else // Agent
7184 { 7657 {
7185 IInventoryService invService = m_scene.RequestModuleInterface<IInventoryService>(); 7658 IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>();
7186 InventoryItemBase assetRequestItem = new InventoryItemBase(itemID, AgentId); 7659 if (invAccess != null)
7187 assetRequestItem = invService.GetItem(assetRequestItem);
7188 if (assetRequestItem == null)
7189 {
7190 assetRequestItem = ((Scene)m_scene).CommsManager.UserProfileCacheService.LibraryRoot.FindItem(itemID);
7191 if (assetRequestItem == null)
7192 return true;
7193 }
7194
7195 // At this point, we need to apply perms
7196 // only to notecards and scripts. All
7197 // other asset types are always available
7198 //
7199 if (assetRequestItem.AssetType == 10)
7200 { 7660 {
7201 if (!((Scene)m_scene).Permissions.CanViewScript(itemID, UUID.Zero, AgentId)) 7661 if (!invAccess.CanGetAgentInventoryItem(this, itemID, requestID))
7202 { 7662 return false;
7203 SendAgentAlertMessage("Insufficient permissions to view script", false);
7204 return true;
7205 }
7206 } 7663 }
7207 else if (assetRequestItem.AssetType == 7) 7664 else
7208 {
7209 if (!((Scene)m_scene).Permissions.CanViewNotecard(itemID, UUID.Zero, AgentId))
7210 {
7211 SendAgentAlertMessage("Insufficient permissions to view notecard", false);
7212 return true;
7213 }
7214 }
7215
7216 if (assetRequestItem.AssetID != requestID)
7217 { 7665 {
7218 m_log.WarnFormat( 7666 return false;
7219 "[CLIENT]: {0} requested asset {1} from item {2} but this does not match item's asset {3}",
7220 Name, requestID, itemID, assetRequestItem.AssetID);
7221 return true;
7222 } 7667 }
7223 } 7668 }
7224 } 7669 }
7225 } 7670 }
7226 7671
7227 //m_assetCache.AddAssetRequest(this, transfer);
7228
7229 MakeAssetRequest(transfer, taskID); 7672 MakeAssetRequest(transfer, taskID);
7230 7673
7231 /* RequestAsset = OnRequestAsset;
7232 if (RequestAsset != null)
7233 {
7234 RequestAsset(this, transfer);
7235 }*/
7236 return true; 7674 return true;
7237 } 7675 }
7238 7676
@@ -7240,7 +7678,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7240 { 7678 {
7241 AssetUploadRequestPacket request = (AssetUploadRequestPacket)Pack; 7679 AssetUploadRequestPacket request = (AssetUploadRequestPacket)Pack;
7242 7680
7243
7244 // m_log.Debug("upload request " + request.ToString()); 7681 // m_log.Debug("upload request " + request.ToString());
7245 // m_log.Debug("upload request was for assetid: " + request.AssetBlock.TransactionID.Combine(this.SecureSessionId).ToString()); 7682 // m_log.Debug("upload request was for assetid: " + request.AssetBlock.TransactionID.Combine(this.SecureSessionId).ToString());
7246 UUID temp = UUID.Combine(request.AssetBlock.TransactionID, SecureSessionId); 7683 UUID temp = UUID.Combine(request.AssetBlock.TransactionID, SecureSessionId);
@@ -7422,6 +7859,38 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7422 return true; 7859 return true;
7423 } 7860 }
7424 7861
7862 private bool HandleLinkInventoryItem(IClientAPI sender, Packet Pack)
7863 {
7864 LinkInventoryItemPacket createLink = (LinkInventoryItemPacket)Pack;
7865
7866 #region Packet Session and User Check
7867 if (m_checkPackets)
7868 {
7869 if (createLink.AgentData.SessionID != SessionId ||
7870 createLink.AgentData.AgentID != AgentId)
7871 return true;
7872 }
7873 #endregion
7874
7875 LinkInventoryItem linkInventoryItem = OnLinkInventoryItem;
7876
7877 if (linkInventoryItem != null)
7878 {
7879 linkInventoryItem(
7880 this,
7881 createLink.InventoryBlock.TransactionID,
7882 createLink.InventoryBlock.FolderID,
7883 createLink.InventoryBlock.CallbackID,
7884 Util.FieldToString(createLink.InventoryBlock.Description),
7885 Util.FieldToString(createLink.InventoryBlock.Name),
7886 createLink.InventoryBlock.InvType,
7887 createLink.InventoryBlock.Type,
7888 createLink.InventoryBlock.OldItemID);
7889 }
7890
7891 return true;
7892 }
7893
7425 private bool HandleFetchInventory(IClientAPI sender, Packet Pack) 7894 private bool HandleFetchInventory(IClientAPI sender, Packet Pack)
7426 { 7895 {
7427 if (OnFetchInventory != null) 7896 if (OnFetchInventory != null)
@@ -7782,7 +8251,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7782 newTaskItem, updatetask.UpdateData.LocalID); 8251 newTaskItem, updatetask.UpdateData.LocalID);
7783 } 8252 }
7784 } 8253 }
7785 } 8254 }
7786 8255
7787 return true; 8256 return true;
7788 } 8257 }
@@ -7919,13 +8388,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7919 return true; 8388 return true;
7920 } 8389 }
7921 #endregion 8390 #endregion
7922
7923 string mapName = Util.UTF8.GetString(map.NameData.Name, 0, 8391 string mapName = Util.UTF8.GetString(map.NameData.Name, 0,
7924 map.NameData.Name.Length - 1); 8392 map.NameData.Name.Length - 1);
7925 RequestMapName handlerMapNameRequest = OnMapNameRequest; 8393 RequestMapName handlerMapNameRequest = OnMapNameRequest;
7926 if (handlerMapNameRequest != null) 8394 if (handlerMapNameRequest != null)
7927 { 8395 {
7928 handlerMapNameRequest(this, mapName); 8396 handlerMapNameRequest(this, mapName, map.AgentData.Flags);
7929 } 8397 }
7930 return true; 8398 return true;
7931 } 8399 }
@@ -7947,16 +8415,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7947 AssetLandmark lm; 8415 AssetLandmark lm;
7948 if (lmid != UUID.Zero) 8416 if (lmid != UUID.Zero)
7949 { 8417 {
8418
7950 //AssetBase lma = m_assetCache.GetAsset(lmid, false); 8419 //AssetBase lma = m_assetCache.GetAsset(lmid, false);
7951 AssetBase lma = m_assetService.Get(lmid.ToString()); 8420 AssetBase lma = m_assetService.Get(lmid.ToString());
7952 8421
7953 if (lma == null) 8422 if (lma == null)
7954 { 8423 {
7955 // Failed to find landmark 8424 // Failed to find landmark
7956 TeleportCancelPacket tpCancel = (TeleportCancelPacket)PacketPool.Instance.GetPacket(PacketType.TeleportCancel); 8425
7957 tpCancel.Info.SessionID = tpReq.Info.SessionID; 8426 // Let's try to search in the user's home asset server
7958 tpCancel.Info.AgentID = tpReq.Info.AgentID; 8427 lma = FindAssetInUserAssetServer(lmid.ToString());
7959 OutPacket(tpCancel, ThrottleOutPacketType.Task); 8428
8429 if (lma == null)
8430 {
8431 // Really doesn't exist
8432 TeleportCancelPacket tpCancel = (TeleportCancelPacket)PacketPool.Instance.GetPacket(PacketType.TeleportCancel);
8433 tpCancel.Info.SessionID = tpReq.Info.SessionID;
8434 tpCancel.Info.AgentID = tpReq.Info.AgentID;
8435 OutPacket(tpCancel, ThrottleOutPacketType.Task);
8436 }
7960 } 8437 }
7961 8438
7962 try 8439 try
@@ -7987,13 +8464,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7987 TeleportLandmarkRequest handlerTeleportLandmarkRequest = OnTeleportLandmarkRequest; 8464 TeleportLandmarkRequest handlerTeleportLandmarkRequest = OnTeleportLandmarkRequest;
7988 if (handlerTeleportLandmarkRequest != null) 8465 if (handlerTeleportLandmarkRequest != null)
7989 { 8466 {
7990 handlerTeleportLandmarkRequest(this, lm.RegionID, lm.Position); 8467 handlerTeleportLandmarkRequest(this, lm);
7991 } 8468 }
7992 else 8469 else
7993 { 8470 {
7994 //no event handler so cancel request 8471 //no event handler so cancel request
7995
7996
7997 TeleportCancelPacket tpCancel = (TeleportCancelPacket)PacketPool.Instance.GetPacket(PacketType.TeleportCancel); 8472 TeleportCancelPacket tpCancel = (TeleportCancelPacket)PacketPool.Instance.GetPacket(PacketType.TeleportCancel);
7998 tpCancel.Info.AgentID = tpReq.Info.AgentID; 8473 tpCancel.Info.AgentID = tpReq.Info.AgentID;
7999 tpCancel.Info.SessionID = tpReq.Info.SessionID; 8474 tpCancel.Info.SessionID = tpReq.Info.SessionID;
@@ -8003,6 +8478,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
8003 return true; 8478 return true;
8004 } 8479 }
8005 8480
8481 private AssetBase FindAssetInUserAssetServer(string id)
8482 {
8483 AgentCircuitData aCircuit = ((Scene)Scene).AuthenticateHandler.GetAgentCircuitData(CircuitCode);
8484 if (aCircuit != null && aCircuit.ServiceURLs != null && aCircuit.ServiceURLs.ContainsKey("AssetServerURI"))
8485 {
8486 string assetServer = aCircuit.ServiceURLs["AssetServerURI"].ToString();
8487 return ((Scene)Scene).AssetService.Get(assetServer + "/" + id);
8488 }
8489
8490 return null;
8491 }
8492
8006 private bool HandleTeleportLocationRequest(IClientAPI sender, Packet Pack) 8493 private bool HandleTeleportLocationRequest(IClientAPI sender, Packet Pack)
8007 { 8494 {
8008 TeleportLocationRequestPacket tpLocReq = (TeleportLocationRequestPacket)Pack; 8495 TeleportLocationRequestPacket tpLocReq = (TeleportLocationRequestPacket)Pack;
@@ -8129,7 +8616,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
8129 ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry(); 8616 ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry();
8130 entry.AgentID = block.ID; 8617 entry.AgentID = block.ID;
8131 entry.Flags = (AccessList)block.Flags; 8618 entry.Flags = (AccessList)block.Flags;
8132 entry.Time = new DateTime(); 8619 entry.Time = Util.ToDateTime(block.Time);
8133 entries.Add(entry); 8620 entries.Add(entry);
8134 } 8621 }
8135 8622
@@ -8137,8 +8624,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
8137 if (handlerParcelAccessListUpdateRequest != null) 8624 if (handlerParcelAccessListUpdateRequest != null)
8138 { 8625 {
8139 handlerParcelAccessListUpdateRequest(updatePacket.AgentData.AgentID, 8626 handlerParcelAccessListUpdateRequest(updatePacket.AgentData.AgentID,
8140 updatePacket.AgentData.SessionID, updatePacket.Data.Flags, 8627 updatePacket.Data.Flags,
8141 updatePacket.Data.LocalID, entries, this); 8628 updatePacket.Data.LocalID,
8629 updatePacket.Data.TransactionID,
8630 updatePacket.Data.SequenceID,
8631 updatePacket.Data.Sections,
8632 entries, this);
8142 } 8633 }
8143 return true; 8634 return true;
8144 } 8635 }
@@ -8649,13 +9140,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP
8649 case "instantmessage": 9140 case "instantmessage":
8650 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false)) 9141 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
8651 { 9142 {
8652 if (messagePacket.ParamList.Length < 5) 9143 if (messagePacket.ParamList.Length < 2)
8653 return true; 9144 return true;
9145
8654 UUID invoice = messagePacket.MethodData.Invoice; 9146 UUID invoice = messagePacket.MethodData.Invoice;
8655 UUID SenderID = new UUID(Utils.BytesToString(messagePacket.ParamList[2].Parameter));
8656 string SenderName = Utils.BytesToString(messagePacket.ParamList[3].Parameter);
8657 string Message = Utils.BytesToString(messagePacket.ParamList[4].Parameter);
8658 UUID sessionID = messagePacket.AgentData.SessionID; 9147 UUID sessionID = messagePacket.AgentData.SessionID;
9148
9149 UUID SenderID;
9150 string SenderName;
9151 string Message;
9152
9153 if (messagePacket.ParamList.Length < 5)
9154 {
9155 SenderID = AgentId;
9156 SenderName = Utils.BytesToString(messagePacket.ParamList[0].Parameter);
9157 Message = Utils.BytesToString(messagePacket.ParamList[1].Parameter);
9158 }
9159 else
9160 {
9161 SenderID = new UUID(Utils.BytesToString(messagePacket.ParamList[2].Parameter));
9162 SenderName = Utils.BytesToString(messagePacket.ParamList[3].Parameter);
9163 Message = Utils.BytesToString(messagePacket.ParamList[4].Parameter);
9164 }
9165
8659 OnEstateBlueBoxMessageRequest(this, invoice, SenderID, sessionID, SenderName, Message); 9166 OnEstateBlueBoxMessageRequest(this, invoice, SenderID, sessionID, SenderName, Message);
8660 } 9167 }
8661 return true; 9168 return true;
@@ -8777,7 +9284,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
8777 9284
8778// return true; 9285// return true;
8779 } 9286 }
8780 9287
8781 private bool HandleRequestRegionInfo(IClientAPI sender, Packet Pack) 9288 private bool HandleRequestRegionInfo(IClientAPI sender, Packet Pack)
8782 { 9289 {
8783 RequestRegionInfoPacket.AgentDataBlock mPacket = ((RequestRegionInfoPacket)Pack).AgentData; 9290 RequestRegionInfoPacket.AgentDataBlock mPacket = ((RequestRegionInfoPacket)Pack).AgentData;
@@ -8798,7 +9305,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
8798 } 9305 }
8799 return true; 9306 return true;
8800 } 9307 }
8801 9308
8802 private bool HandleEstateCovenantRequest(IClientAPI sender, Packet Pack) 9309 private bool HandleEstateCovenantRequest(IClientAPI sender, Packet Pack)
8803 { 9310 {
8804 9311
@@ -8835,7 +9342,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
8835 9342
8836 return true; 9343 return true;
8837 } 9344 }
8838 9345
8839 private bool HandleGodUpdateRegionInfoUpdate(IClientAPI client, Packet Packet) 9346 private bool HandleGodUpdateRegionInfoUpdate(IClientAPI client, Packet Packet)
8840 { 9347 {
8841 GodUpdateRegionInfoPacket GodUpdateRegionInfo = 9348 GodUpdateRegionInfoPacket GodUpdateRegionInfo =
@@ -8855,7 +9362,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
8855 } 9362 }
8856 return false; 9363 return false;
8857 } 9364 }
8858 9365
8859 private bool HandleSimWideDeletes(IClientAPI client, Packet Packet) 9366 private bool HandleSimWideDeletes(IClientAPI client, Packet Packet)
8860 { 9367 {
8861 SimWideDeletesPacket SimWideDeletesRequest = 9368 SimWideDeletesPacket SimWideDeletesRequest =
@@ -8868,7 +9375,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
8868 } 9375 }
8869 return false; 9376 return false;
8870 } 9377 }
8871 9378
8872 private bool HandleGodlikeMessage(IClientAPI client, Packet Packet) 9379 private bool HandleGodlikeMessage(IClientAPI client, Packet Packet)
8873 { 9380 {
8874 GodlikeMessagePacket GodlikeMessage = 9381 GodlikeMessagePacket GodlikeMessage =
@@ -8885,7 +9392,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
8885 } 9392 }
8886 return false; 9393 return false;
8887 } 9394 }
8888 9395
8889 private bool HandleSaveStatePacket(IClientAPI client, Packet Packet) 9396 private bool HandleSaveStatePacket(IClientAPI client, Packet Packet)
8890 { 9397 {
8891 StateSavePacket SaveStateMessage = 9398 StateSavePacket SaveStateMessage =
@@ -8898,7 +9405,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
8898 } 9405 }
8899 return false; 9406 return false;
8900 } 9407 }
8901 9408
8902 private bool HandleGodKickUser(IClientAPI sender, Packet Pack) 9409 private bool HandleGodKickUser(IClientAPI sender, Packet Pack)
8903 { 9410 {
8904 GodKickUserPacket gkupack = (GodKickUserPacket)Pack; 9411 GodKickUserPacket gkupack = (GodKickUserPacket)Pack;
@@ -8909,7 +9416,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
8909 if (handlerGodKickUser != null) 9416 if (handlerGodKickUser != null)
8910 { 9417 {
8911 handlerGodKickUser(gkupack.UserInfo.GodID, gkupack.UserInfo.GodSessionID, 9418 handlerGodKickUser(gkupack.UserInfo.GodID, gkupack.UserInfo.GodSessionID,
8912 gkupack.UserInfo.AgentID, (uint)0, gkupack.UserInfo.Reason); 9419 gkupack.UserInfo.AgentID, gkupack.UserInfo.KickFlags, gkupack.UserInfo.Reason);
8913 } 9420 }
8914 } 9421 }
8915 else 9422 else
@@ -9036,7 +9543,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9036 } 9543 }
9037 return true; 9544 return true;
9038 } 9545 }
9039 9546
9040 #endregion Economy/Transaction Packets 9547 #endregion Economy/Transaction Packets
9041 9548
9042 #region Script Packets 9549 #region Script Packets
@@ -9249,7 +9756,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9249 } 9756 }
9250 return true; 9757 return true;
9251 } 9758 }
9252 9759
9253 private bool HandleUpdateMuteListEntry(IClientAPI client, Packet Packet) 9760 private bool HandleUpdateMuteListEntry(IClientAPI client, Packet Packet)
9254 { 9761 {
9255 UpdateMuteListEntryPacket UpdateMuteListEntry = 9762 UpdateMuteListEntryPacket UpdateMuteListEntry =
@@ -9260,12 +9767,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9260 handlerUpdateMuteListEntry(this, UpdateMuteListEntry.MuteData.MuteID, 9767 handlerUpdateMuteListEntry(this, UpdateMuteListEntry.MuteData.MuteID,
9261 Utils.BytesToString(UpdateMuteListEntry.MuteData.MuteName), 9768 Utils.BytesToString(UpdateMuteListEntry.MuteData.MuteName),
9262 UpdateMuteListEntry.MuteData.MuteType, 9769 UpdateMuteListEntry.MuteData.MuteType,
9263 UpdateMuteListEntry.AgentData.AgentID); 9770 UpdateMuteListEntry.MuteData.MuteFlags);
9264 return true; 9771 return true;
9265 } 9772 }
9266 return false; 9773 return false;
9267 } 9774 }
9268 9775
9269 private bool HandleRemoveMuteListEntry(IClientAPI client, Packet Packet) 9776 private bool HandleRemoveMuteListEntry(IClientAPI client, Packet Packet)
9270 { 9777 {
9271 RemoveMuteListEntryPacket RemoveMuteListEntry = 9778 RemoveMuteListEntryPacket RemoveMuteListEntry =
@@ -9275,13 +9782,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9275 { 9782 {
9276 handlerRemoveMuteListEntry(this, 9783 handlerRemoveMuteListEntry(this,
9277 RemoveMuteListEntry.MuteData.MuteID, 9784 RemoveMuteListEntry.MuteData.MuteID,
9278 Utils.BytesToString(RemoveMuteListEntry.MuteData.MuteName), 9785 Utils.BytesToString(RemoveMuteListEntry.MuteData.MuteName));
9279 RemoveMuteListEntry.AgentData.AgentID);
9280 return true; 9786 return true;
9281 } 9787 }
9282 return false; 9788 return false;
9283 } 9789 }
9284 9790
9285 private bool HandleUserReport(IClientAPI client, Packet Packet) 9791 private bool HandleUserReport(IClientAPI client, Packet Packet)
9286 { 9792 {
9287 UserReportPacket UserReport = 9793 UserReportPacket UserReport =
@@ -9306,7 +9812,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9306 } 9812 }
9307 return false; 9813 return false;
9308 } 9814 }
9309 9815
9310 private bool HandleSendPostcard(IClientAPI client, Packet packet) 9816 private bool HandleSendPostcard(IClientAPI client, Packet packet)
9311 { 9817 {
9312// SendPostcardPacket SendPostcard = 9818// SendPostcardPacket SendPostcard =
@@ -9320,10 +9826,55 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9320 return false; 9826 return false;
9321 } 9827 }
9322 9828
9829 private bool HandleChangeInventoryItemFlags(IClientAPI client, Packet packet)
9830 {
9831 ChangeInventoryItemFlagsPacket ChangeInventoryItemFlags =
9832 (ChangeInventoryItemFlagsPacket)packet;
9833 ChangeInventoryItemFlags handlerChangeInventoryItemFlags = OnChangeInventoryItemFlags;
9834 if (handlerChangeInventoryItemFlags != null)
9835 {
9836 foreach(ChangeInventoryItemFlagsPacket.InventoryDataBlock b in ChangeInventoryItemFlags.InventoryData)
9837 handlerChangeInventoryItemFlags(this, b.ItemID, b.Flags);
9838 return true;
9839 }
9840 return false;
9841 }
9842
9323 private bool HandleUseCircuitCode(IClientAPI sender, Packet Pack) 9843 private bool HandleUseCircuitCode(IClientAPI sender, Packet Pack)
9324 { 9844 {
9325 return true; 9845 return true;
9326 } 9846 }
9847
9848 private bool HandleCreateNewOutfitAttachments(IClientAPI sender, Packet Pack)
9849 {
9850 CreateNewOutfitAttachmentsPacket packet = (CreateNewOutfitAttachmentsPacket)Pack;
9851
9852 #region Packet Session and User Check
9853 if (m_checkPackets)
9854 {
9855 if (packet.AgentData.SessionID != SessionId ||
9856 packet.AgentData.AgentID != AgentId)
9857 return true;
9858 }
9859 #endregion
9860 MoveItemsAndLeaveCopy handlerMoveItemsAndLeaveCopy = null;
9861 List<InventoryItemBase> items = new List<InventoryItemBase>();
9862 foreach (CreateNewOutfitAttachmentsPacket.ObjectDataBlock n in packet.ObjectData)
9863 {
9864 InventoryItemBase b = new InventoryItemBase();
9865 b.ID = n.OldItemID;
9866 b.Folder = n.OldFolderID;
9867 items.Add(b);
9868 }
9869
9870 handlerMoveItemsAndLeaveCopy = OnMoveItemsAndLeaveCopy;
9871 if (handlerMoveItemsAndLeaveCopy != null)
9872 {
9873 handlerMoveItemsAndLeaveCopy(this, items, packet.HeaderData.NewFolderID);
9874 }
9875
9876 return true;
9877 }
9327 9878
9328 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack) 9879 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack)
9329 { 9880 {
@@ -9588,7 +10139,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9588 return true; 10139 return true;
9589 10140
9590 } 10141 }
9591 10142
9592 private bool HandleGroupVoteHistoryRequest(IClientAPI client, Packet Packet) 10143 private bool HandleGroupVoteHistoryRequest(IClientAPI client, Packet Packet)
9593 { 10144 {
9594 GroupVoteHistoryRequestPacket GroupVoteHistoryRequest = 10145 GroupVoteHistoryRequestPacket GroupVoteHistoryRequest =
@@ -9601,7 +10152,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9601 } 10152 }
9602 return false; 10153 return false;
9603 } 10154 }
9604 10155
9605 private bool HandleGroupActiveProposalsRequest(IClientAPI client, Packet Packet) 10156 private bool HandleGroupActiveProposalsRequest(IClientAPI client, Packet Packet)
9606 { 10157 {
9607 GroupActiveProposalsRequestPacket GroupActiveProposalsRequest = 10158 GroupActiveProposalsRequestPacket GroupActiveProposalsRequest =
@@ -9614,7 +10165,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9614 } 10165 }
9615 return false; 10166 return false;
9616 } 10167 }
9617 10168
9618 private bool HandleGroupAccountDetailsRequest(IClientAPI client, Packet Packet) 10169 private bool HandleGroupAccountDetailsRequest(IClientAPI client, Packet Packet)
9619 { 10170 {
9620 GroupAccountDetailsRequestPacket GroupAccountDetailsRequest = 10171 GroupAccountDetailsRequestPacket GroupAccountDetailsRequest =
@@ -9627,7 +10178,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9627 } 10178 }
9628 return false; 10179 return false;
9629 } 10180 }
9630 10181
9631 private bool HandleGroupAccountSummaryRequest(IClientAPI client, Packet Packet) 10182 private bool HandleGroupAccountSummaryRequest(IClientAPI client, Packet Packet)
9632 { 10183 {
9633 GroupAccountSummaryRequestPacket GroupAccountSummaryRequest = 10184 GroupAccountSummaryRequestPacket GroupAccountSummaryRequest =
@@ -9640,7 +10191,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9640 } 10191 }
9641 return false; 10192 return false;
9642 } 10193 }
9643 10194
9644 private bool HandleGroupTransactionsDetailsRequest(IClientAPI client, Packet Packet) 10195 private bool HandleGroupTransactionsDetailsRequest(IClientAPI client, Packet Packet)
9645 { 10196 {
9646 GroupAccountTransactionsRequestPacket GroupAccountTransactionsRequest = 10197 GroupAccountTransactionsRequestPacket GroupAccountTransactionsRequest =
@@ -9653,7 +10204,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9653 } 10204 }
9654 return false; 10205 return false;
9655 } 10206 }
9656 10207
9657 private bool HandleGroupTitlesRequest(IClientAPI sender, Packet Pack) 10208 private bool HandleGroupTitlesRequest(IClientAPI sender, Packet Pack)
9658 { 10209 {
9659 GroupTitlesRequestPacket groupTitlesRequest = 10210 GroupTitlesRequestPacket groupTitlesRequest =
@@ -9750,6 +10301,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9750 groupProfileReply.GroupData.MaturePublish = d.MaturePublish; 10301 groupProfileReply.GroupData.MaturePublish = d.MaturePublish;
9751 groupProfileReply.GroupData.OwnerRole = d.OwnerRole; 10302 groupProfileReply.GroupData.OwnerRole = d.OwnerRole;
9752 10303
10304 Scene scene = (Scene)m_scene;
10305 if (scene.Permissions.IsGod(sender.AgentId) && (!sender.IsGroupMember(groupProfileRequest.GroupData.GroupID)))
10306 {
10307 ScenePresence p;
10308 if (scene.TryGetScenePresence(sender.AgentId, out p))
10309 {
10310 if (p.GodLevel >= 200)
10311 {
10312 groupProfileReply.GroupData.OpenEnrollment = true;
10313 groupProfileReply.GroupData.MembershipFee = 0;
10314 }
10315 }
10316 }
10317
9753 OutPacket(groupProfileReply, ThrottleOutPacketType.Task); 10318 OutPacket(groupProfileReply, ThrottleOutPacketType.Task);
9754 } 10319 }
9755 return true; 10320 return true;
@@ -10322,11 +10887,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10322 10887
10323 StartLure handlerStartLure = OnStartLure; 10888 StartLure handlerStartLure = OnStartLure;
10324 if (handlerStartLure != null) 10889 if (handlerStartLure != null)
10325 handlerStartLure(startLureRequest.Info.LureType, 10890 {
10326 Utils.BytesToString( 10891 for (int i = 0 ; i < startLureRequest.TargetData.Length ; i++)
10327 startLureRequest.Info.Message), 10892 {
10328 startLureRequest.TargetData[0].TargetID, 10893 handlerStartLure(startLureRequest.Info.LureType,
10329 this); 10894 Utils.BytesToString(
10895 startLureRequest.Info.Message),
10896 startLureRequest.TargetData[i].TargetID,
10897 this);
10898 }
10899 }
10330 return true; 10900 return true;
10331 } 10901 }
10332 private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack) 10902 private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack)
@@ -10440,10 +11010,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10440 } 11010 }
10441 #endregion 11011 #endregion
10442 11012
10443 ClassifiedDelete handlerClassifiedGodDelete = OnClassifiedGodDelete; 11013 ClassifiedGodDelete handlerClassifiedGodDelete = OnClassifiedGodDelete;
10444 if (handlerClassifiedGodDelete != null) 11014 if (handlerClassifiedGodDelete != null)
10445 handlerClassifiedGodDelete( 11015 handlerClassifiedGodDelete(
10446 classifiedGodDelete.Data.ClassifiedID, 11016 classifiedGodDelete.Data.ClassifiedID,
11017 classifiedGodDelete.Data.QueryID,
10447 this); 11018 this);
10448 return true; 11019 return true;
10449 } 11020 }
@@ -10644,6 +11215,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10644 Utils.BytesToString(avatarInterestUpdate.PropertiesData.LanguagesText)); 11215 Utils.BytesToString(avatarInterestUpdate.PropertiesData.LanguagesText));
10645 return true; 11216 return true;
10646 } 11217 }
11218
10647 private bool HandleGrantUserRights(IClientAPI sender, Packet Pack) 11219 private bool HandleGrantUserRights(IClientAPI sender, Packet Pack)
10648 { 11220 {
10649 GrantUserRightsPacket GrantUserRights = 11221 GrantUserRightsPacket GrantUserRights =
@@ -10664,6 +11236,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10664 GrantUserRights.Rights[0].RelatedRights); 11236 GrantUserRights.Rights[0].RelatedRights);
10665 return true; 11237 return true;
10666 } 11238 }
11239
10667 private bool HandlePlacesQuery(IClientAPI sender, Packet Pack) 11240 private bool HandlePlacesQuery(IClientAPI sender, Packet Pack)
10668 { 11241 {
10669 PlacesQueryPacket placesQueryPacket = 11242 PlacesQueryPacket placesQueryPacket =
@@ -10803,8 +11376,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10803 protected bool HandleMultipleObjUpdate(IClientAPI simClient, Packet packet) 11376 protected bool HandleMultipleObjUpdate(IClientAPI simClient, Packet packet)
10804 { 11377 {
10805 MultipleObjectUpdatePacket multipleupdate = (MultipleObjectUpdatePacket)packet; 11378 MultipleObjectUpdatePacket multipleupdate = (MultipleObjectUpdatePacket)packet;
10806 if (multipleupdate.AgentData.SessionID != SessionId) return false; 11379
10807 // m_log.Debug("new multi update packet " + multipleupdate.ToString()); 11380 if (multipleupdate.AgentData.SessionID != SessionId)
11381 return false;
11382
11383// m_log.DebugFormat(
11384// "[CLIENT]: Incoming MultipleObjectUpdatePacket contained {0} blocks", multipleupdate.ObjectData.Length);
11385
10808 Scene tScene = (Scene)m_scene; 11386 Scene tScene = (Scene)m_scene;
10809 11387
10810 for (int i = 0; i < multipleupdate.ObjectData.Length; i++) 11388 for (int i = 0; i < multipleupdate.ObjectData.Length; i++)
@@ -10821,11 +11399,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10821 { 11399 {
10822 // It's a ghost! tell the client to delete it from view. 11400 // It's a ghost! tell the client to delete it from view.
10823 simClient.SendKillObject(Scene.RegionInfo.RegionHandle, 11401 simClient.SendKillObject(Scene.RegionInfo.RegionHandle,
10824 localId); 11402 new List<uint> { localId });
10825 } 11403 }
10826 else 11404 else
10827 { 11405 {
10828 // UUID partId = part.UUID; 11406// m_log.DebugFormat(
11407// "[CLIENT]: Processing block {0} type {1} for {2} {3}",
11408// i, block.Type, part.Name, part.LocalId);
11409
11410// // Do this once since fetch parts creates a new array.
11411// SceneObjectPart[] parts = part.ParentGroup.Parts;
11412// for (int j = 0; j < parts.Length; j++)
11413// {
11414// part.StoreUndoState();
11415// parts[j].IgnoreUndoUpdate = true;
11416// }
11417
10829 UpdatePrimGroupRotation handlerUpdatePrimGroupRotation; 11418 UpdatePrimGroupRotation handlerUpdatePrimGroupRotation;
10830 11419
10831 switch (block.Type) 11420 switch (block.Type)
@@ -10840,6 +11429,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10840 handlerUpdatePrimSinglePosition(localId, pos1, this); 11429 handlerUpdatePrimSinglePosition(localId, pos1, this);
10841 } 11430 }
10842 break; 11431 break;
11432
10843 case 2: 11433 case 2:
10844 Quaternion rot1 = new Quaternion(block.Data, 0, true); 11434 Quaternion rot1 = new Quaternion(block.Data, 0, true);
10845 11435
@@ -10850,6 +11440,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10850 handlerUpdatePrimSingleRotation(localId, rot1, this); 11440 handlerUpdatePrimSingleRotation(localId, rot1, this);
10851 } 11441 }
10852 break; 11442 break;
11443
10853 case 3: 11444 case 3:
10854 Vector3 rotPos = new Vector3(block.Data, 0); 11445 Vector3 rotPos = new Vector3(block.Data, 0);
10855 Quaternion rot2 = new Quaternion(block.Data, 12, true); 11446 Quaternion rot2 = new Quaternion(block.Data, 12, true);
@@ -10862,6 +11453,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10862 handlerUpdatePrimSingleRotationPosition(localId, rot2, rotPos, this); 11453 handlerUpdatePrimSingleRotationPosition(localId, rot2, rotPos, this);
10863 } 11454 }
10864 break; 11455 break;
11456
10865 case 4: 11457 case 4:
10866 case 20: 11458 case 20:
10867 Vector3 scale4 = new Vector3(block.Data, 0); 11459 Vector3 scale4 = new Vector3(block.Data, 0);
@@ -10873,8 +11465,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10873 handlerUpdatePrimScale(localId, scale4, this); 11465 handlerUpdatePrimScale(localId, scale4, this);
10874 } 11466 }
10875 break; 11467 break;
10876 case 5:
10877 11468
11469 case 5:
10878 Vector3 scale1 = new Vector3(block.Data, 12); 11470 Vector3 scale1 = new Vector3(block.Data, 12);
10879 Vector3 pos11 = new Vector3(block.Data, 0); 11471 Vector3 pos11 = new Vector3(block.Data, 0);
10880 11472
@@ -10891,6 +11483,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10891 } 11483 }
10892 } 11484 }
10893 break; 11485 break;
11486
10894 case 9: 11487 case 9:
10895 Vector3 pos2 = new Vector3(block.Data, 0); 11488 Vector3 pos2 = new Vector3(block.Data, 0);
10896 11489
@@ -10898,10 +11491,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10898 11491
10899 if (handlerUpdateVector != null) 11492 if (handlerUpdateVector != null)
10900 { 11493 {
10901
10902 handlerUpdateVector(localId, pos2, this); 11494 handlerUpdateVector(localId, pos2, this);
10903 } 11495 }
10904 break; 11496 break;
11497
10905 case 10: 11498 case 10:
10906 Quaternion rot3 = new Quaternion(block.Data, 0, true); 11499 Quaternion rot3 = new Quaternion(block.Data, 0, true);
10907 11500
@@ -10912,6 +11505,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10912 handlerUpdatePrimRotation(localId, rot3, this); 11505 handlerUpdatePrimRotation(localId, rot3, this);
10913 } 11506 }
10914 break; 11507 break;
11508
10915 case 11: 11509 case 11:
10916 Vector3 pos3 = new Vector3(block.Data, 0); 11510 Vector3 pos3 = new Vector3(block.Data, 0);
10917 Quaternion rot4 = new Quaternion(block.Data, 12, true); 11511 Quaternion rot4 = new Quaternion(block.Data, 12, true);
@@ -10935,6 +11529,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10935 handlerUpdatePrimGroupScale(localId, scale7, this); 11529 handlerUpdatePrimGroupScale(localId, scale7, this);
10936 } 11530 }
10937 break; 11531 break;
11532
10938 case 13: 11533 case 13:
10939 Vector3 scale2 = new Vector3(block.Data, 12); 11534 Vector3 scale2 = new Vector3(block.Data, 12);
10940 Vector3 pos4 = new Vector3(block.Data, 0); 11535 Vector3 pos4 = new Vector3(block.Data, 0);
@@ -10954,6 +11549,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10954 } 11549 }
10955 } 11550 }
10956 break; 11551 break;
11552
10957 case 29: 11553 case 29:
10958 Vector3 scale5 = new Vector3(block.Data, 12); 11554 Vector3 scale5 = new Vector3(block.Data, 12);
10959 Vector3 pos5 = new Vector3(block.Data, 0); 11555 Vector3 pos5 = new Vector3(block.Data, 0);
@@ -10962,6 +11558,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10962 if (handlerUpdatePrimGroupScale != null) 11558 if (handlerUpdatePrimGroupScale != null)
10963 { 11559 {
10964 // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z); 11560 // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
11561 part.StoreUndoState(true);
11562 part.IgnoreUndoUpdate = true;
10965 handlerUpdatePrimGroupScale(localId, scale5, this); 11563 handlerUpdatePrimGroupScale(localId, scale5, this);
10966 handlerUpdateVector = OnUpdatePrimGroupPosition; 11564 handlerUpdateVector = OnUpdatePrimGroupPosition;
10967 11565
@@ -10969,8 +11567,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10969 { 11567 {
10970 handlerUpdateVector(localId, pos5, this); 11568 handlerUpdateVector(localId, pos5, this);
10971 } 11569 }
11570
11571 part.IgnoreUndoUpdate = false;
10972 } 11572 }
11573
10973 break; 11574 break;
11575
10974 case 21: 11576 case 21:
10975 Vector3 scale6 = new Vector3(block.Data, 12); 11577 Vector3 scale6 = new Vector3(block.Data, 12);
10976 Vector3 pos6 = new Vector3(block.Data, 0); 11578 Vector3 pos6 = new Vector3(block.Data, 0);
@@ -10978,6 +11580,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10978 handlerUpdatePrimScale = OnUpdatePrimScale; 11580 handlerUpdatePrimScale = OnUpdatePrimScale;
10979 if (handlerUpdatePrimScale != null) 11581 if (handlerUpdatePrimScale != null)
10980 { 11582 {
11583 part.StoreUndoState(false);
11584 part.IgnoreUndoUpdate = true;
11585
10981 // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z); 11586 // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
10982 handlerUpdatePrimScale(localId, scale6, this); 11587 handlerUpdatePrimScale(localId, scale6, this);
10983 handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 11588 handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition;
@@ -10985,15 +11590,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10985 { 11590 {
10986 handlerUpdatePrimSinglePosition(localId, pos6, this); 11591 handlerUpdatePrimSinglePosition(localId, pos6, this);
10987 } 11592 }
11593
11594 part.IgnoreUndoUpdate = false;
10988 } 11595 }
10989 break; 11596 break;
11597
10990 default: 11598 default:
10991 m_log.Debug("[CLIENT] MultipleObjUpdate recieved an unknown packet type: " + (block.Type)); 11599 m_log.Debug("[CLIENT]: MultipleObjUpdate recieved an unknown packet type: " + (block.Type));
10992 break; 11600 break;
10993 } 11601 }
11602
11603// for (int j = 0; j < parts.Length; j++)
11604// parts[j].IgnoreUndoUpdate = false;
10994 } 11605 }
10995 } 11606 }
10996 } 11607 }
11608
10997 return true; 11609 return true;
10998 } 11610 }
10999 11611
@@ -11063,7 +11675,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11063 /// <returns></returns> 11675 /// <returns></returns>
11064 public byte[] GetThrottlesPacked(float multiplier) 11676 public byte[] GetThrottlesPacked(float multiplier)
11065 { 11677 {
11066 return m_udpClient.GetThrottlesPacked(); 11678 return m_udpClient.GetThrottlesPacked(multiplier);
11067 } 11679 }
11068 11680
11069 /// <summary> 11681 /// <summary>
@@ -11098,10 +11710,50 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11098 /// handles splitting manually</param> 11710 /// handles splitting manually</param>
11099 protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting) 11711 protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting)
11100 { 11712 {
11101 if (m_debugPacketLevel >= 255) 11713 OutPacket(packet, throttlePacketType, doAutomaticSplitting, null);
11102 m_log.DebugFormat("[CLIENT]: Packet OUT {0}", packet.Type); 11714 }
11715
11716 /// <summary>
11717 /// This is the starting point for sending a simulator packet out to the client
11718 /// </summary>
11719 /// <param name="packet">Packet to send</param>
11720 /// <param name="throttlePacketType">Throttling category for the packet</param>
11721 /// <param name="doAutomaticSplitting">True to automatically split oversized
11722 /// packets (the default), or false to disable splitting if the calling code
11723 /// handles splitting manually</param>
11724 /// <param name="method">The method to be called in the event this packet is reliable
11725 /// and unacknowledged. The server will provide normal resend capability if you do not
11726 /// provide your own method.</param>
11727 protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting, UnackedPacketMethod method)
11728 {
11729 if (DebugPacketLevel > 0)
11730 {
11731 bool logPacket = true;
11732
11733 if (DebugPacketLevel <= 255
11734 && (packet.Type == PacketType.SimStats || packet.Type == PacketType.SimulatorViewerTimeMessage))
11735 logPacket = false;
11736
11737 if (DebugPacketLevel <= 200
11738 && (packet.Type == PacketType.ImagePacket
11739 || packet.Type == PacketType.ImageData
11740 || packet.Type == PacketType.LayerData
11741 || packet.Type == PacketType.CoarseLocationUpdate))
11742 logPacket = false;
11743
11744 if (DebugPacketLevel <= 100 && (packet.Type == PacketType.AvatarAnimation || packet.Type == PacketType.ViewerEffect))
11745 logPacket = false;
11746
11747 if (DebugPacketLevel <= 50 && packet.Type == PacketType.ImprovedTerseObjectUpdate)
11748 logPacket = false;
11749
11750 if (logPacket)
11751 m_log.DebugFormat(
11752 "[CLIENT]: PACKET OUT to {0} ({1}) in {2} - {3}",
11753 Name, ChildAgentStatus() ? "child" : "root ", m_scene.RegionInfo.RegionName, packet.Type);
11754 }
11103 11755
11104 m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting); 11756 m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting, method);
11105 } 11757 }
11106 11758
11107 public bool AddMoney(int debit) 11759 public bool AddMoney(int debit)
@@ -11115,70 +11767,53 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11115 return false; 11767 return false;
11116 } 11768 }
11117 11769
11118 /// <summary> 11770 protected void HandleAutopilot(Object sender, string method, List<String> args)
11119 /// Breaks down the genericMessagePacket into specific events
11120 /// </summary>
11121 /// <param name="gmMethod"></param>
11122 /// <param name="gmInvoice"></param>
11123 /// <param name="gmParams"></param>
11124 public void DecipherGenericMessage(string gmMethod, UUID gmInvoice, GenericMessagePacket.ParamListBlock[] gmParams)
11125 { 11771 {
11126 switch (gmMethod) 11772 float locx = 0;
11127 { 11773 float locy = 0;
11128 case "autopilot": 11774 float locz = 0;
11129 float locx; 11775 uint regionX = 0;
11130 float locy; 11776 uint regionY = 0;
11131 float locz;
11132 11777
11133 try 11778 Utils.LongToUInts(m_scene.RegionInfo.RegionHandle, out regionX, out regionY);
11134 { 11779 locx = Convert.ToSingle(args[0]) - (float)regionX;
11135 uint regionX; 11780 locy = Convert.ToSingle(args[1]) - (float)regionY;
11136 uint regionY; 11781 locz = Convert.ToSingle(args[2]);
11137 Utils.LongToUInts(Scene.RegionInfo.RegionHandle, out regionX, out regionY);
11138 locx = Convert.ToSingle(Utils.BytesToString(gmParams[0].Parameter)) - regionX;
11139 locy = Convert.ToSingle(Utils.BytesToString(gmParams[1].Parameter)) - regionY;
11140 locz = Convert.ToSingle(Utils.BytesToString(gmParams[2].Parameter));
11141 }
11142 catch (InvalidCastException)
11143 {
11144 m_log.Error("[CLIENT]: Invalid autopilot request");
11145 return;
11146 }
11147
11148 UpdateVector handlerAutoPilotGo = OnAutoPilotGo;
11149 if (handlerAutoPilotGo != null)
11150 {
11151 handlerAutoPilotGo(0, new Vector3(locx, locy, locz), this);
11152 }
11153 m_log.InfoFormat("[CLIENT]: Client Requests autopilot to position <{0},{1},{2}>", locx, locy, locz);
11154
11155
11156 break;
11157 default:
11158 m_log.Debug("[CLIENT]: Unknown Generic Message, Method: " + gmMethod + ". Invoice: " + gmInvoice + ". Dumping Params:");
11159 for (int hi = 0; hi < gmParams.Length; hi++)
11160 {
11161 Console.WriteLine(gmParams[hi].ToString());
11162 }
11163 //gmpack.MethodData.
11164 break;
11165 11782
11166 } 11783 Action<Vector3, bool, bool> handlerAutoPilotGo = OnAutoPilotGo;
11784 if (handlerAutoPilotGo != null)
11785 handlerAutoPilotGo(new Vector3(locx, locy, locz), false, false);
11167 } 11786 }
11168 11787
11169 /// <summary> 11788 /// <summary>
11170 /// Entryway from the client to the simulator. All UDP packets from the client will end up here 11789 /// Entryway from the client to the simulator. All UDP packets from the client will end up here
11171 /// </summary> 11790 /// </summary>
11172 /// <param name="Pack">OpenMetaverse.packet</param> 11791 /// <param name="Pack">OpenMetaverse.packet</param>
11173 public void ProcessInPacket(Packet Pack) 11792 public void ProcessInPacket(Packet packet)
11174 { 11793 {
11175 if (m_debugPacketLevel >= 255) 11794 if (DebugPacketLevel > 0)
11176 m_log.DebugFormat("[CLIENT]: Packet IN {0}", Pack.Type); 11795 {
11177 11796 bool logPacket = true;
11178 if (!ProcessPacketMethod(Pack))
11179 m_log.Warn("[CLIENT]: unhandled packet " + Pack.Type);
11180 11797
11181 PacketPool.Instance.ReturnPacket(Pack); 11798 if (DebugPacketLevel <= 255 && packet.Type == PacketType.AgentUpdate)
11799 logPacket = false;
11800
11801 if (DebugPacketLevel <= 200 && packet.Type == PacketType.RequestImage)
11802 logPacket = false;
11803
11804 if (DebugPacketLevel <= 100 && (packet.Type == PacketType.ViewerEffect || packet.Type == PacketType.AgentAnimation))
11805 logPacket = false;
11806
11807 if (logPacket)
11808 m_log.DebugFormat(
11809 "[CLIENT]: PACKET IN from {0} ({1}) in {2} - {3}",
11810 Name, ChildAgentStatus() ? "child" : "root ", m_scene.RegionInfo.RegionName, packet.Type);
11811 }
11812
11813 if (!ProcessPacketMethod(packet))
11814 m_log.Warn("[CLIENT]: unhandled packet " + packet.Type);
11815
11816 PacketPool.Instance.ReturnPacket(packet);
11182 } 11817 }
11183 11818
11184 private static PrimitiveBaseShape GetShapeFromAddPacket(ObjectAddPacket addPacket) 11819 private static PrimitiveBaseShape GetShapeFromAddPacket(ObjectAddPacket addPacket)
@@ -11218,7 +11853,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11218 11853
11219 info.userEP = m_userEndPoint; 11854 info.userEP = m_userEndPoint;
11220 info.proxyEP = null; 11855 info.proxyEP = null;
11221 info.agentcircuit = new sAgentCircuitData(RequestClientInfo()); 11856 info.agentcircuit = RequestClientInfo();
11222 11857
11223 return info; 11858 return info;
11224 } 11859 }
@@ -11396,81 +12031,60 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11396 return String.Empty; 12031 return String.Empty;
11397 } 12032 }
11398 12033
11399 public void MakeAssetRequest(TransferRequestPacket transferRequest, UUID taskID) 12034 /// <summary>
12035 /// Make an asset request to the asset service in response to a client request.
12036 /// </summary>
12037 /// <param name="transferRequest"></param>
12038 /// <param name="taskID"></param>
12039 protected void MakeAssetRequest(TransferRequestPacket transferRequest, UUID taskID)
11400 { 12040 {
11401 UUID requestID = UUID.Zero; 12041 UUID requestID = UUID.Zero;
11402 if (transferRequest.TransferInfo.SourceType == 2) 12042 if (transferRequest.TransferInfo.SourceType == (int)SourceType.Asset)
11403 { 12043 {
11404 //direct asset request
11405 requestID = new UUID(transferRequest.TransferInfo.Params, 0); 12044 requestID = new UUID(transferRequest.TransferInfo.Params, 0);
11406 } 12045 }
11407 else if (transferRequest.TransferInfo.SourceType == 3) 12046 else if (transferRequest.TransferInfo.SourceType == (int)SourceType.SimInventoryItem)
11408 { 12047 {
11409 //inventory asset request
11410 requestID = new UUID(transferRequest.TransferInfo.Params, 80); 12048 requestID = new UUID(transferRequest.TransferInfo.Params, 80);
11411 //m_log.Debug("[XXX] inventory asset request " + requestID);
11412 //if (taskID == UUID.Zero) // Agent
11413 // if (m_scene is HGScene)
11414 // {
11415 // m_log.Debug("[XXX] hg asset request " + requestID);
11416 // // We may need to fetch the asset from the user's asset server into the local asset server
11417 // HGAssetMapper mapper = ((HGScene)m_scene).AssetMapper;
11418 // mapper.Get(requestID, AgentId);
11419 // }
11420 } 12049 }
11421 12050
11422// m_log.DebugFormat("[CLIENT]: {0} requesting asset {1}", Name, requestID); 12051// m_log.DebugFormat("[CLIENT]: {0} requesting asset {1}", Name, requestID);
11423 12052
12053
12054 //Note, the bool returned from the below function is useless since it is always false.
11424 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived); 12055 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived);
11425 12056
11426 } 12057 }
11427 12058
12059 /// <summary>
12060 /// When we get a reply back from the asset service in response to a client request, send back the data.
12061 /// </summary>
12062 /// <param name="id"></param>
12063 /// <param name="sender"></param>
12064 /// <param name="asset"></param>
11428 protected void AssetReceived(string id, Object sender, AssetBase asset) 12065 protected void AssetReceived(string id, Object sender, AssetBase asset)
11429 { 12066 {
12067 if (asset == null)
12068 return;
12069
11430 TransferRequestPacket transferRequest = (TransferRequestPacket)sender; 12070 TransferRequestPacket transferRequest = (TransferRequestPacket)sender;
11431 12071
11432 UUID requestID = UUID.Zero; 12072 UUID requestID = UUID.Zero;
11433 byte source = 2; 12073 byte source = (byte)SourceType.Asset;
11434 if ((transferRequest.TransferInfo.SourceType == 2) || (transferRequest.TransferInfo.SourceType == 2222)) 12074
12075 if (transferRequest.TransferInfo.SourceType == (int)SourceType.Asset)
11435 { 12076 {
11436 //direct asset request
11437 requestID = new UUID(transferRequest.TransferInfo.Params, 0); 12077 requestID = new UUID(transferRequest.TransferInfo.Params, 0);
11438 } 12078 }
11439 else if ((transferRequest.TransferInfo.SourceType == 3) || (transferRequest.TransferInfo.SourceType == 3333)) 12079 else if (transferRequest.TransferInfo.SourceType == (int)SourceType.SimInventoryItem)
11440 { 12080 {
11441 //inventory asset request
11442 requestID = new UUID(transferRequest.TransferInfo.Params, 80); 12081 requestID = new UUID(transferRequest.TransferInfo.Params, 80);
11443 source = 3; 12082 source = (byte)SourceType.SimInventoryItem;
11444 //m_log.Debug("asset request " + requestID); 12083 //m_log.Debug("asset request " + requestID);
11445 } 12084 }
11446 12085
11447 if (null == asset)
11448 {
11449 if ((m_hyperAssets != null) && (transferRequest.TransferInfo.SourceType < 2000))
11450 {
11451 // Try the user's inventory, but only if it's different from the regions'
11452 string userAssets = m_hyperAssets.GetUserAssetServer(AgentId);
11453 if ((userAssets != string.Empty) && (userAssets != m_hyperAssets.GetSimAssetServer()))
11454 {
11455 m_log.DebugFormat("[CLIENT]: asset {0} not found in local asset storage. Trying user's storage.", id);
11456 if (transferRequest.TransferInfo.SourceType == 2)
11457 transferRequest.TransferInfo.SourceType = 2222; // marker
11458 else if (transferRequest.TransferInfo.SourceType == 3)
11459 transferRequest.TransferInfo.SourceType = 3333; // marker
11460
11461 m_assetService.Get(userAssets + "/" + id, transferRequest, AssetReceived);
11462 return;
11463 }
11464 }
11465
11466 //m_log.DebugFormat("[ASSET CACHE]: Asset transfer request for asset which is {0} already known to be missing. Dropping", requestID);
11467
11468 // FIXME: We never tell the client about assets which do not exist when requested by this transfer mechanism, which can't be right.
11469 return;
11470 }
11471
11472 // Scripts cannot be retrieved by direct request 12086 // Scripts cannot be retrieved by direct request
11473 if (transferRequest.TransferInfo.SourceType == 2 && asset.Type == 10) 12087 if (transferRequest.TransferInfo.SourceType == (int)SourceType.Asset && asset.Type == 10)
11474 return; 12088 return;
11475 12089
11476 // The asset is known to exist and is in our cache, so add it to the AssetRequests list 12090 // The asset is known to exist and is in our cache, so add it to the AssetRequests list
@@ -11496,6 +12110,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11496 const uint m_maxPacketSize = 600; 12110 const uint m_maxPacketSize = 600;
11497 int numPackets = 1; 12111 int numPackets = 1;
11498 12112
12113 if (data == null)
12114 return 0;
12115
11499 if (data.LongLength > m_maxPacketSize) 12116 if (data.LongLength > m_maxPacketSize)
11500 { 12117 {
11501 // over max number of bytes so split up file 12118 // over max number of bytes so split up file
@@ -11535,172 +12152,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11535 OutPacket(pack, ThrottleOutPacketType.Task); 12152 OutPacket(pack, ThrottleOutPacketType.Task);
11536 } 12153 }
11537 12154
11538 #region PriorityQueue
11539 public class PriorityQueue<TPriority, TValue>
11540 {
11541 internal delegate bool UpdatePriorityHandler(ref TPriority priority, uint local_id);
11542
11543 private MinHeap<MinHeapItem>[] m_heaps = new MinHeap<MinHeapItem>[1];
11544 private Dictionary<uint, LookupItem> m_lookupTable;
11545 private Comparison<TPriority> m_comparison;
11546 private object m_syncRoot = new object();
11547
11548 internal PriorityQueue() :
11549 this(MinHeap<MinHeapItem>.DEFAULT_CAPACITY, Comparer<TPriority>.Default) { }
11550 internal PriorityQueue(int capacity) :
11551 this(capacity, Comparer<TPriority>.Default) { }
11552 internal PriorityQueue(IComparer<TPriority> comparer) :
11553 this(new Comparison<TPriority>(comparer.Compare)) { }
11554 internal PriorityQueue(Comparison<TPriority> comparison) :
11555 this(MinHeap<MinHeapItem>.DEFAULT_CAPACITY, comparison) { }
11556 internal PriorityQueue(int capacity, IComparer<TPriority> comparer) :
11557 this(capacity, new Comparison<TPriority>(comparer.Compare)) { }
11558 internal PriorityQueue(int capacity, Comparison<TPriority> comparison)
11559 {
11560 m_lookupTable = new Dictionary<uint, LookupItem>(capacity);
11561
11562 for (int i = 0; i < m_heaps.Length; ++i)
11563 m_heaps[i] = new MinHeap<MinHeapItem>(capacity);
11564 this.m_comparison = comparison;
11565 }
11566
11567 public object SyncRoot { get { return this.m_syncRoot; } }
11568 internal int Count
11569 {
11570 get
11571 {
11572 int count = 0;
11573 for (int i = 0; i < m_heaps.Length; ++i)
11574 count = m_heaps[i].Count;
11575 return count;
11576 }
11577 }
11578
11579 public bool Enqueue(TPriority priority, TValue value, uint local_id)
11580 {
11581 LookupItem item;
11582
11583 if (m_lookupTable.TryGetValue(local_id, out item))
11584 {
11585 item.Heap[item.Handle] = new MinHeapItem(priority, value, local_id, this.m_comparison);
11586 return false;
11587 }
11588 else
11589 {
11590 item.Heap = m_heaps[0];
11591 item.Heap.Add(new MinHeapItem(priority, value, local_id, this.m_comparison), ref item.Handle);
11592 m_lookupTable.Add(local_id, item);
11593 return true;
11594 }
11595 }
11596
11597 internal TValue Peek()
11598 {
11599 for (int i = 0; i < m_heaps.Length; ++i)
11600 if (m_heaps[i].Count > 0)
11601 return m_heaps[i].Min().Value;
11602 throw new InvalidOperationException(string.Format("The {0} is empty", this.GetType().ToString()));
11603 }
11604
11605 internal TValue Dequeue()
11606 {
11607 for (int i = 0; i < m_heaps.Length; ++i)
11608 {
11609 if (m_heaps[i].Count > 0)
11610 {
11611 MinHeapItem item = m_heaps[i].RemoveMin();
11612 m_lookupTable.Remove(item.LocalID);
11613 return item.Value;
11614 }
11615 }
11616 throw new InvalidOperationException(string.Format("The {0} is empty", this.GetType().ToString()));
11617 }
11618
11619 internal void Reprioritize(UpdatePriorityHandler handler)
11620 {
11621 MinHeapItem item;
11622 TPriority priority;
11623
11624 foreach (LookupItem lookup in new List<LookupItem>(this.m_lookupTable.Values))
11625 {
11626 if (lookup.Heap.TryGetValue(lookup.Handle, out item))
11627 {
11628 priority = item.Priority;
11629 if (handler(ref priority, item.LocalID))
11630 {
11631 if (lookup.Heap.ContainsHandle(lookup.Handle))
11632 lookup.Heap[lookup.Handle] =
11633 new MinHeapItem(priority, item.Value, item.LocalID, this.m_comparison);
11634 }
11635 else
11636 {
11637 m_log.Warn("[LLCLIENTVIEW]: UpdatePriorityHandler returned false, dropping update");
11638 lookup.Heap.Remove(lookup.Handle);
11639 this.m_lookupTable.Remove(item.LocalID);
11640 }
11641 }
11642 }
11643 }
11644
11645 #region MinHeapItem
11646 private struct MinHeapItem : IComparable<MinHeapItem>
11647 {
11648 private TPriority priority;
11649 private TValue value;
11650 private uint local_id;
11651 private Comparison<TPriority> comparison;
11652
11653 internal MinHeapItem(TPriority priority, TValue value, uint local_id) :
11654 this(priority, value, local_id, Comparer<TPriority>.Default) { }
11655 internal MinHeapItem(TPriority priority, TValue value, uint local_id, IComparer<TPriority> comparer) :
11656 this(priority, value, local_id, new Comparison<TPriority>(comparer.Compare)) { }
11657 internal MinHeapItem(TPriority priority, TValue value, uint local_id, Comparison<TPriority> comparison)
11658 {
11659 this.priority = priority;
11660 this.value = value;
11661 this.local_id = local_id;
11662 this.comparison = comparison;
11663 }
11664
11665 internal TPriority Priority { get { return this.priority; } }
11666 internal TValue Value { get { return this.value; } }
11667 internal uint LocalID { get { return this.local_id; } }
11668
11669 public override string ToString()
11670 {
11671 StringBuilder sb = new StringBuilder();
11672 sb.Append("[");
11673 if (this.priority != null)
11674 sb.Append(this.priority.ToString());
11675 sb.Append(",");
11676 if (this.value != null)
11677 sb.Append(this.value.ToString());
11678 sb.Append("]");
11679 return sb.ToString();
11680 }
11681
11682 public int CompareTo(MinHeapItem other)
11683 {
11684 return this.comparison(this.priority, other.priority);
11685 }
11686 }
11687 #endregion
11688
11689 #region LookupItem
11690 private struct LookupItem
11691 {
11692 internal MinHeap<MinHeapItem> Heap;
11693 internal IHandle Handle;
11694 }
11695 #endregion
11696 }
11697
11698 public struct PacketProcessor 12155 public struct PacketProcessor
11699 { 12156 {
11700 public PacketMethod method; 12157 public PacketMethod method;
11701 public bool Async; 12158 public bool Async;
11702 } 12159 }
11703 12160
11704 public class AsyncPacketProcess 12161 public class AsyncPacketProcess
11705 { 12162 {
11706 public bool result = false; 12163 public bool result = false;
@@ -11715,8 +12172,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11715 } 12172 }
11716 } 12173 }
11717 12174
11718 #endregion
11719
11720 public static OSD BuildEvent(string eventName, OSD eventBody) 12175 public static OSD BuildEvent(string eventName, OSD eventBody)
11721 { 12176 {
11722 OSDMap osdEvent = new OSDMap(2); 12177 OSDMap osdEvent = new OSDMap(2);
@@ -11742,5 +12197,153 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11742 packet.PropertiesData.LanguagesText = Utils.StringToBytes(languages); 12197 packet.PropertiesData.LanguagesText = Utils.StringToBytes(languages);
11743 OutPacket(packet, ThrottleOutPacketType.Task); 12198 OutPacket(packet, ThrottleOutPacketType.Task);
11744 } 12199 }
12200
12201 public void SendChangeUserRights(UUID agentID, UUID friendID, int rights)
12202 {
12203 ChangeUserRightsPacket packet = (ChangeUserRightsPacket)PacketPool.Instance.GetPacket(PacketType.ChangeUserRights);
12204
12205 packet.AgentData = new ChangeUserRightsPacket.AgentDataBlock();
12206 packet.AgentData.AgentID = agentID;
12207
12208 packet.Rights = new ChangeUserRightsPacket.RightsBlock[1];
12209 packet.Rights[0] = new ChangeUserRightsPacket.RightsBlock();
12210 packet.Rights[0].AgentRelated = friendID;
12211 packet.Rights[0].RelatedRights = rights;
12212
12213 OutPacket(packet, ThrottleOutPacketType.Task);
12214 }
12215
12216 public void SendTextBoxRequest(string message, int chatChannel, string objectname, UUID ownerID, string ownerFirstName, string ownerLastName, UUID objectId)
12217 {
12218 ScriptDialogPacket dialog = (ScriptDialogPacket)PacketPool.Instance.GetPacket(PacketType.ScriptDialog);
12219 dialog.Data.ObjectID = objectId;
12220 dialog.Data.ChatChannel = chatChannel;
12221 dialog.Data.ImageID = UUID.Zero;
12222 dialog.Data.ObjectName = Util.StringToBytes256(objectname);
12223 // this is the username of the *owner*
12224 dialog.Data.FirstName = Util.StringToBytes256(ownerFirstName);
12225 dialog.Data.LastName = Util.StringToBytes256(ownerLastName);
12226 dialog.Data.Message = Util.StringToBytes256(message);
12227
12228 ScriptDialogPacket.ButtonsBlock[] buttons = new ScriptDialogPacket.ButtonsBlock[1];
12229 buttons[0] = new ScriptDialogPacket.ButtonsBlock();
12230 buttons[0].ButtonLabel = Util.StringToBytes256("!!llTextBox!!");
12231 dialog.Buttons = buttons;
12232
12233 dialog.OwnerData = new ScriptDialogPacket.OwnerDataBlock[1];
12234 dialog.OwnerData[0] = new ScriptDialogPacket.OwnerDataBlock();
12235 dialog.OwnerData[0].OwnerID = ownerID;
12236
12237 OutPacket(dialog, ThrottleOutPacketType.Task);
12238 }
12239
12240 public void StopFlying(ISceneEntity p)
12241 {
12242 if (p is ScenePresence)
12243 {
12244 ScenePresence presence = p as ScenePresence;
12245 // It turns out to get the agent to stop flying, you have to feed it stop flying velocities
12246 // There's no explicit message to send the client to tell it to stop flying.. it relies on the
12247 // velocity, collision plane and avatar height
12248
12249 // Add 1/6 the avatar's height to it's position so it doesn't shoot into the air
12250 // when the avatar stands up
12251
12252 Vector3 pos = presence.AbsolutePosition;
12253
12254 if (presence.Appearance.AvatarHeight != 127.0f)
12255 pos += new Vector3(0f, 0f, (presence.Appearance.AvatarHeight/6f));
12256 else
12257 pos += new Vector3(0f, 0f, (1.56f/6f));
12258
12259 presence.AbsolutePosition = pos;
12260
12261 // attach a suitable collision plane regardless of the actual situation to force the LLClient to land.
12262 // Collision plane below the avatar's position a 6th of the avatar's height is suitable.
12263 // Mind you, that this method doesn't get called if the avatar's velocity magnitude is greater then a
12264 // certain amount.. because the LLClient wouldn't land in that situation anyway.
12265
12266 // why are we still testing for this really old height value default???
12267 if (presence.Appearance.AvatarHeight != 127.0f)
12268 presence.CollisionPlane = new Vector4(0, 0, 0, pos.Z - presence.Appearance.AvatarHeight/6f);
12269 else
12270 presence.CollisionPlane = new Vector4(0, 0, 0, pos.Z - (1.56f/6f));
12271
12272
12273 ImprovedTerseObjectUpdatePacket.ObjectDataBlock block =
12274 CreateImprovedTerseBlock(p, false);
12275
12276 const float TIME_DILATION = 1.0f;
12277 ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f);
12278
12279
12280 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
12281 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
12282 packet.RegionData.TimeDilation = timeDilation;
12283 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1];
12284
12285 packet.ObjectData[0] = block;
12286
12287 OutPacket(packet, ThrottleOutPacketType.Task, true);
12288 }
12289
12290 //ControllingClient.SendAvatarTerseUpdate(new SendAvatarTerseData(m_rootRegionHandle, (ushort)(m_scene.TimeDilation * ushort.MaxValue), LocalId,
12291 // AbsolutePosition, Velocity, Vector3.Zero, m_bodyRot, new Vector4(0,0,1,AbsolutePosition.Z - 0.5f), m_uuid, null, GetUpdatePriority(ControllingClient)));
12292 }
12293
12294 public void SendPlacesReply(UUID queryID, UUID transactionID,
12295 PlacesReplyData[] data)
12296 {
12297 PlacesReplyPacket reply = null;
12298 PlacesReplyPacket.QueryDataBlock[] dataBlocks =
12299 new PlacesReplyPacket.QueryDataBlock[0];
12300
12301 for (int i = 0 ; i < data.Length ; i++)
12302 {
12303 PlacesReplyPacket.QueryDataBlock block =
12304 new PlacesReplyPacket.QueryDataBlock();
12305
12306 block.OwnerID = data[i].OwnerID;
12307 block.Name = Util.StringToBytes256(data[i].Name);
12308 block.Desc = Util.StringToBytes1024(data[i].Desc);
12309 block.ActualArea = data[i].ActualArea;
12310 block.BillableArea = data[i].BillableArea;
12311 block.Flags = data[i].Flags;
12312 block.GlobalX = data[i].GlobalX;
12313 block.GlobalY = data[i].GlobalY;
12314 block.GlobalZ = data[i].GlobalZ;
12315 block.SimName = Util.StringToBytes256(data[i].SimName);
12316 block.SnapshotID = data[i].SnapshotID;
12317 block.Dwell = data[i].Dwell;
12318 block.Price = data[i].Price;
12319
12320 if (reply != null && reply.Length + block.Length > 1400)
12321 {
12322 OutPacket(reply, ThrottleOutPacketType.Task);
12323
12324 reply = null;
12325 dataBlocks = new PlacesReplyPacket.QueryDataBlock[0];
12326 }
12327
12328 if (reply == null)
12329 {
12330 reply = (PlacesReplyPacket)PacketPool.Instance.GetPacket(PacketType.PlacesReply);
12331 reply.AgentData = new PlacesReplyPacket.AgentDataBlock();
12332 reply.AgentData.AgentID = AgentId;
12333 reply.AgentData.QueryID = queryID;
12334
12335 reply.TransactionData = new PlacesReplyPacket.TransactionDataBlock();
12336 reply.TransactionData.TransactionID = transactionID;
12337
12338 reply.QueryData = dataBlocks;
12339 }
12340
12341 Array.Resize(ref dataBlocks, dataBlocks.Length + 1);
12342 dataBlocks[dataBlocks.Length - 1] = block;
12343 reply.QueryData = dataBlocks;
12344 }
12345 if (reply != null)
12346 OutPacket(reply, ThrottleOutPacketType.Task);
12347 }
11745 } 12348 }
11746} \ No newline at end of file 12349}
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs
index 938cf50..9e0db12 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs
@@ -58,8 +58,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
58 private C5.IntervalHeap<J2KImage> m_priorityQueue = new C5.IntervalHeap<J2KImage>(10, new J2KImageComparer()); 58 private C5.IntervalHeap<J2KImage> m_priorityQueue = new C5.IntervalHeap<J2KImage>(10, new J2KImageComparer());
59 private object m_syncRoot = new object(); 59 private object m_syncRoot = new object();
60 60
61 private IHyperAssetService m_hyperAssets;
62
63 public LLClientView Client { get { return m_client; } } 61 public LLClientView Client { get { return m_client; } }
64 public AssetBase MissingImage { get { return m_missingImage; } } 62 public AssetBase MissingImage { get { return m_missingImage; } }
65 63
@@ -75,7 +73,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
75 m_log.Error("[ClientView] - Couldn't set missing image asset, falling back to missing image packet. This is known to crash the client"); 73 m_log.Error("[ClientView] - Couldn't set missing image asset, falling back to missing image packet. This is known to crash the client");
76 74
77 m_j2kDecodeModule = pJ2kDecodeModule; 75 m_j2kDecodeModule = pJ2kDecodeModule;
78 m_hyperAssets = client.Scene.RequestModuleInterface<IHyperAssetService>();
79 } 76 }
80 77
81 /// <summary> 78 /// <summary>
@@ -149,7 +146,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
149 imgrequest.J2KDecoder = m_j2kDecodeModule; 146 imgrequest.J2KDecoder = m_j2kDecodeModule;
150 imgrequest.AssetService = m_assetCache; 147 imgrequest.AssetService = m_assetCache;
151 imgrequest.AgentID = m_client.AgentId; 148 imgrequest.AgentID = m_client.AgentId;
152 imgrequest.HyperAssets = m_hyperAssets; 149 imgrequest.InventoryAccessModule = m_client.Scene.RequestModuleInterface<IInventoryAccessModule>();
153 imgrequest.DiscardLevel = newRequest.DiscardLevel; 150 imgrequest.DiscardLevel = newRequest.DiscardLevel;
154 imgrequest.StartPacket = Math.Max(1, newRequest.PacketNumber); 151 imgrequest.StartPacket = Math.Max(1, newRequest.PacketNumber);
155 imgrequest.Priority = newRequest.Priority; 152 imgrequest.Priority = newRequest.Priority;
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
index 55d9c9c..ae72175 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
@@ -122,6 +122,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
122 public int PacketsReceived; 122 public int PacketsReceived;
123 /// <summary>Number of packets sent to this client</summary> 123 /// <summary>Number of packets sent to this client</summary>
124 public int PacketsSent; 124 public int PacketsSent;
125 /// <summary>Number of packets resent to this client</summary>
126 public int PacketsResent;
125 /// <summary>Total byte count of unacked packets sent to this client</summary> 127 /// <summary>Total byte count of unacked packets sent to this client</summary>
126 public int UnackedBytes; 128 public int UnackedBytes;
127 129
@@ -133,7 +135,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
133 private int m_nextOnQueueEmpty = 1; 135 private int m_nextOnQueueEmpty = 1;
134 136
135 /// <summary>Throttle bucket for this agent's connection</summary> 137 /// <summary>Throttle bucket for this agent's connection</summary>
136 private readonly TokenBucket m_throttle; 138 private readonly AdaptiveTokenBucket m_throttleClient;
139 public AdaptiveTokenBucket FlowThrottle
140 {
141 get { return m_throttleClient; }
142 }
143
144 /// <summary>Throttle bucket for this agent's connection</summary>
145 private readonly TokenBucket m_throttleCategory;
137 /// <summary>Throttle buckets for each packet category</summary> 146 /// <summary>Throttle buckets for each packet category</summary>
138 private readonly TokenBucket[] m_throttleCategories; 147 private readonly TokenBucket[] m_throttleCategories;
139 /// <summary>Outgoing queues for throttled packets</summary> 148 /// <summary>Outgoing queues for throttled packets</summary>
@@ -144,8 +153,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
144 /// <summary>A reference to the LLUDPServer that is managing this client</summary> 153 /// <summary>A reference to the LLUDPServer that is managing this client</summary>
145 private readonly LLUDPServer m_udpServer; 154 private readonly LLUDPServer m_udpServer;
146 155
147 private int m_defaultRTO = 3000; 156 /// <summary>Caches packed throttle information</summary>
157 private byte[] m_packedThrottles;
158
159 private int m_defaultRTO = 1000; // 1sec is the recommendation in the RFC
148 private int m_maxRTO = 60000; 160 private int m_maxRTO = 60000;
161 public bool m_deliverPackets = true;
149 162
150 /// <summary> 163 /// <summary>
151 /// Default constructor 164 /// Default constructor
@@ -157,7 +170,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
157 /// <param name="circuitCode">Circuit code for this connection</param> 170 /// <param name="circuitCode">Circuit code for this connection</param>
158 /// <param name="agentID">AgentID for the connected agent</param> 171 /// <param name="agentID">AgentID for the connected agent</param>
159 /// <param name="remoteEndPoint">Remote endpoint for this connection</param> 172 /// <param name="remoteEndPoint">Remote endpoint for this connection</param>
160 public LLUDPClient(LLUDPServer server, ThrottleRates rates, TokenBucket parentThrottle, uint circuitCode, UUID agentID, IPEndPoint remoteEndPoint, int defaultRTO, int maxRTO) 173 /// <param name="defaultRTO">
174 /// Default retransmission timeout for unacked packets. The RTO will never drop
175 /// beyond this number.
176 /// </param>
177 /// <param name="maxRTO">
178 /// The maximum retransmission timeout for unacked packets. The RTO will never exceed this number.
179 /// </param>
180 public LLUDPClient(
181 LLUDPServer server, ThrottleRates rates, TokenBucket parentThrottle, uint circuitCode, UUID agentID,
182 IPEndPoint remoteEndPoint, int defaultRTO, int maxRTO)
161 { 183 {
162 AgentID = agentID; 184 AgentID = agentID;
163 RemoteEndPoint = remoteEndPoint; 185 RemoteEndPoint = remoteEndPoint;
@@ -169,7 +191,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
169 m_maxRTO = maxRTO; 191 m_maxRTO = maxRTO;
170 192
171 // Create a token bucket throttle for this client that has the scene token bucket as a parent 193 // Create a token bucket throttle for this client that has the scene token bucket as a parent
172 m_throttle = new TokenBucket(parentThrottle, rates.TotalLimit, rates.Total); 194 m_throttleClient = new AdaptiveTokenBucket(parentThrottle, rates.Total, rates.AdaptiveThrottlesEnabled);
195 // Create a token bucket throttle for the total categary with the client bucket as a throttle
196 m_throttleCategory = new TokenBucket(m_throttleClient, 0);
173 // Create an array of token buckets for this clients different throttle categories 197 // Create an array of token buckets for this clients different throttle categories
174 m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; 198 m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT];
175 199
@@ -180,10 +204,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
180 // Initialize the packet outboxes, where packets sit while they are waiting for tokens 204 // Initialize the packet outboxes, where packets sit while they are waiting for tokens
181 m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>(); 205 m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>();
182 // Initialize the token buckets that control the throttling for each category 206 // Initialize the token buckets that control the throttling for each category
183 m_throttleCategories[i] = new TokenBucket(m_throttle, rates.GetLimit(type), rates.GetRate(type)); 207 m_throttleCategories[i] = new TokenBucket(m_throttleCategory, rates.GetRate(type));
184 } 208 }
185 209
186 // Default the retransmission timeout to three seconds 210 // Default the retransmission timeout to one second
187 RTO = m_defaultRTO; 211 RTO = m_defaultRTO;
188 212
189 // Initialize this to a sane value to prevent early disconnects 213 // Initialize this to a sane value to prevent early disconnects
@@ -201,6 +225,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
201 m_packetOutboxes[i].Clear(); 225 m_packetOutboxes[i].Clear();
202 m_nextPackets[i] = null; 226 m_nextPackets[i] = null;
203 } 227 }
228
229 // pull the throttle out of the scene throttle
230 m_throttleClient.Parent.UnregisterRequest(m_throttleClient);
204 OnPacketStats = null; 231 OnPacketStats = null;
205 OnQueueEmpty = null; 232 OnQueueEmpty = null;
206 } 233 }
@@ -218,15 +245,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
218 info.pendingAcks = new Dictionary<uint, uint>(); 245 info.pendingAcks = new Dictionary<uint, uint>();
219 info.needAck = new Dictionary<uint, byte[]>(); 246 info.needAck = new Dictionary<uint, byte[]>();
220 247
221 info.resendThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate; 248 info.resendThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate;
222 info.landThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; 249 info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate;
223 info.windThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; 250 info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate;
224 info.cloudThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; 251 info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate;
225 info.taskThrottle = m_throttleCategories[(int)ThrottleOutPacketType.State].DripRate + m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; 252 info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate;
226 info.assetThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; 253 info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate;
227 info.textureThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; 254 info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate;
228 info.totalThrottle = info.resendThrottle + info.landThrottle + info.windThrottle + info.cloudThrottle + 255 info.totalThrottle = (int)m_throttleCategory.DripRate;
229 info.taskThrottle + info.assetThrottle + info.textureThrottle;
230 256
231 return info; 257 return info;
232 } 258 }
@@ -243,11 +269,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP
243 throw new NotImplementedException(); 269 throw new NotImplementedException();
244 } 270 }
245 271
272 /// <summary>
273 /// Return statistics information about client packet queues.
274 /// </summary>
275 /// <remarks>
276 /// FIXME: This should really be done in a more sensible manner rather than sending back a formatted string.
277 /// </remarks>
278 /// <returns></returns>
246 public string GetStats() 279 public string GetStats()
247 { 280 {
248 // TODO: ??? 281 return string.Format(
249 return string.Format("{0,7} {1,7} {2,7} {3,7} {4,7} {5,7} {6,7} {7,7} {8,7} {9,7}", 282 "{0,7} {1,7} {2,7} {3,9} {4,7} {5,7} {6,7} {7,7} {8,7} {9,8} {10,7} {11,7}",
250 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); 283 PacketsReceived,
284 PacketsSent,
285 PacketsResent,
286 UnackedBytes,
287 m_packetOutboxes[(int)ThrottleOutPacketType.Resend].Count,
288 m_packetOutboxes[(int)ThrottleOutPacketType.Land].Count,
289 m_packetOutboxes[(int)ThrottleOutPacketType.Wind].Count,
290 m_packetOutboxes[(int)ThrottleOutPacketType.Cloud].Count,
291 m_packetOutboxes[(int)ThrottleOutPacketType.Task].Count,
292 m_packetOutboxes[(int)ThrottleOutPacketType.Texture].Count,
293 m_packetOutboxes[(int)ThrottleOutPacketType.Asset].Count,
294 m_packetOutboxes[(int)ThrottleOutPacketType.State].Count);
251 } 295 }
252 296
253 public void SendPacketStats() 297 public void SendPacketStats()
@@ -294,8 +338,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
294 int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; 338 int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
295 int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); 339 int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
296 // State is a subcategory of task that we allocate a percentage to 340 // State is a subcategory of task that we allocate a percentage to
297 int state = (int)((float)task * STATE_TASK_PERCENTAGE); 341 int state = 0;
298 task -= state;
299 342
300 // Make sure none of the throttles are set below our packet MTU, 343 // Make sure none of the throttles are set below our packet MTU,
301 // otherwise a throttle could become permanently clogged 344 // otherwise a throttle could become permanently clogged
@@ -306,86 +349,124 @@ namespace OpenSim.Region.ClientStack.LindenUDP
306 task = Math.Max(task, LLUDPServer.MTU); 349 task = Math.Max(task, LLUDPServer.MTU);
307 texture = Math.Max(texture, LLUDPServer.MTU); 350 texture = Math.Max(texture, LLUDPServer.MTU);
308 asset = Math.Max(asset, LLUDPServer.MTU); 351 asset = Math.Max(asset, LLUDPServer.MTU);
309 state = Math.Max(state, LLUDPServer.MTU);
310
311 int total = resend + land + wind + cloud + task + texture + asset + state;
312 352
313 //m_log.DebugFormat("[LLUDPCLIENT]: {0} is setting throttles. Resend={1}, Land={2}, Wind={3}, Cloud={4}, Task={5}, Texture={6}, Asset={7}, State={8}, Total={9}", 353 //int total = resend + land + wind + cloud + task + texture + asset;
314 // AgentID, resend, land, wind, cloud, task, texture, asset, state, total); 354 //m_log.DebugFormat("[LLUDPCLIENT]: {0} is setting throttles. Resend={1}, Land={2}, Wind={3}, Cloud={4}, Task={5}, Texture={6}, Asset={7}, Total={8}",
355 // AgentID, resend, land, wind, cloud, task, texture, asset, total);
315 356
316 // Update the token buckets with new throttle values 357 // Update the token buckets with new throttle values
317 TokenBucket bucket; 358 TokenBucket bucket;
318 359
319 bucket = m_throttle;
320 bucket.MaxBurst = total;
321
322 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend]; 360 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend];
323 bucket.DripRate = resend; 361 bucket.RequestedDripRate = resend;
324 bucket.MaxBurst = resend;
325 362
326 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land]; 363 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land];
327 bucket.DripRate = land; 364 bucket.RequestedDripRate = land;
328 bucket.MaxBurst = land;
329 365
330 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind]; 366 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind];
331 bucket.DripRate = wind; 367 bucket.RequestedDripRate = wind;
332 bucket.MaxBurst = wind;
333 368
334 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud]; 369 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud];
335 bucket.DripRate = cloud; 370 bucket.RequestedDripRate = cloud;
336 bucket.MaxBurst = cloud;
337 371
338 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset]; 372 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset];
339 bucket.DripRate = asset; 373 bucket.RequestedDripRate = asset;
340 bucket.MaxBurst = asset;
341 374
342 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task]; 375 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task];
343 bucket.DripRate = task + state; 376 bucket.RequestedDripRate = task;
344 bucket.MaxBurst = task + state;
345 377
346 bucket = m_throttleCategories[(int)ThrottleOutPacketType.State]; 378 bucket = m_throttleCategories[(int)ThrottleOutPacketType.State];
347 bucket.DripRate = state; 379 bucket.RequestedDripRate = state;
348 bucket.MaxBurst = state;
349 380
350 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture]; 381 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture];
351 bucket.DripRate = texture; 382 bucket.RequestedDripRate = texture;
352 bucket.MaxBurst = texture; 383
384 // Reset the packed throttles cached data
385 m_packedThrottles = null;
353 } 386 }
354 387
355 public byte[] GetThrottlesPacked() 388 public byte[] GetThrottlesPacked(float multiplier)
356 { 389 {
357 byte[] data = new byte[7 * 4]; 390 byte[] data = m_packedThrottles;
358 int i = 0; 391
359 392 if (data == null)
360 Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate), 0, data, i, 4); i += 4; 393 {
361 Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate), 0, data, i, 4); i += 4; 394 float rate;
362 Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate), 0, data, i, 4); i += 4; 395
363 Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate), 0, data, i, 4); i += 4; 396 data = new byte[7 * 4];
364 Buffer.BlockCopy(Utils.FloatToBytes((float)(m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate) + 397 int i = 0;
365 m_throttleCategories[(int)ThrottleOutPacketType.State].DripRate), 0, data, i, 4); i += 4; 398
366 Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate), 0, data, i, 4); i += 4; 399 // multiply by 8 to convert bytes back to bits
367 Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate), 0, data, i, 4); i += 4; 400 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].RequestedDripRate * 8 * multiplier;
401 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
402
403 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Land].RequestedDripRate * 8 * multiplier;
404 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
405
406 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].RequestedDripRate * 8 * multiplier;
407 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
408
409 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].RequestedDripRate * 8 * multiplier;
410 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
411
412 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Task].RequestedDripRate * 8 * multiplier;
413 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
414
415 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].RequestedDripRate * 8 * multiplier;
416 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
417
418 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].RequestedDripRate * 8 * multiplier;
419 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
420
421 m_packedThrottles = data;
422 }
368 423
369 return data; 424 return data;
370 } 425 }
371 426
372 public bool EnqueueOutgoing(OutgoingPacket packet) 427 /// <summary>
428 /// Queue an outgoing packet if appropriate.
429 /// </summary>
430 /// <param name="packet"></param>
431 /// <param name="forceQueue">Always queue the packet if at all possible.</param>
432 /// <returns>
433 /// true if the packet has been queued,
434 /// false if the packet has not been queued and should be sent immediately.
435 /// </returns>
436 public bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue)
373 { 437 {
374 int category = (int)packet.Category; 438 int category = (int)packet.Category;
375 439
376 if (category >= 0 && category < m_packetOutboxes.Length) 440 if (category >= 0 && category < m_packetOutboxes.Length)
377 { 441 {
378 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category]; 442 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category];
443
444 if (m_deliverPackets == false)
445 {
446 queue.Enqueue(packet);
447 return true;
448 }
449
379 TokenBucket bucket = m_throttleCategories[category]; 450 TokenBucket bucket = m_throttleCategories[category];
380 451
381 if (bucket.RemoveTokens(packet.Buffer.DataLength)) 452 // Don't send this packet if there is already a packet waiting in the queue
453 // even if we have the tokens to send it, tokens should go to the already
454 // queued packets
455 if (queue.Count > 0)
456 {
457 queue.Enqueue(packet);
458 return true;
459 }
460
461
462 if (!forceQueue && bucket.RemoveTokens(packet.Buffer.DataLength))
382 { 463 {
383 // Enough tokens were removed from the bucket, the packet will not be queued 464 // Enough tokens were removed from the bucket, the packet will not be queued
384 return false; 465 return false;
385 } 466 }
386 else 467 else
387 { 468 {
388 // Not enough tokens in the bucket, queue this packet 469 // Force queue specified or not enough tokens in the bucket, queue this packet
389 queue.Enqueue(packet); 470 queue.Enqueue(packet);
390 return true; 471 return true;
391 } 472 }
@@ -399,14 +480,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
399 480
400 /// <summary> 481 /// <summary>
401 /// Loops through all of the packet queues for this client and tries to send 482 /// Loops through all of the packet queues for this client and tries to send
402 /// any outgoing packets, obeying the throttling bucket limits 483 /// an outgoing packet from each, obeying the throttling bucket limits
403 /// </summary> 484 /// </summary>
404 /// <remarks>This function is only called from a synchronous loop in the 485 ///
405 /// UDPServer so we don't need to bother making this thread safe</remarks> 486 /// <remarks>
487 /// Packet queues are inspected in ascending numerical order starting from 0. Therefore, queues with a lower
488 /// ThrottleOutPacketType number will see their packet get sent first (e.g. if both Land and Wind queues have
489 /// packets, then the packet at the front of the Land queue will be sent before the packet at the front of the
490 /// wind queue).
491 ///
492 /// This function is only called from a synchronous loop in the
493 /// UDPServer so we don't need to bother making this thread safe
494 /// </remarks>
495 ///
406 /// <returns>True if any packets were sent, otherwise false</returns> 496 /// <returns>True if any packets were sent, otherwise false</returns>
407 public bool DequeueOutgoing() 497 public bool DequeueOutgoing()
408 { 498 {
409 OutgoingPacket packet; 499 if (m_deliverPackets == false) return false;
500
501 OutgoingPacket packet = null;
410 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue; 502 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue;
411 TokenBucket bucket; 503 TokenBucket bucket;
412 bool packetSent = false; 504 bool packetSent = false;
@@ -431,7 +523,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
431 m_udpServer.SendPacketFinal(nextPacket); 523 m_udpServer.SendPacketFinal(nextPacket);
432 m_nextPackets[i] = null; 524 m_nextPackets[i] = null;
433 packetSent = true; 525 packetSent = true;
434 this.PacketsSent++;
435 } 526 }
436 } 527 }
437 else 528 else
@@ -439,33 +530,49 @@ namespace OpenSim.Region.ClientStack.LindenUDP
439 // No dequeued packet waiting to be sent, try to pull one off 530 // No dequeued packet waiting to be sent, try to pull one off
440 // this queue 531 // this queue
441 queue = m_packetOutboxes[i]; 532 queue = m_packetOutboxes[i];
442 if (queue.Dequeue(out packet)) 533 if (queue != null)
443 { 534 {
444 // A packet was pulled off the queue. See if we have 535 bool success = false;
445 // enough tokens in the bucket to send it out 536 try
446 if (bucket.RemoveTokens(packet.Buffer.DataLength))
447 { 537 {
448 // Send the packet 538 success = queue.Dequeue(out packet);
449 m_udpServer.SendPacketFinal(packet);
450 packetSent = true;
451 this.PacketsSent++;
452 } 539 }
453 else 540 catch
454 { 541 {
455 // Save the dequeued packet for the next iteration 542 m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>();
456 m_nextPackets[i] = packet;
457 } 543 }
458 544 if (success)
459 // If the queue is empty after this dequeue, fire the queue 545 {
460 // empty callback now so it has a chance to fill before we 546 // A packet was pulled off the queue. See if we have
461 // get back here 547 // enough tokens in the bucket to send it out
462 if (queue.Count == 0) 548 if (bucket.RemoveTokens(packet.Buffer.DataLength))
549 {
550 // Send the packet
551 m_udpServer.SendPacketFinal(packet);
552 packetSent = true;
553 }
554 else
555 {
556 // Save the dequeued packet for the next iteration
557 m_nextPackets[i] = packet;
558 }
559
560 // If the queue is empty after this dequeue, fire the queue
561 // empty callback now so it has a chance to fill before we
562 // get back here
563 if (queue.Count == 0)
564 emptyCategories |= CategoryToFlag(i);
565 }
566 else
567 {
568 // No packets in this queue. Fire the queue empty callback
569 // if it has not been called recently
463 emptyCategories |= CategoryToFlag(i); 570 emptyCategories |= CategoryToFlag(i);
571 }
464 } 572 }
465 else 573 else
466 { 574 {
467 // No packets in this queue. Fire the queue empty callback 575 m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>();
468 // if it has not been called recently
469 emptyCategories |= CategoryToFlag(i); 576 emptyCategories |= CategoryToFlag(i);
470 } 577 }
471 } 578 }
@@ -508,12 +615,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
508 int rto = (int)(SRTT + Math.Max(m_udpServer.TickCountResolution, K * RTTVAR)); 615 int rto = (int)(SRTT + Math.Max(m_udpServer.TickCountResolution, K * RTTVAR));
509 616
510 // Clamp the retransmission timeout to manageable values 617 // Clamp the retransmission timeout to manageable values
511 rto = Utils.Clamp(RTO, m_defaultRTO, m_maxRTO); 618 rto = Utils.Clamp(rto, m_defaultRTO, m_maxRTO);
512 619
513 RTO = rto; 620 RTO = rto;
514 621
515 //m_log.Debug("[LLUDPCLIENT]: Setting agent " + this.Agent.FullName + "'s RTO to " + RTO + "ms with an RTTVAR of " + 622 //if (RTO != rto)
516 // RTTVAR + " based on new RTT of " + r + "ms"); 623 // m_log.Debug("[LLUDPCLIENT]: Setting RTO to " + RTO + "ms from " + rto + "ms with an RTTVAR of " +
624 //RTTVAR + " based on new RTT of " + r + "ms");
517 } 625 }
518 626
519 /// <summary> 627 /// <summary>
@@ -535,8 +643,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
535 /// Does an early check to see if this queue empty callback is already 643 /// Does an early check to see if this queue empty callback is already
536 /// running, then asynchronously firing the event 644 /// running, then asynchronously firing the event
537 /// </summary> 645 /// </summary>
538 /// <param name="throttleIndex">Throttle category to fire the callback 646 /// <param name="categories">Throttle categories to fire the callback for</param>
539 /// for</param>
540 private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories) 647 private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories)
541 { 648 {
542 if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty) 649 if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty)
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
index 5ed4cd7..bf5b85a 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -27,6 +27,7 @@
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Diagnostics;
30using System.IO; 31using System.IO;
31using System.Net; 32using System.Net;
32using System.Net.Sockets; 33using System.Net.Sockets;
@@ -99,15 +100,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
99 100
100 /// <summary>The measured resolution of Environment.TickCount</summary> 101 /// <summary>The measured resolution of Environment.TickCount</summary>
101 public readonly float TickCountResolution; 102 public readonly float TickCountResolution;
102 /// <summary>Number of terse prim updates to put on the queue each time the 103 /// <summary>Number of prim updates to put on the queue each time the
103 /// OnQueueEmpty event is triggered for updates</summary> 104 /// OnQueueEmpty event is triggered for updates</summary>
104 public readonly int PrimTerseUpdatesPerPacket; 105 public readonly int PrimUpdatesPerCallback;
105 /// <summary>Number of terse avatar updates to put on the queue each time the
106 /// OnQueueEmpty event is triggered for updates</summary>
107 public readonly int AvatarTerseUpdatesPerPacket;
108 /// <summary>Number of full prim updates to put on the queue each time the
109 /// OnQueueEmpty event is triggered for updates</summary>
110 public readonly int PrimFullUpdatesPerPacket;
111 /// <summary>Number of texture packets to put on the queue each time the 106 /// <summary>Number of texture packets to put on the queue each time the
112 /// OnQueueEmpty event is triggered for textures</summary> 107 /// OnQueueEmpty event is triggered for textures</summary>
113 public readonly int TextureSendLimit; 108 public readonly int TextureSendLimit;
@@ -120,8 +115,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
120 //private UDPClientCollection m_clients = new UDPClientCollection(); 115 //private UDPClientCollection m_clients = new UDPClientCollection();
121 /// <summary>Bandwidth throttle for this UDP server</summary> 116 /// <summary>Bandwidth throttle for this UDP server</summary>
122 protected TokenBucket m_throttle; 117 protected TokenBucket m_throttle;
118
123 /// <summary>Bandwidth throttle rates for this UDP server</summary> 119 /// <summary>Bandwidth throttle rates for this UDP server</summary>
124 protected ThrottleRates m_throttleRates; 120 public ThrottleRates ThrottleRates { get; private set; }
121
125 /// <summary>Manages authentication for agent circuits</summary> 122 /// <summary>Manages authentication for agent circuits</summary>
126 private AgentCircuitManager m_circuitManager; 123 private AgentCircuitManager m_circuitManager;
127 /// <summary>Reference to the scene this UDP server is attached to</summary> 124 /// <summary>Reference to the scene this UDP server is attached to</summary>
@@ -159,8 +156,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
159 private int m_defaultRTO = 0; 156 private int m_defaultRTO = 0;
160 private int m_maxRTO = 0; 157 private int m_maxRTO = 0;
161 158
159 private bool m_disableFacelights = false;
160
162 public Socket Server { get { return null; } } 161 public Socket Server { get { return null; } }
163 162
163 private int m_malformedCount = 0; // Guard against a spamming attack
164
164 public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) 165 public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager)
165 : base(listenIP, (int)port) 166 : base(listenIP, (int)port)
166 { 167 {
@@ -187,23 +188,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
187 IConfig config = configSource.Configs["ClientStack.LindenUDP"]; 188 IConfig config = configSource.Configs["ClientStack.LindenUDP"];
188 if (config != null) 189 if (config != null)
189 { 190 {
190 m_asyncPacketHandling = config.GetBoolean("async_packet_handling", false); 191 m_asyncPacketHandling = config.GetBoolean("async_packet_handling", true);
191 m_recvBufferSize = config.GetInt("client_socket_rcvbuf_size", 0); 192 m_recvBufferSize = config.GetInt("client_socket_rcvbuf_size", 0);
192 sceneThrottleBps = config.GetInt("scene_throttle_max_bps", 0); 193 sceneThrottleBps = config.GetInt("scene_throttle_max_bps", 0);
193 194
194 PrimTerseUpdatesPerPacket = config.GetInt("PrimTerseUpdatesPerPacket", 25); 195 PrimUpdatesPerCallback = config.GetInt("PrimUpdatesPerCallback", 100);
195 AvatarTerseUpdatesPerPacket = config.GetInt("AvatarTerseUpdatesPerPacket", 10);
196 PrimFullUpdatesPerPacket = config.GetInt("PrimFullUpdatesPerPacket", 100);
197 TextureSendLimit = config.GetInt("TextureSendLimit", 20); 196 TextureSendLimit = config.GetInt("TextureSendLimit", 20);
198 197
199 m_defaultRTO = config.GetInt("DefaultRTO", 0); 198 m_defaultRTO = config.GetInt("DefaultRTO", 0);
200 m_maxRTO = config.GetInt("MaxRTO", 0); 199 m_maxRTO = config.GetInt("MaxRTO", 0);
200 m_disableFacelights = config.GetBoolean("DisableFacelights", false);
201 } 201 }
202 else 202 else
203 { 203 {
204 PrimTerseUpdatesPerPacket = 25; 204 PrimUpdatesPerCallback = 100;
205 AvatarTerseUpdatesPerPacket = 10;
206 PrimFullUpdatesPerPacket = 100;
207 TextureSendLimit = 20; 205 TextureSendLimit = 20;
208 } 206 }
209 207
@@ -232,8 +230,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
232 } 230 }
233 #endregion BinaryStats 231 #endregion BinaryStats
234 232
235 m_throttle = new TokenBucket(null, sceneThrottleBps, sceneThrottleBps); 233 m_throttle = new TokenBucket(null, sceneThrottleBps);
236 m_throttleRates = new ThrottleRates(configSource); 234 ThrottleRates = new ThrottleRates(configSource);
237 } 235 }
238 236
239 public void Start() 237 public void Start()
@@ -301,7 +299,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
301 delegate(IClientAPI client) 299 delegate(IClientAPI client)
302 { 300 {
303 if (client is LLClientView) 301 if (client is LLClientView)
304 SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category); 302 SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null);
305 } 303 }
306 ); 304 );
307 } 305 }
@@ -313,13 +311,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
313 delegate(IClientAPI client) 311 delegate(IClientAPI client)
314 { 312 {
315 if (client is LLClientView) 313 if (client is LLClientView)
316 SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category); 314 SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null);
317 } 315 }
318 ); 316 );
319 } 317 }
320 } 318 }
321 319
322 public void SendPacket(LLUDPClient udpClient, Packet packet, ThrottleOutPacketType category, bool allowSplitting) 320 /// <summary>
321 /// Start the process of sending a packet to the client.
322 /// </summary>
323 /// <param name="udpClient"></param>
324 /// <param name="packet"></param>
325 /// <param name="category"></param>
326 /// <param name="allowSplitting"></param>
327 /// <param name="method">
328 /// The method to call if the packet is not acked by the client. If null, then a standard
329 /// resend of the packet is done.
330 /// </param>
331 public virtual void SendPacket(
332 LLUDPClient udpClient, Packet packet, ThrottleOutPacketType category, bool allowSplitting, UnackedPacketMethod method)
323 { 333 {
324 // CoarseLocationUpdate packets cannot be split in an automated way 334 // CoarseLocationUpdate packets cannot be split in an automated way
325 if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting) 335 if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting)
@@ -336,17 +346,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP
336 for (int i = 0; i < packetCount; i++) 346 for (int i = 0; i < packetCount; i++)
337 { 347 {
338 byte[] data = datas[i]; 348 byte[] data = datas[i];
339 SendPacketData(udpClient, data, packet.Type, category); 349 SendPacketData(udpClient, data, packet.Type, category, method);
340 } 350 }
341 } 351 }
342 else 352 else
343 { 353 {
344 byte[] data = packet.ToBytes(); 354 byte[] data = packet.ToBytes();
345 SendPacketData(udpClient, data, packet.Type, category); 355 SendPacketData(udpClient, data, packet.Type, category, method);
346 } 356 }
347 } 357 }
348 358
349 public void SendPacketData(LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category) 359 /// <summary>
360 /// Start the process of sending a packet to the client.
361 /// </summary>
362 /// <param name="udpClient"></param>
363 /// <param name="data"></param>
364 /// <param name="type"></param>
365 /// <param name="category"></param>
366 /// <param name="method">
367 /// The method to call if the packet is not acked by the client. If null, then a standard
368 /// resend of the packet is done.
369 /// </param>
370 public void SendPacketData(
371 LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category, UnackedPacketMethod method)
350 { 372 {
351 int dataLength = data.Length; 373 int dataLength = data.Length;
352 bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0; 374 bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0;
@@ -401,9 +423,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
401 423
402 #region Queue or Send 424 #region Queue or Send
403 425
404 OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category); 426 OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null);
427 // If we were not provided a method for handling unacked, use the UDPServer default method
428 outgoingPacket.UnackedMethod = ((method == null) ? delegate(OutgoingPacket oPacket) { ResendUnacked(oPacket); } : method);
405 429
406 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) 430 // If a Linden Lab 1.23.5 client receives an update packet after a kill packet for an object, it will
431 // continue to display the deleted object until relog. Therefore, we need to always queue a kill object
432 // packet so that it isn't sent before a queued update packet.
433 bool requestQueue = type == PacketType.KillObject;
434 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue))
407 SendPacketFinal(outgoingPacket); 435 SendPacketFinal(outgoingPacket);
408 436
409 #endregion Queue or Send 437 #endregion Queue or Send
@@ -431,7 +459,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
431 packet.Header.Reliable = false; 459 packet.Header.Reliable = false;
432 packet.Packets = blocks.ToArray(); 460 packet.Packets = blocks.ToArray();
433 461
434 SendPacket(udpClient, packet, ThrottleOutPacketType.Unknown, true); 462 SendPacket(udpClient, packet, ThrottleOutPacketType.Unknown, true, null);
435 } 463 }
436 } 464 }
437 465
@@ -444,17 +472,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
444 // We *could* get OldestUnacked, but it would hurt performance and not provide any benefit 472 // We *could* get OldestUnacked, but it would hurt performance and not provide any benefit
445 pc.PingID.OldestUnacked = 0; 473 pc.PingID.OldestUnacked = 0;
446 474
447 SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false); 475 SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false, null);
448 } 476 }
449 477
450 public void CompletePing(LLUDPClient udpClient, byte pingID) 478 public void CompletePing(LLUDPClient udpClient, byte pingID)
451 { 479 {
452 CompletePingCheckPacket completePing = new CompletePingCheckPacket(); 480 CompletePingCheckPacket completePing = new CompletePingCheckPacket();
453 completePing.PingID.PingID = pingID; 481 completePing.PingID.PingID = pingID;
454 SendPacket(udpClient, completePing, ThrottleOutPacketType.Unknown, false); 482 SendPacket(udpClient, completePing, ThrottleOutPacketType.Unknown, false, null);
455 } 483 }
456 484
457 public void ResendUnacked(LLUDPClient udpClient) 485 public void HandleUnacked(LLUDPClient udpClient)
458 { 486 {
459 if (!udpClient.IsConnected) 487 if (!udpClient.IsConnected)
460 return; 488 return;
@@ -474,32 +502,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP
474 502
475 if (expiredPackets != null) 503 if (expiredPackets != null)
476 { 504 {
477 //m_log.Debug("[LLUDPSERVER]: Resending " + expiredPackets.Count + " packets to " + udpClient.AgentID + ", RTO=" + udpClient.RTO); 505 //m_log.Debug("[LLUDPSERVER]: Handling " + expiredPackets.Count + " packets to " + udpClient.AgentID + ", RTO=" + udpClient.RTO);
478
479 // Exponential backoff of the retransmission timeout 506 // Exponential backoff of the retransmission timeout
480 udpClient.BackoffRTO(); 507 udpClient.BackoffRTO();
508 for (int i = 0; i < expiredPackets.Count; ++i)
509 expiredPackets[i].UnackedMethod(expiredPackets[i]);
510 }
511 }
481 512
482 // Resend packets 513 public void ResendUnacked(OutgoingPacket outgoingPacket)
483 for (int i = 0; i < expiredPackets.Count; i++) 514 {
484 { 515 //m_log.DebugFormat("[LLUDPSERVER]: Resending packet #{0} (attempt {1}), {2}ms have passed",
485 OutgoingPacket outgoingPacket = expiredPackets[i]; 516 // outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount);
486
487 //m_log.DebugFormat("[LLUDPSERVER]: Resending packet #{0} (attempt {1}), {2}ms have passed",
488 // outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount);
489 517
490 // Set the resent flag 518 // Set the resent flag
491 outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT); 519 outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT);
492 outgoingPacket.Category = ThrottleOutPacketType.Resend; 520 outgoingPacket.Category = ThrottleOutPacketType.Resend;
493 521
494 // Bump up the resend count on this packet 522 // Bump up the resend count on this packet
495 Interlocked.Increment(ref outgoingPacket.ResendCount); 523 Interlocked.Increment(ref outgoingPacket.ResendCount);
496 //Interlocked.Increment(ref Stats.ResentPackets);
497 524
498 // Requeue or resend the packet 525 // Requeue or resend the packet
499 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) 526 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, false))
500 SendPacketFinal(outgoingPacket); 527 SendPacketFinal(outgoingPacket);
501 }
502 }
503 } 528 }
504 529
505 public void Flush(LLUDPClient udpClient) 530 public void Flush(LLUDPClient udpClient)
@@ -507,6 +532,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
507 // FIXME: Implement? 532 // FIXME: Implement?
508 } 533 }
509 534
535 /// <summary>
536 /// Actually send a packet to a client.
537 /// </summary>
538 /// <param name="outgoingPacket"></param>
510 internal void SendPacketFinal(OutgoingPacket outgoingPacket) 539 internal void SendPacketFinal(OutgoingPacket outgoingPacket)
511 { 540 {
512 UDPPacketBuffer buffer = outgoingPacket.Buffer; 541 UDPPacketBuffer buffer = outgoingPacket.Buffer;
@@ -565,13 +594,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
565 udpClient.NeedAcks.Add(outgoingPacket); 594 udpClient.NeedAcks.Add(outgoingPacket);
566 } 595 }
567 } 596 }
597 else
598 {
599 Interlocked.Increment(ref udpClient.PacketsResent);
600 }
568 601
569 #endregion Sequence Number Assignment 602 #endregion Sequence Number Assignment
570 603
571 // Stats tracking 604 // Stats tracking
572 Interlocked.Increment(ref udpClient.PacketsSent); 605 Interlocked.Increment(ref udpClient.PacketsSent);
573 if (isReliable)
574 Interlocked.Add(ref udpClient.UnackedBytes, outgoingPacket.Buffer.DataLength);
575 606
576 // Put the UDP payload on the wire 607 // Put the UDP payload on the wire
577 AsyncBeginSend(buffer); 608 AsyncBeginSend(buffer);
@@ -580,11 +611,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
580 outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue; 611 outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue;
581 } 612 }
582 613
583 protected override void PacketReceived(UDPPacketBuffer buffer) 614 public override void PacketReceived(UDPPacketBuffer buffer)
584 { 615 {
585 // Debugging/Profiling 616 // Debugging/Profiling
586 //try { Thread.CurrentThread.Name = "PacketReceived (" + m_scene.RegionInfo.RegionName + ")"; } 617 //try { Thread.CurrentThread.Name = "PacketReceived (" + m_scene.RegionInfo.RegionName + ")"; }
587 //catch (Exception) { } 618 //catch (Exception) { }
619// m_log.DebugFormat(
620// "[LLUDPSERVER]: Packet received from {0} in {1}", buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
588 621
589 LLUDPClient udpClient = null; 622 LLUDPClient udpClient = null;
590 Packet packet = null; 623 Packet packet = null;
@@ -593,6 +626,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP
593 626
594 #region Decoding 627 #region Decoding
595 628
629 if (buffer.DataLength < 7)
630 {
631// m_log.WarnFormat(
632// "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}",
633// buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
634
635 return; // Drop undersizd packet
636 }
637
638 int headerLen = 7;
639 if (buffer.Data[6] == 0xFF)
640 {
641 if (buffer.Data[7] == 0xFF)
642 headerLen = 10;
643 else
644 headerLen = 8;
645 }
646
647 if (buffer.DataLength < headerLen)
648 {
649// m_log.WarnFormat(
650// "[LLUDPSERVER]: Dropping packet with malformed header received from {0} in {1}",
651// buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
652
653 return; // Malformed header
654 }
655
596 try 656 try
597 { 657 {
598 packet = Packet.BuildPacket(buffer.Data, ref packetEnd, 658 packet = Packet.BuildPacket(buffer.Data, ref packetEnd,
@@ -601,15 +661,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP
601 } 661 }
602 catch (MalformedDataException) 662 catch (MalformedDataException)
603 { 663 {
604 m_log.ErrorFormat("[LLUDPSERVER]: Malformed data, cannot parse packet from {0}:\n{1}", 664 }
605 buffer.RemoteEndPoint, Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)); 665 catch (IndexOutOfRangeException)
666 {
667// m_log.WarnFormat(
668// "[LLUDPSERVER]: Dropping short packet received from {0} in {1}",
669// buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
670
671 return; // Drop short packet
672 }
673 catch(Exception e)
674 {
675 if (m_malformedCount < 100)
676 m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString());
677 m_malformedCount++;
678 if ((m_malformedCount % 100000) == 0)
679 m_log.DebugFormat("[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack.", m_malformedCount);
606 } 680 }
607 681
608 // Fail-safe check 682 // Fail-safe check
609 if (packet == null) 683 if (packet == null)
610 { 684 {
611 m_log.Warn("[LLUDPSERVER]: Couldn't build a message from incoming data " + buffer.DataLength + 685 m_log.ErrorFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}:",
612 " bytes long from " + buffer.RemoteEndPoint); 686 buffer.DataLength, buffer.RemoteEndPoint);
687 m_log.Error(Utils.BytesToHexString(buffer.Data, buffer.DataLength, null));
613 return; 688 return;
614 } 689 }
615 690
@@ -620,13 +695,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
620 // UseCircuitCode handling 695 // UseCircuitCode handling
621 if (packet.Type == PacketType.UseCircuitCode) 696 if (packet.Type == PacketType.UseCircuitCode)
622 { 697 {
623 m_log.Debug("[LLUDPSERVER]: Handling UseCircuitCode packet from " + buffer.RemoteEndPoint);
624 object[] array = new object[] { buffer, packet }; 698 object[] array = new object[] { buffer, packet };
625 699
626 if (m_asyncPacketHandling) 700 Util.FireAndForget(HandleUseCircuitCode, array);
627 Util.FireAndForget(HandleUseCircuitCode, array);
628 else
629 HandleUseCircuitCode(array);
630 701
631 return; 702 return;
632 } 703 }
@@ -658,7 +729,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
658 if (packet.Header.AppendedAcks && packet.Header.AckList != null) 729 if (packet.Header.AppendedAcks && packet.Header.AckList != null)
659 { 730 {
660 for (int i = 0; i < packet.Header.AckList.Length; i++) 731 for (int i = 0; i < packet.Header.AckList.Length; i++)
661 udpClient.NeedAcks.Remove(packet.Header.AckList[i], now, packet.Header.Resent); 732 udpClient.NeedAcks.Acknowledge(packet.Header.AckList[i], now, packet.Header.Resent);
662 } 733 }
663 734
664 // Handle PacketAck packets 735 // Handle PacketAck packets
@@ -667,7 +738,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
667 PacketAckPacket ackPacket = (PacketAckPacket)packet; 738 PacketAckPacket ackPacket = (PacketAckPacket)packet;
668 739
669 for (int i = 0; i < ackPacket.Packets.Length; i++) 740 for (int i = 0; i < ackPacket.Packets.Length; i++)
670 udpClient.NeedAcks.Remove(ackPacket.Packets[i].ID, now, packet.Header.Resent); 741 udpClient.NeedAcks.Acknowledge(ackPacket.Packets[i].ID, now, packet.Header.Resent);
671 742
672 // We don't need to do anything else with PacketAck packets 743 // We don't need to do anything else with PacketAck packets
673 return; 744 return;
@@ -703,9 +774,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
703 if (packet.Header.Reliable && !udpClient.PacketArchive.TryEnqueue(packet.Header.Sequence)) 774 if (packet.Header.Reliable && !udpClient.PacketArchive.TryEnqueue(packet.Header.Sequence))
704 { 775 {
705 if (packet.Header.Resent) 776 if (packet.Header.Resent)
706 m_log.Debug("[LLUDPSERVER]: Received a resend of already processed packet #" + packet.Header.Sequence + ", type: " + packet.Type); 777 m_log.DebugFormat(
707 else 778 "[LLUDPSERVER]: Received a resend of already processed packet #{0}, type {1} from {2}",
708 m_log.Warn("[LLUDPSERVER]: Received a duplicate (not marked as resend) of packet #" + packet.Header.Sequence + ", type: " + packet.Type); 779 packet.Header.Sequence, packet.Type, client.Name);
780 else
781 m_log.WarnFormat(
782 "[LLUDPSERVER]: Received a duplicate (not marked as resend) of packet #{0}, type {1} from {2}",
783 packet.Header.Sequence, packet.Type, client.Name);
709 784
710 // Avoid firing a callback twice for the same packet 785 // Avoid firing a callback twice for the same packet
711 return; 786 return;
@@ -827,19 +902,58 @@ namespace OpenSim.Region.ClientStack.LindenUDP
827 902
828 private void HandleUseCircuitCode(object o) 903 private void HandleUseCircuitCode(object o)
829 { 904 {
905// DateTime startTime = DateTime.Now;
830 object[] array = (object[])o; 906 object[] array = (object[])o;
831 UDPPacketBuffer buffer = (UDPPacketBuffer)array[0]; 907 UDPPacketBuffer buffer = (UDPPacketBuffer)array[0];
832 UseCircuitCodePacket packet = (UseCircuitCodePacket)array[1]; 908 UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1];
909
910 m_log.DebugFormat("[LLUDPSERVER]: Handling UseCircuitCode request from {0}", buffer.RemoteEndPoint);
833 911
834 IPEndPoint remoteEndPoint = (IPEndPoint)buffer.RemoteEndPoint; 912 IPEndPoint remoteEndPoint = (IPEndPoint)buffer.RemoteEndPoint;
835 913
836 // Begin the process of adding the client to the simulator 914 AuthenticateResponse sessionInfo;
837 AddNewClient((UseCircuitCodePacket)packet, remoteEndPoint); 915 if (IsClientAuthorized(uccp, out sessionInfo))
916 {
917 // Begin the process of adding the client to the simulator
918 IClientAPI client
919 = AddClient(
920 uccp.CircuitCode.Code,
921 uccp.CircuitCode.ID,
922 uccp.CircuitCode.SessionID,
923 remoteEndPoint,
924 sessionInfo);
925
926 // Send ack straight away to let the viewer know that the connection is active.
927 // The client will be null if it already exists (e.g. if on a region crossing the client sends a use
928 // circuit code to the existing child agent. This is not particularly obvious.
929 SendAckImmediate(remoteEndPoint, uccp.Header.Sequence);
930
931 // We only want to send initial data to new clients, not ones which are being converted from child to root.
932 if (client != null)
933 client.SceneAgent.SendInitialDataToMe();
934 }
935 else
936 {
937 // Don't create clients for unauthorized requesters.
938 m_log.WarnFormat(
939 "[LLUDPSERVER]: Connection request for client {0} connecting with unnotified circuit code {1} from {2}",
940 uccp.CircuitCode.ID, uccp.CircuitCode.Code, remoteEndPoint);
941 }
838 942
839 // Acknowledge the UseCircuitCode packet 943 // m_log.DebugFormat(
840 SendAckImmediate(remoteEndPoint, packet.Header.Sequence); 944// "[LLUDPSERVER]: Handling UseCircuitCode request from {0} took {1}ms",
945// buffer.RemoteEndPoint, (DateTime.Now - startTime).Milliseconds);
841 } 946 }
842 947
948 /// <summary>
949 /// Send an ack immediately to the given endpoint.
950 /// </summary>
951 /// <remarks>
952 /// FIXME: Might be possible to use SendPacketData() like everything else, but this will require refactoring so
953 /// that we can obtain the UDPClient easily at this point.
954 /// </remarks>
955 /// <param name="remoteEndpoint"></param>
956 /// <param name="sequenceNumber"></param>
843 private void SendAckImmediate(IPEndPoint remoteEndpoint, uint sequenceNumber) 957 private void SendAckImmediate(IPEndPoint remoteEndpoint, uint sequenceNumber)
844 { 958 {
845 PacketAckPacket ack = new PacketAckPacket(); 959 PacketAckPacket ack = new PacketAckPacket();
@@ -848,6 +962,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
848 ack.Packets[0] = new PacketAckPacket.PacketsBlock(); 962 ack.Packets[0] = new PacketAckPacket.PacketsBlock();
849 ack.Packets[0].ID = sequenceNumber; 963 ack.Packets[0].ID = sequenceNumber;
850 964
965 SendAckImmediate(remoteEndpoint, ack);
966 }
967
968 public virtual void SendAckImmediate(IPEndPoint remoteEndpoint, PacketAckPacket ack)
969 {
851 byte[] packetData = ack.ToBytes(); 970 byte[] packetData = ack.ToBytes();
852 int length = packetData.Length; 971 int length = packetData.Length;
853 972
@@ -869,54 +988,39 @@ namespace OpenSim.Region.ClientStack.LindenUDP
869 return sessionInfo.Authorised; 988 return sessionInfo.Authorised;
870 } 989 }
871 990
872 private void AddNewClient(UseCircuitCodePacket useCircuitCode, IPEndPoint remoteEndPoint) 991 /// <summary>
992 /// Add a client.
993 /// </summary>
994 /// <param name="circuitCode"></param>
995 /// <param name="agentID"></param>
996 /// <param name="sessionID"></param>
997 /// <param name="remoteEndPoint"></param>
998 /// <param name="sessionInfo"></param>
999 /// <returns>The client if it was added. Null if the client already existed.</returns>
1000 protected virtual IClientAPI AddClient(
1001 uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo)
873 { 1002 {
874 UUID agentID = useCircuitCode.CircuitCode.ID; 1003 IClientAPI client = null;
875 UUID sessionID = useCircuitCode.CircuitCode.SessionID;
876 uint circuitCode = useCircuitCode.CircuitCode.Code;
877 1004
878 if (m_scene.RegionStatus != RegionStatus.SlaveScene) 1005 // In priciple there shouldn't be more than one thread here, ever.
1006 // But in case that happens, we need to synchronize this piece of code
1007 // because it's too important
1008 lock (this)
879 { 1009 {
880 AuthenticateResponse sessionInfo; 1010 if (!m_scene.TryGetClient(agentID, out client))
881 if (IsClientAuthorized(useCircuitCode, out sessionInfo))
882 { 1011 {
883 AddClient(circuitCode, agentID, sessionID, remoteEndPoint, sessionInfo); 1012 LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, m_throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO);
884 }
885 else
886 {
887 // Don't create circuits for unauthorized clients
888 m_log.WarnFormat(
889 "[LLUDPSERVER]: Connection request for client {0} connecting with unnotified circuit code {1} from {2}",
890 useCircuitCode.CircuitCode.ID, useCircuitCode.CircuitCode.Code, remoteEndPoint);
891 }
892 }
893 else
894 {
895 // Slave regions don't accept new clients
896 m_log.Debug("[LLUDPSERVER]: Slave region " + m_scene.RegionInfo.RegionName + " ignoring UseCircuitCode packet");
897 }
898 }
899 1013
900 protected virtual void AddClient(uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo) 1014 client = new LLClientView(remoteEndPoint, m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
901 { 1015 client.OnLogout += LogoutHandler;
902 // Create the LLUDPClient
903 LLUDPClient udpClient = new LLUDPClient(this, m_throttleRates, m_throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO);
904 IClientAPI existingClient;
905 1016
906 if (!m_scene.TryGetClient(agentID, out existingClient)) 1017 ((LLClientView)client).DisableFacelights = m_disableFacelights;
907 {
908 // Create the LLClientView
909 LLClientView client = new LLClientView(remoteEndPoint, m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
910 client.OnLogout += LogoutHandler;
911 1018
912 // Start the IClientAPI 1019 client.Start();
913 client.Start(); 1020 }
914 }
915 else
916 {
917 m_log.WarnFormat("[LLUDPSERVER]: Ignoring a repeated UseCircuitCode from {0} at {1} for circuit {2}",
918 udpClient.AgentID, remoteEndPoint, circuitCode);
919 } 1021 }
1022
1023 return client;
920 } 1024 }
921 1025
922 private void RemoveClient(LLUDPClient udpClient) 1026 private void RemoveClient(LLUDPClient udpClient)
@@ -924,7 +1028,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
924 // Remove this client from the scene 1028 // Remove this client from the scene
925 IClientAPI client; 1029 IClientAPI client;
926 if (m_scene.TryGetClient(udpClient.AgentID, out client)) 1030 if (m_scene.TryGetClient(udpClient.AgentID, out client))
927 client.Close(); 1031 {
1032 client.IsLoggingOut = true;
1033 client.Close(false);
1034 }
928 } 1035 }
929 1036
930 private void IncomingPacketHandler() 1037 private void IncomingPacketHandler()
@@ -935,6 +1042,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
935 1042
936 while (base.IsRunning) 1043 while (base.IsRunning)
937 { 1044 {
1045 m_scene.ThreadAlive(1);
938 try 1046 try
939 { 1047 {
940 IncomingPacket incomingPacket = null; 1048 IncomingPacket incomingPacket = null;
@@ -977,6 +1085,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
977 1085
978 while (base.IsRunning) 1086 while (base.IsRunning)
979 { 1087 {
1088 m_scene.ThreadAlive(2);
980 try 1089 try
981 { 1090 {
982 m_packetSent = false; 1091 m_packetSent = false;
@@ -1021,9 +1130,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1021 1130
1022 #endregion Update Timers 1131 #endregion Update Timers
1023 1132
1133 // Use this for emergency monitoring -- bug hunting
1134 //if (m_scene.EmergencyMonitoring)
1135 // clientPacketHandler = MonitoredClientOutgoingPacketHandler;
1136 //else
1137 // clientPacketHandler = ClientOutgoingPacketHandler;
1138
1024 // Handle outgoing packets, resends, acknowledgements, and pings for each 1139 // Handle outgoing packets, resends, acknowledgements, and pings for each
1025 // client. m_packetSent will be set to true if a packet is sent 1140 // client. m_packetSent will be set to true if a packet is sent
1026 m_scene.ForEachClient(clientPacketHandler, false); 1141 m_scene.ForEachClient(clientPacketHandler);
1027 1142
1028 // If nothing was sent, sleep for the minimum amount of time before a 1143 // If nothing was sent, sleep for the minimum amount of time before a
1029 // token bucket could get more tokens 1144 // token bucket could get more tokens
@@ -1052,18 +1167,110 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1052 if (udpClient.IsConnected) 1167 if (udpClient.IsConnected)
1053 { 1168 {
1054 if (m_resendUnacked) 1169 if (m_resendUnacked)
1055 ResendUnacked(udpClient); 1170 HandleUnacked(udpClient);
1171
1172 if (m_sendAcks)
1173 SendAcks(udpClient);
1174
1175 if (m_sendPing)
1176 SendPing(udpClient);
1177
1178 // Dequeue any outgoing packets that are within the throttle limits
1179 if (udpClient.DequeueOutgoing())
1180 m_packetSent = true;
1181 }
1182 }
1183 }
1184 catch (Exception ex)
1185 {
1186 m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler iteration for " + client.Name +
1187 " threw an exception: " + ex.Message, ex);
1188 }
1189 }
1190
1191 #region Emergency Monitoring
1192 // Alternative packet handler fuull of instrumentation
1193 // Handy for hunting bugs
1194 private Stopwatch watch1 = new Stopwatch();
1195 private Stopwatch watch2 = new Stopwatch();
1196
1197 private float avgProcessingTicks = 0;
1198 private float avgResendUnackedTicks = 0;
1199 private float avgSendAcksTicks = 0;
1200 private float avgSendPingTicks = 0;
1201 private float avgDequeueTicks = 0;
1202 private long nticks = 0;
1203 private long nticksUnack = 0;
1204 private long nticksAck = 0;
1205 private long nticksPing = 0;
1206 private int npacksSent = 0;
1207 private int npackNotSent = 0;
1208
1209 private void MonitoredClientOutgoingPacketHandler(IClientAPI client)
1210 {
1211 nticks++;
1212 watch1.Start();
1213 try
1214 {
1215 if (client is LLClientView)
1216 {
1217 LLUDPClient udpClient = ((LLClientView)client).UDPClient;
1218
1219 if (udpClient.IsConnected)
1220 {
1221 if (m_resendUnacked)
1222 {
1223 nticksUnack++;
1224 watch2.Start();
1225
1226 HandleUnacked(udpClient);
1227
1228 watch2.Stop();
1229 avgResendUnackedTicks = (nticksUnack - 1)/(float)nticksUnack * avgResendUnackedTicks + (watch2.ElapsedTicks / (float)nticksUnack);
1230 watch2.Reset();
1231 }
1056 1232
1057 if (m_sendAcks) 1233 if (m_sendAcks)
1234 {
1235 nticksAck++;
1236 watch2.Start();
1237
1058 SendAcks(udpClient); 1238 SendAcks(udpClient);
1059 1239
1240 watch2.Stop();
1241 avgSendAcksTicks = (nticksAck - 1) / (float)nticksAck * avgSendAcksTicks + (watch2.ElapsedTicks / (float)nticksAck);
1242 watch2.Reset();
1243 }
1244
1060 if (m_sendPing) 1245 if (m_sendPing)
1246 {
1247 nticksPing++;
1248 watch2.Start();
1249
1061 SendPing(udpClient); 1250 SendPing(udpClient);
1062 1251
1252 watch2.Stop();
1253 avgSendPingTicks = (nticksPing - 1) / (float)nticksPing * avgSendPingTicks + (watch2.ElapsedTicks / (float)nticksPing);
1254 watch2.Reset();
1255 }
1256
1257 watch2.Start();
1063 // Dequeue any outgoing packets that are within the throttle limits 1258 // Dequeue any outgoing packets that are within the throttle limits
1064 if (udpClient.DequeueOutgoing()) 1259 if (udpClient.DequeueOutgoing())
1260 {
1065 m_packetSent = true; 1261 m_packetSent = true;
1262 npacksSent++;
1263 }
1264 else
1265 npackNotSent++;
1266
1267 watch2.Stop();
1268 avgDequeueTicks = (nticks - 1) / (float)nticks * avgDequeueTicks + (watch2.ElapsedTicks / (float)nticks);
1269 watch2.Reset();
1270
1066 } 1271 }
1272 else
1273 m_log.WarnFormat("[LLUDPSERVER]: Client is not connected");
1067 } 1274 }
1068 } 1275 }
1069 catch (Exception ex) 1276 catch (Exception ex)
@@ -1071,8 +1278,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1071 m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler iteration for " + client.Name + 1278 m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler iteration for " + client.Name +
1072 " threw an exception: " + ex.Message, ex); 1279 " threw an exception: " + ex.Message, ex);
1073 } 1280 }
1281 watch1.Stop();
1282 avgProcessingTicks = (nticks - 1) / (float)nticks * avgProcessingTicks + (watch1.ElapsedTicks / (float)nticks);
1283 watch1.Reset();
1284
1285 // reuse this -- it's every ~100ms
1286 if (m_scene.EmergencyMonitoring && nticks % 100 == 0)
1287 {
1288 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})",
1289 avgProcessingTicks, avgResendUnackedTicks, avgSendAcksTicks, avgSendPingTicks, avgDequeueTicks, TickCountResolution, npacksSent, npackNotSent);
1290 npackNotSent = npacksSent = 0;
1291 }
1292
1074 } 1293 }
1075 1294
1295 #endregion
1296
1076 private void ProcessInPacket(object state) 1297 private void ProcessInPacket(object state)
1077 { 1298 {
1078 IncomingPacket incomingPacket = (IncomingPacket)state; 1299 IncomingPacket incomingPacket = (IncomingPacket)state;
diff --git a/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
index d2779ba..cfe7c9d 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
@@ -44,7 +44,7 @@ namespace OpenMetaverse
44 /// This method is called when an incoming packet is received 44 /// This method is called when an incoming packet is received
45 /// </summary> 45 /// </summary>
46 /// <param name="buffer">Incoming packet buffer</param> 46 /// <param name="buffer">Incoming packet buffer</param>
47 protected abstract void PacketReceived(UDPPacketBuffer buffer); 47 public abstract void PacketReceived(UDPPacketBuffer buffer);
48 48
49 /// <summary>UDP port to bind to in server mode</summary> 49 /// <summary>UDP port to bind to in server mode</summary>
50 protected int m_udpPort; 50 protected int m_udpPort;
diff --git a/OpenSim/Region/ClientStack/LindenUDP/OutgoingPacket.cs b/OpenSim/Region/ClientStack/Linden/UDP/OutgoingPacket.cs
index 1a1a1cb..76c6c14 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/OutgoingPacket.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/OutgoingPacket.cs
@@ -31,6 +31,8 @@ using OpenMetaverse;
31 31
32namespace OpenSim.Region.ClientStack.LindenUDP 32namespace OpenSim.Region.ClientStack.LindenUDP
33{ 33{
34
35 public delegate void UnackedPacketMethod(OutgoingPacket oPacket);
34 /// <summary> 36 /// <summary>
35 /// Holds a reference to the <seealso cref="LLUDPClient"/> this packet is 37 /// Holds a reference to the <seealso cref="LLUDPClient"/> this packet is
36 /// destined for, along with the serialized packet data, sequence number 38 /// destined for, along with the serialized packet data, sequence number
@@ -52,6 +54,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
52 public int TickCount; 54 public int TickCount;
53 /// <summary>Category this packet belongs to</summary> 55 /// <summary>Category this packet belongs to</summary>
54 public ThrottleOutPacketType Category; 56 public ThrottleOutPacketType Category;
57 /// <summary>The delegate to be called if this packet is determined to be unacknowledged</summary>
58 public UnackedPacketMethod UnackedMethod;
55 59
56 /// <summary> 60 /// <summary>
57 /// Default constructor 61 /// Default constructor
@@ -60,11 +64,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
60 /// <param name="buffer">Serialized packet data. If the flags or sequence number 64 /// <param name="buffer">Serialized packet data. If the flags or sequence number
61 /// need to be updated, they will be injected directly into this binary buffer</param> 65 /// need to be updated, they will be injected directly into this binary buffer</param>
62 /// <param name="category">Throttling category for this packet</param> 66 /// <param name="category">Throttling category for this packet</param>
63 public OutgoingPacket(LLUDPClient client, UDPPacketBuffer buffer, ThrottleOutPacketType category) 67 public OutgoingPacket(LLUDPClient client, UDPPacketBuffer buffer, ThrottleOutPacketType category, UnackedPacketMethod method)
64 { 68 {
65 Client = client; 69 Client = client;
66 Buffer = buffer; 70 Buffer = buffer;
67 Category = category; 71 Category = category;
72 UnackedMethod = method;
68 } 73 }
69 } 74 }
70} 75}
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..a575e36
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs
@@ -0,0 +1,318 @@
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.Region.Framework.Scenes;
37using OpenSim.Tests.Common;
38using OpenSim.Tests.Common.Mock;
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
47 {
48 [TestFixtureSetUp]
49 public void FixtureInit()
50 {
51 // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
52 Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest;
53 }
54
55 [TestFixtureTearDown]
56 public void TearDown()
57 {
58 // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
59 // threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression
60 // tests really shouldn't).
61 Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
62 }
63
64// /// <summary>
65// /// Add a client for testing
66// /// </summary>
67// /// <param name="scene"></param>
68// /// <param name="testLLUDPServer"></param>
69// /// <param name="testPacketServer"></param>
70// /// <param name="acm">Agent circuit manager used in setting up the stack</param>
71// protected void SetupStack(
72// IScene scene, out TestLLUDPServer testLLUDPServer, out TestLLPacketServer testPacketServer,
73// out AgentCircuitManager acm)
74// {
75// IConfigSource configSource = new IniConfigSource();
76// ClientStackUserSettings userSettings = new ClientStackUserSettings();
77// testLLUDPServer = new TestLLUDPServer();
78// acm = new AgentCircuitManager();
79//
80// uint port = 666;
81// testLLUDPServer.Initialise(null, ref port, 0, false, configSource, acm);
82// testPacketServer = new TestLLPacketServer(testLLUDPServer, userSettings);
83// testLLUDPServer.LocalScene = scene;
84// }
85
86// /// <summary>
87// /// Set up a client for tests which aren't concerned with this process itself and where only one client is being
88// /// tested
89// /// </summary>
90// /// <param name="circuitCode"></param>
91// /// <param name="epSender"></param>
92// /// <param name="testLLUDPServer"></param>
93// /// <param name="acm"></param>
94// protected void AddClient(
95// uint circuitCode, EndPoint epSender, TestLLUDPServer testLLUDPServer, AgentCircuitManager acm)
96// {
97// UUID myAgentUuid = UUID.Parse("00000000-0000-0000-0000-000000000001");
98// UUID mySessionUuid = UUID.Parse("00000000-0000-0000-0000-000000000002");
99//
100// AddClient(circuitCode, epSender, myAgentUuid, mySessionUuid, testLLUDPServer, acm);
101// }
102
103// /// <summary>
104// /// Set up a client for tests which aren't concerned with this process itself
105// /// </summary>
106// /// <param name="circuitCode"></param>
107// /// <param name="epSender"></param>
108// /// <param name="agentId"></param>
109// /// <param name="sessionId"></param>
110// /// <param name="testLLUDPServer"></param>
111// /// <param name="acm"></param>
112// protected void AddClient(
113// uint circuitCode, EndPoint epSender, UUID agentId, UUID sessionId,
114// TestLLUDPServer testLLUDPServer, AgentCircuitManager acm)
115// {
116// AgentCircuitData acd = new AgentCircuitData();
117// acd.AgentID = agentId;
118// acd.SessionID = sessionId;
119//
120// UseCircuitCodePacket uccp = new UseCircuitCodePacket();
121//
122// UseCircuitCodePacket.CircuitCodeBlock uccpCcBlock
123// = new UseCircuitCodePacket.CircuitCodeBlock();
124// uccpCcBlock.Code = circuitCode;
125// uccpCcBlock.ID = agentId;
126// uccpCcBlock.SessionID = sessionId;
127// uccp.CircuitCode = uccpCcBlock;
128//
129// acm.AddNewCircuit(circuitCode, acd);
130//
131// testLLUDPServer.LoadReceive(uccp, epSender);
132// testLLUDPServer.ReceiveData(null);
133// }
134
135 /// <summary>
136 /// Build an object name packet for test purposes
137 /// </summary>
138 /// <param name="objectLocalId"></param>
139 /// <param name="objectName"></param>
140 protected ObjectNamePacket BuildTestObjectNamePacket(uint objectLocalId, string objectName)
141 {
142 ObjectNamePacket onp = new ObjectNamePacket();
143 ObjectNamePacket.ObjectDataBlock odb = new ObjectNamePacket.ObjectDataBlock();
144 odb.LocalID = objectLocalId;
145 odb.Name = Utils.StringToBytes(objectName);
146 onp.ObjectData = new ObjectNamePacket.ObjectDataBlock[] { odb };
147 onp.Header.Zerocoded = false;
148
149 return onp;
150 }
151
152 /// <summary>
153 /// Test adding a client to the stack
154 /// </summary>
155 [Test]
156 public void TestAddClient()
157 {
158 TestHelpers.InMethod();
159// XmlConfigurator.Configure();
160
161 TestScene scene = SceneHelpers.SetupScene();
162 uint myCircuitCode = 123456;
163 UUID myAgentUuid = TestHelpers.ParseTail(0x1);
164 UUID mySessionUuid = TestHelpers.ParseTail(0x2);
165 IPEndPoint testEp = new IPEndPoint(IPAddress.Loopback, 999);
166
167 uint port = 0;
168 AgentCircuitManager acm = scene.AuthenticateHandler;
169
170 TestLLUDPServer llUdpServer
171 = new TestLLUDPServer(IPAddress.Any, ref port, 0, false, new IniConfigSource(), acm);
172 llUdpServer.AddScene(scene);
173
174 UseCircuitCodePacket uccp = new UseCircuitCodePacket();
175
176 UseCircuitCodePacket.CircuitCodeBlock uccpCcBlock
177 = new UseCircuitCodePacket.CircuitCodeBlock();
178 uccpCcBlock.Code = myCircuitCode;
179 uccpCcBlock.ID = myAgentUuid;
180 uccpCcBlock.SessionID = mySessionUuid;
181 uccp.CircuitCode = uccpCcBlock;
182
183 byte[] uccpBytes = uccp.ToBytes();
184 UDPPacketBuffer upb = new UDPPacketBuffer(testEp, uccpBytes.Length);
185 upb.DataLength = uccpBytes.Length; // God knows why this isn't set by the constructor.
186 Buffer.BlockCopy(uccpBytes, 0, upb.Data, 0, uccpBytes.Length);
187
188 llUdpServer.PacketReceived(upb);
189
190 // Presence shouldn't exist since the circuit manager doesn't know about this circuit for authentication yet
191 Assert.That(scene.GetScenePresence(myAgentUuid), Is.Null);
192
193 AgentCircuitData acd = new AgentCircuitData();
194 acd.AgentID = myAgentUuid;
195 acd.SessionID = mySessionUuid;
196
197 acm.AddNewCircuit(myCircuitCode, acd);
198
199 llUdpServer.PacketReceived(upb);
200
201 // Should succeed now
202 ScenePresence sp = scene.GetScenePresence(myAgentUuid);
203 Assert.That(sp.UUID, Is.EqualTo(myAgentUuid));
204
205 Assert.That(llUdpServer.PacketsSent.Count, Is.EqualTo(1));
206
207 Packet packet = llUdpServer.PacketsSent[0];
208 Assert.That(packet, Is.InstanceOf(typeof(PacketAckPacket)));
209
210 PacketAckPacket ackPacket = packet as PacketAckPacket;
211 Assert.That(ackPacket.Packets.Length, Is.EqualTo(1));
212 Assert.That(ackPacket.Packets[0].ID, Is.EqualTo(0));
213 }
214
215// /// <summary>
216// /// Test removing a client from the stack
217// /// </summary>
218// [Test]
219// public void TestRemoveClient()
220// {
221// TestHelper.InMethod();
222//
223// uint myCircuitCode = 123457;
224//
225// TestLLUDPServer testLLUDPServer;
226// TestLLPacketServer testLLPacketServer;
227// AgentCircuitManager acm;
228// SetupStack(new MockScene(), out testLLUDPServer, out testLLPacketServer, out acm);
229// AddClient(myCircuitCode, new IPEndPoint(IPAddress.Loopback, 1000), testLLUDPServer, acm);
230//
231// testLLUDPServer.RemoveClientCircuit(myCircuitCode);
232// Assert.IsFalse(testLLUDPServer.HasCircuit(myCircuitCode));
233//
234// // Check that removing a non-existant circuit doesn't have any bad effects
235// testLLUDPServer.RemoveClientCircuit(101);
236// Assert.IsFalse(testLLUDPServer.HasCircuit(101));
237// }
238//
239// /// <summary>
240// /// Make sure that the client stack reacts okay to malformed packets
241// /// </summary>
242// [Test]
243// public void TestMalformedPacketSend()
244// {
245// TestHelper.InMethod();
246//
247// uint myCircuitCode = 123458;
248// EndPoint testEp = new IPEndPoint(IPAddress.Loopback, 1001);
249// MockScene scene = new MockScene();
250//
251// TestLLUDPServer testLLUDPServer;
252// TestLLPacketServer testLLPacketServer;
253// AgentCircuitManager acm;
254// SetupStack(scene, out testLLUDPServer, out testLLPacketServer, out acm);
255// AddClient(myCircuitCode, testEp, testLLUDPServer, acm);
256//
257// byte[] data = new byte[] { 0x01, 0x02, 0x03, 0x04 };
258//
259// // Send two garbled 'packets' in succession
260// testLLUDPServer.LoadReceive(data, testEp);
261// testLLUDPServer.LoadReceive(data, testEp);
262// testLLUDPServer.ReceiveData(null);
263//
264// // Check that we are still here
265// Assert.IsTrue(testLLUDPServer.HasCircuit(myCircuitCode));
266// Assert.That(testLLPacketServer.GetTotalPacketsReceived(), Is.EqualTo(0));
267//
268// // Check that sending a valid packet to same circuit still succeeds
269// Assert.That(scene.ObjectNameCallsReceived, Is.EqualTo(0));
270//
271// testLLUDPServer.LoadReceive(BuildTestObjectNamePacket(1, "helloooo"), testEp);
272// testLLUDPServer.ReceiveData(null);
273//
274// Assert.That(testLLPacketServer.GetTotalPacketsReceived(), Is.EqualTo(1));
275// Assert.That(testLLPacketServer.GetPacketsReceivedFor(PacketType.ObjectName), Is.EqualTo(1));
276// }
277//
278// /// <summary>
279// /// Test that the stack continues to work even if some client has caused a
280// /// SocketException on Socket.BeginReceive()
281// /// </summary>
282// [Test]
283// public void TestExceptionOnBeginReceive()
284// {
285// TestHelper.InMethod();
286//
287// MockScene scene = new MockScene();
288//
289// uint circuitCodeA = 130000;
290// EndPoint epA = new IPEndPoint(IPAddress.Loopback, 1300);
291// UUID agentIdA = UUID.Parse("00000000-0000-0000-0000-000000001300");
292// UUID sessionIdA = UUID.Parse("00000000-0000-0000-0000-000000002300");
293//
294// uint circuitCodeB = 130001;
295// EndPoint epB = new IPEndPoint(IPAddress.Loopback, 1301);
296// UUID agentIdB = UUID.Parse("00000000-0000-0000-0000-000000001301");
297// UUID sessionIdB = UUID.Parse("00000000-0000-0000-0000-000000002301");
298//
299// TestLLUDPServer testLLUDPServer;
300// TestLLPacketServer testLLPacketServer;
301// AgentCircuitManager acm;
302// SetupStack(scene, out testLLUDPServer, out testLLPacketServer, out acm);
303// AddClient(circuitCodeA, epA, agentIdA, sessionIdA, testLLUDPServer, acm);
304// AddClient(circuitCodeB, epB, agentIdB, sessionIdB, testLLUDPServer, acm);
305//
306// testLLUDPServer.LoadReceive(BuildTestObjectNamePacket(1, "packet1"), epA);
307// testLLUDPServer.LoadReceive(BuildTestObjectNamePacket(1, "packet2"), epB);
308// testLLUDPServer.LoadReceiveWithBeginException(epA);
309// testLLUDPServer.LoadReceive(BuildTestObjectNamePacket(2, "packet3"), epB);
310// testLLUDPServer.ReceiveData(null);
311//
312// Assert.IsFalse(testLLUDPServer.HasCircuit(circuitCodeA));
313//
314// Assert.That(testLLPacketServer.GetTotalPacketsReceived(), Is.EqualTo(3));
315// Assert.That(testLLPacketServer.GetPacketsReceivedFor(PacketType.ObjectName), Is.EqualTo(3));
316// }
317 }
318}
diff --git a/OpenSim/Region/ClientStack/LindenUDP/Tests/MockScene.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs
index 34c21aa..fb94355 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/Tests/MockScene.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs
@@ -25,6 +25,7 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System.Net;
28using OpenMetaverse; 29using OpenMetaverse;
29using OpenSim.Framework; 30using OpenSim.Framework;
30using OpenSim.Region.Framework.Scenes; 31using OpenSim.Region.Framework.Scenes;
@@ -52,14 +53,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
52 public override void Update() {} 53 public override void Update() {}
53 public override void LoadWorldMap() {} 54 public override void LoadWorldMap() {}
54 55
55 public override void AddNewClient(IClientAPI client) 56 public override ISceneAgent AddNewClient(IClientAPI client, PresenceType type)
56 { 57 {
57 client.OnObjectName += RecordObjectNameCall; 58 client.OnObjectName += RecordObjectNameCall;
59
60 // FIXME
61 return null;
58 } 62 }
59 63
60 public override void RemoveClient(UUID agentID) {} 64 public override void RemoveClient(UUID agentID, bool someReason) {}
61 public override void CloseAllAgents(uint circuitcode) {} 65// public override void CloseAllAgents(uint circuitcode) {}
66 public override bool CheckClient(UUID clientId, IPEndPoint endPoint) { return true; }
62 public override void OtherRegionUp(GridRegion otherRegion) { } 67 public override void OtherRegionUp(GridRegion otherRegion) { }
68
69 public override bool TryGetScenePresence(UUID uuid, out ScenePresence sp) { sp = null; return false; }
63 70
64 /// <summary> 71 /// <summary>
65 /// Doesn't really matter what the call is - we're using this to test that a packet has actually been received 72 /// Doesn't really matter what the call is - we're using this to test that a packet has actually been received
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..0f88ec6
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs
@@ -0,0 +1,105 @@
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.Mock;
34using OpenSim.Tests.Common;
35
36namespace OpenSim.Region.ClientStack.LindenUDP.Tests
37{
38 /// <summary>
39 /// Tests for the LL packet handler
40 /// </summary>
41 [TestFixture]
42 public class PacketHandlerTests
43 {
44// [Test]
45// /// <summary>
46// /// More a placeholder, really
47// /// </summary>
48// public void InPacketTest()
49// {
50// TestHelper.InMethod();
51//
52// AgentCircuitData agent = new AgentCircuitData();
53// agent.AgentID = UUID.Random();
54// agent.firstname = "testfirstname";
55// agent.lastname = "testlastname";
56// agent.SessionID = UUID.Zero;
57// agent.SecureSessionID = UUID.Zero;
58// agent.circuitcode = 123;
59// agent.BaseFolder = UUID.Zero;
60// agent.InventoryFolder = UUID.Zero;
61// agent.startpos = Vector3.Zero;
62// agent.CapsPath = "http://wibble.com";
63//
64// TestLLUDPServer testLLUDPServer;
65// TestLLPacketServer testLLPacketServer;
66// AgentCircuitManager acm;
67// IScene scene = new MockScene();
68// SetupStack(scene, out testLLUDPServer, out testLLPacketServer, out acm);
69//
70// TestClient testClient = new TestClient(agent, scene);
71//
72// LLPacketHandler packetHandler
73// = new LLPacketHandler(testClient, testLLPacketServer, new ClientStackUserSettings());
74//
75// packetHandler.InPacket(new AgentAnimationPacket());
76// LLQueItem receivedPacket = packetHandler.PacketQueue.Dequeue();
77//
78// Assert.That(receivedPacket, Is.Not.Null);
79// Assert.That(receivedPacket.Incoming, Is.True);
80// Assert.That(receivedPacket.Packet, Is.TypeOf(typeof(AgentAnimationPacket)));
81// }
82//
83// /// <summary>
84// /// Add a client for testing
85// /// </summary>
86// /// <param name="scene"></param>
87// /// <param name="testLLUDPServer"></param>
88// /// <param name="testPacketServer"></param>
89// /// <param name="acm">Agent circuit manager used in setting up the stack</param>
90// protected void SetupStack(
91// IScene scene, out TestLLUDPServer testLLUDPServer, out TestLLPacketServer testPacketServer,
92// out AgentCircuitManager acm)
93// {
94// IConfigSource configSource = new IniConfigSource();
95// ClientStackUserSettings userSettings = new ClientStackUserSettings();
96// testLLUDPServer = new TestLLUDPServer();
97// acm = new AgentCircuitManager();
98//
99// uint port = 666;
100// testLLUDPServer.Initialise(null, ref port, 0, false, configSource, acm);
101// testPacketServer = new TestLLPacketServer(testLLUDPServer, userSettings);
102// testLLUDPServer.LocalScene = scene;
103// }
104 }
105}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/TestLLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/TestLLUDPServer.cs
new file mode 100644
index 0000000..0302385
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/TestLLUDPServer.cs
@@ -0,0 +1,161 @@
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.Net.Sockets;
32using Nini.Config;
33using OpenMetaverse.Packets;
34using OpenSim.Framework;
35
36namespace OpenSim.Region.ClientStack.LindenUDP.Tests
37{
38 /// <summary>
39 /// This class enables regression testing of the LLUDPServer by allowing us to intercept outgoing data.
40 /// </summary>
41 public class TestLLUDPServer : LLUDPServer
42 {
43 public List<Packet> PacketsSent { get; private set; }
44
45 public TestLLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager)
46 : base(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager)
47 {
48 PacketsSent = new List<Packet>();
49 }
50
51 public override void SendAckImmediate(IPEndPoint remoteEndpoint, PacketAckPacket ack)
52 {
53 PacketsSent.Add(ack);
54 }
55
56 public override void SendPacket(
57 LLUDPClient udpClient, Packet packet, ThrottleOutPacketType category, bool allowSplitting, UnackedPacketMethod method)
58 {
59 PacketsSent.Add(packet);
60 }
61
62//// /// <summary>
63//// /// The chunks of data to pass to the LLUDPServer when it calls EndReceive
64//// /// </summary>
65//// protected Queue<ChunkSenderTuple> m_chunksToLoad = new Queue<ChunkSenderTuple>();
66//
67//// protected override void BeginReceive()
68//// {
69//// if (m_chunksToLoad.Count > 0 && m_chunksToLoad.Peek().BeginReceiveException)
70//// {
71//// ChunkSenderTuple tuple = m_chunksToLoad.Dequeue();
72//// reusedEpSender = tuple.Sender;
73//// throw new SocketException();
74//// }
75//// }
76//
77//// protected override bool EndReceive(out int numBytes, IAsyncResult result, ref EndPoint epSender)
78//// {
79//// numBytes = 0;
80////
81//// //m_log.Debug("Queue size " + m_chunksToLoad.Count);
82////
83//// if (m_chunksToLoad.Count <= 0)
84//// return false;
85////
86//// ChunkSenderTuple tuple = m_chunksToLoad.Dequeue();
87//// RecvBuffer = tuple.Data;
88//// numBytes = tuple.Data.Length;
89//// epSender = tuple.Sender;
90////
91//// return true;
92//// }
93//
94//// public override void SendPacketTo(byte[] buffer, int size, SocketFlags flags, uint circuitcode)
95//// {
96//// // Don't do anything just yet
97//// }
98//
99// /// <summary>
100// /// Signal that this chunk should throw an exception on Socket.BeginReceive()
101// /// </summary>
102// /// <param name="epSender"></param>
103// public void LoadReceiveWithBeginException(EndPoint epSender)
104// {
105// ChunkSenderTuple tuple = new ChunkSenderTuple(epSender);
106// tuple.BeginReceiveException = true;
107// m_chunksToLoad.Enqueue(tuple);
108// }
109//
110// /// <summary>
111// /// Load some data to be received by the LLUDPServer on the next receive call
112// /// </summary>
113// /// <param name="data"></param>
114// /// <param name="epSender"></param>
115// public void LoadReceive(byte[] data, EndPoint epSender)
116// {
117// m_chunksToLoad.Enqueue(new ChunkSenderTuple(data, epSender));
118// }
119//
120// /// <summary>
121// /// Load a packet to be received by the LLUDPServer on the next receive call
122// /// </summary>
123// /// <param name="packet"></param>
124// public void LoadReceive(Packet packet, EndPoint epSender)
125// {
126// LoadReceive(packet.ToBytes(), epSender);
127// }
128//
129// /// <summary>
130// /// Calls the protected asynchronous result method. This fires out all data chunks currently queued for send
131// /// </summary>
132// /// <param name="result"></param>
133// public void ReceiveData(IAsyncResult result)
134// {
135// // Doesn't work the same way anymore
136//// while (m_chunksToLoad.Count > 0)
137//// OnReceivedData(result);
138// }
139 }
140
141 /// <summary>
142 /// Record the data and sender tuple
143 /// </summary>
144 public class ChunkSenderTuple
145 {
146 public byte[] Data;
147 public EndPoint Sender;
148 public bool BeginReceiveException;
149
150 public ChunkSenderTuple(byte[] data, EndPoint sender)
151 {
152 Data = data;
153 Sender = sender;
154 }
155
156 public ChunkSenderTuple(EndPoint sender)
157 {
158 Sender = sender;
159 }
160 }
161}
diff --git a/OpenSim/Region/ClientStack/LindenUDP/ThrottleRates.cs b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs
index aaf6e26..c9aac0b 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/ThrottleRates.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs
@@ -52,30 +52,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
52 public int Texture; 52 public int Texture;
53 /// <summary>Drip rate for asset packets</summary> 53 /// <summary>Drip rate for asset packets</summary>
54 public int Asset; 54 public int Asset;
55 /// <summary>Drip rate for state packets</summary> 55
56 public int State;
57 /// <summary>Drip rate for the parent token bucket</summary> 56 /// <summary>Drip rate for the parent token bucket</summary>
58 public int Total; 57 public int Total;
59 58
60 /// <summary>Maximum burst rate for resent packets</summary> 59 /// <summary>Flag used to enable adaptive throttles</summary>
61 public int ResendLimit; 60 public bool AdaptiveThrottlesEnabled;
62 /// <summary>Maximum burst rate for land packets</summary> 61
63 public int LandLimit;
64 /// <summary>Maximum burst rate for wind packets</summary>
65 public int WindLimit;
66 /// <summary>Maximum burst rate for cloud packets</summary>
67 public int CloudLimit;
68 /// <summary>Maximum burst rate for task (state and transaction) packets</summary>
69 public int TaskLimit;
70 /// <summary>Maximum burst rate for texture packets</summary>
71 public int TextureLimit;
72 /// <summary>Maximum burst rate for asset packets</summary>
73 public int AssetLimit;
74 /// <summary>Maximum burst rate for state packets</summary>
75 public int StateLimit;
76 /// <summary>Burst rate for the parent token bucket</summary>
77 public int TotalLimit;
78
79 /// <summary> 62 /// <summary>
80 /// Default constructor 63 /// Default constructor
81 /// </summary> 64 /// </summary>
@@ -86,26 +69,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
86 { 69 {
87 IConfig throttleConfig = config.Configs["ClientStack.LindenUDP"]; 70 IConfig throttleConfig = config.Configs["ClientStack.LindenUDP"];
88 71
89 Resend = throttleConfig.GetInt("resend_default", 12500); 72 Resend = throttleConfig.GetInt("resend_default", 6625);
90 Land = throttleConfig.GetInt("land_default", 1000); 73 Land = throttleConfig.GetInt("land_default", 9125);
91 Wind = throttleConfig.GetInt("wind_default", 1000); 74 Wind = throttleConfig.GetInt("wind_default", 1750);
92 Cloud = throttleConfig.GetInt("cloud_default", 1000); 75 Cloud = throttleConfig.GetInt("cloud_default", 1750);
93 Task = throttleConfig.GetInt("task_default", 1000); 76 Task = throttleConfig.GetInt("task_default", 18500);
94 Texture = throttleConfig.GetInt("texture_default", 1000); 77 Texture = throttleConfig.GetInt("texture_default", 18500);
95 Asset = throttleConfig.GetInt("asset_default", 1000); 78 Asset = throttleConfig.GetInt("asset_default", 10500);
96 State = throttleConfig.GetInt("state_default", 1000);
97
98 ResendLimit = throttleConfig.GetInt("resend_limit", 18750);
99 LandLimit = throttleConfig.GetInt("land_limit", 29750);
100 WindLimit = throttleConfig.GetInt("wind_limit", 18750);
101 CloudLimit = throttleConfig.GetInt("cloud_limit", 18750);
102 TaskLimit = throttleConfig.GetInt("task_limit", 18750);
103 TextureLimit = throttleConfig.GetInt("texture_limit", 55750);
104 AssetLimit = throttleConfig.GetInt("asset_limit", 27500);
105 StateLimit = throttleConfig.GetInt("state_limit", 37000);
106 79
107 Total = throttleConfig.GetInt("client_throttle_max_bps", 0); 80 Total = throttleConfig.GetInt("client_throttle_max_bps", 0);
108 TotalLimit = Total; 81
82 AdaptiveThrottlesEnabled = throttleConfig.GetBoolean("enable_adaptive_throttles", false);
109 } 83 }
110 catch (Exception) { } 84 catch (Exception) { }
111 } 85 }
@@ -128,34 +102,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
128 return Texture; 102 return Texture;
129 case ThrottleOutPacketType.Asset: 103 case ThrottleOutPacketType.Asset:
130 return Asset; 104 return Asset;
131 case ThrottleOutPacketType.State:
132 return State;
133 case ThrottleOutPacketType.Unknown:
134 default:
135 return 0;
136 }
137 }
138
139 public int GetLimit(ThrottleOutPacketType type)
140 {
141 switch (type)
142 {
143 case ThrottleOutPacketType.Resend:
144 return ResendLimit;
145 case ThrottleOutPacketType.Land:
146 return LandLimit;
147 case ThrottleOutPacketType.Wind:
148 return WindLimit;
149 case ThrottleOutPacketType.Cloud:
150 return CloudLimit;
151 case ThrottleOutPacketType.Task:
152 return TaskLimit;
153 case ThrottleOutPacketType.Texture:
154 return TextureLimit;
155 case ThrottleOutPacketType.Asset:
156 return AssetLimit;
157 case ThrottleOutPacketType.State:
158 return StateLimit;
159 case ThrottleOutPacketType.Unknown: 105 case ThrottleOutPacketType.Unknown:
160 default: 106 default:
161 return 0; 107 return 0;
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs
new file mode 100644
index 0000000..4c33db5
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs
@@ -0,0 +1,394 @@
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 private static Int32 m_counter = 0;
46
47// private Int32 m_identifier;
48
49 /// <summary>
50 /// Number of ticks (ms) per quantum, drip rate and max burst
51 /// are defined over this interval.
52 /// </summary>
53 protected const Int32 m_ticksPerQuantum = 1000;
54
55 /// <summary>
56 /// This is the number of quantums worth of packets that can
57 /// be accommodated during a burst
58 /// </summary>
59 protected const Double m_quantumsPerBurst = 1.5;
60
61 /// <summary>
62 /// </summary>
63 protected const Int32 m_minimumDripRate = 1400;
64
65 /// <summary>Time of the last drip, in system ticks</summary>
66 protected Int32 m_lastDrip;
67
68 /// <summary>
69 /// The number of bytes that can be sent at this moment. This is the
70 /// current number of tokens in the bucket
71 /// </summary>
72 protected Int64 m_tokenCount;
73
74 /// <summary>
75 /// Map of children buckets and their requested maximum burst rate
76 /// </summary>
77 protected Dictionary<TokenBucket,Int64> m_children = new Dictionary<TokenBucket,Int64>();
78
79#region Properties
80
81 /// <summary>
82 /// The parent bucket of this bucket, or null if this bucket has no
83 /// parent. The parent bucket will limit the aggregate bandwidth of all
84 /// of its children buckets
85 /// </summary>
86 protected TokenBucket m_parent;
87 public TokenBucket Parent
88 {
89 get { return m_parent; }
90 set { m_parent = value; }
91 }
92
93 /// <summary>
94 /// Maximum burst rate in bytes per second. This is the maximum number
95 /// of tokens that can accumulate in the bucket at any one time. This
96 /// also sets the total request for leaf nodes
97 /// </summary>
98 protected Int64 m_burstRate;
99 public Int64 RequestedBurstRate
100 {
101 get { return m_burstRate; }
102 set { m_burstRate = (value < 0 ? 0 : value); }
103 }
104
105 public Int64 BurstRate
106 {
107 get {
108 double rate = RequestedBurstRate * BurstRateModifier();
109 if (rate < m_minimumDripRate * m_quantumsPerBurst)
110 rate = m_minimumDripRate * m_quantumsPerBurst;
111
112 return (Int64) rate;
113 }
114 }
115
116 /// <summary>
117 /// The speed limit of this bucket in bytes per second. This is the
118 /// number of tokens that are added to the bucket per quantum
119 /// </summary>
120 /// <remarks>Tokens are added to the bucket any time
121 /// <seealso cref="RemoveTokens"/> is called, at the granularity of
122 /// the system tick interval (typically around 15-22ms)</remarks>
123 protected Int64 m_dripRate;
124 public virtual Int64 RequestedDripRate
125 {
126 get { return (m_dripRate == 0 ? m_totalDripRequest : m_dripRate); }
127 set {
128 m_dripRate = (value < 0 ? 0 : value);
129 m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst);
130 m_totalDripRequest = m_dripRate;
131 if (m_parent != null)
132 m_parent.RegisterRequest(this,m_dripRate);
133 }
134 }
135
136 public virtual Int64 DripRate
137 {
138 get {
139 if (m_parent == null)
140 return Math.Min(RequestedDripRate,TotalDripRequest);
141
142 double rate = (double)RequestedDripRate * m_parent.DripRateModifier();
143 if (rate < m_minimumDripRate)
144 rate = m_minimumDripRate;
145
146 return (Int64)rate;
147 }
148 }
149
150 /// <summary>
151 /// The current total of the requested maximum burst rates of
152 /// this bucket's children buckets.
153 /// </summary>
154 protected Int64 m_totalDripRequest;
155 public Int64 TotalDripRequest
156 {
157 get { return m_totalDripRequest; }
158 set { m_totalDripRequest = value; }
159 }
160
161#endregion Properties
162
163#region Constructor
164
165 /// <summary>
166 /// Default constructor
167 /// </summary>
168 /// <param name="parent">Parent bucket if this is a child bucket, or
169 /// null if this is a root bucket</param>
170 /// <param name="maxBurst">Maximum size of the bucket in bytes, or
171 /// zero if this bucket has no maximum capacity</param>
172 /// <param name="dripRate">Rate that the bucket fills, in bytes per
173 /// second. If zero, the bucket always remains full</param>
174 public TokenBucket(TokenBucket parent, Int64 dripRate)
175 {
176// m_identifier = m_counter++;
177 m_counter++;
178
179 Parent = parent;
180 RequestedDripRate = dripRate;
181 // TotalDripRequest = dripRate; // this will be overwritten when a child node registers
182 // MaxBurst = (Int64)((double)dripRate * m_quantumsPerBurst);
183 m_lastDrip = Util.EnvironmentTickCount();
184 }
185
186#endregion Constructor
187
188 /// <summary>
189 /// Compute a modifier for the MaxBurst rate. This is 1.0, meaning
190 /// no modification if the requested bandwidth is less than the
191 /// max burst bandwidth all the way to the root of the throttle
192 /// hierarchy. However, if any of the parents is over-booked, then
193 /// the modifier will be less than 1.
194 /// </summary>
195 protected double DripRateModifier()
196 {
197 Int64 driprate = DripRate;
198 return driprate >= TotalDripRequest ? 1.0 : (double)driprate / (double)TotalDripRequest;
199 }
200
201 /// <summary>
202 /// </summary>
203 protected double BurstRateModifier()
204 {
205 // for now... burst rate is always m_quantumsPerBurst (constant)
206 // larger than drip rate so the ratio of burst requests is the
207 // same as the drip ratio
208 return DripRateModifier();
209 }
210
211 /// <summary>
212 /// Register drip rate requested by a child of this throttle. Pass the
213 /// changes up the hierarchy.
214 /// </summary>
215 public void RegisterRequest(TokenBucket child, Int64 request)
216 {
217 lock (m_children)
218 {
219 m_children[child] = request;
220 // m_totalDripRequest = m_children.Values.Sum();
221
222 m_totalDripRequest = 0;
223 foreach (KeyValuePair<TokenBucket, Int64> cref in m_children)
224 m_totalDripRequest += cref.Value;
225 }
226
227 // Pass the new values up to the parent
228 if (m_parent != null)
229 m_parent.RegisterRequest(this,Math.Min(RequestedDripRate, TotalDripRequest));
230 }
231
232 /// <summary>
233 /// Remove the rate requested by a child of this throttle. Pass the
234 /// changes up the hierarchy.
235 /// </summary>
236 public void UnregisterRequest(TokenBucket child)
237 {
238 lock (m_children)
239 {
240 m_children.Remove(child);
241 // m_totalDripRequest = m_children.Values.Sum();
242
243 m_totalDripRequest = 0;
244 foreach (KeyValuePair<TokenBucket, Int64> cref in m_children)
245 m_totalDripRequest += cref.Value;
246 }
247
248
249 // Pass the new values up to the parent
250 if (m_parent != null)
251 m_parent.RegisterRequest(this,Math.Min(RequestedDripRate, TotalDripRequest));
252 }
253
254 /// <summary>
255 /// Remove a given number of tokens from the bucket
256 /// </summary>
257 /// <param name="amount">Number of tokens to remove from the bucket</param>
258 /// <returns>True if the requested number of tokens were removed from
259 /// the bucket, otherwise false</returns>
260 public bool RemoveTokens(Int64 amount)
261 {
262 // Deposit tokens for this interval
263 Drip();
264
265 // If we have enough tokens then remove them and return
266 if (m_tokenCount - amount >= 0)
267 {
268 // we don't have to remove from the parent, the drip rate is already
269 // reflective of the drip rate limits in the parent
270 m_tokenCount -= amount;
271 return true;
272 }
273
274 return false;
275 }
276
277 /// <summary>
278 /// Deposit tokens into the bucket from a child bucket that did
279 /// not use all of its available tokens
280 /// </summary>
281 protected void Deposit(Int64 count)
282 {
283 m_tokenCount += count;
284
285 // Deposit the overflow in the parent bucket, this is how we share
286 // unused bandwidth
287 Int64 burstrate = BurstRate;
288 if (m_tokenCount > burstrate)
289 m_tokenCount = burstrate;
290 }
291
292 /// <summary>
293 /// Add tokens to the bucket over time. The number of tokens added each
294 /// call depends on the length of time that has passed since the last
295 /// call to Drip
296 /// </summary>
297 /// <returns>True if tokens were added to the bucket, otherwise false</returns>
298 protected void Drip()
299 {
300 // This should never happen... means we are a leaf node and were created
301 // with no drip rate...
302 if (DripRate == 0)
303 {
304 m_log.WarnFormat("[TOKENBUCKET] something odd is happening and drip rate is 0");
305 return;
306 }
307
308 // Determine the interval over which we are adding tokens, never add
309 // more than a single quantum of tokens
310 Int32 deltaMS = Math.Min(Util.EnvironmentTickCountSubtract(m_lastDrip), m_ticksPerQuantum);
311 m_lastDrip = Util.EnvironmentTickCount();
312
313 // This can be 0 in the very unusual case that the timer wrapped
314 // It can be 0 if we try add tokens at a sub-tick rate
315 if (deltaMS <= 0)
316 return;
317
318 Deposit(deltaMS * DripRate / m_ticksPerQuantum);
319 }
320 }
321
322 public class AdaptiveTokenBucket : TokenBucket
323 {
324// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
325
326 /// <summary>
327 /// The minimum rate for flow control. Minimum drip rate is one
328 /// packet per second. Open the throttle to 15 packets per second
329 /// or about 160kbps.
330 /// </summary>
331 protected const Int64 m_minimumFlow = m_minimumDripRate * 15;
332
333 // <summary>
334 // The maximum rate for flow control. Drip rate can never be
335 // greater than this.
336 // </summary>
337 protected Int64 m_maxDripRate = 0;
338 protected Int64 MaxDripRate
339 {
340 get { return (m_maxDripRate == 0 ? m_totalDripRequest : m_maxDripRate); }
341 set { m_maxDripRate = (value == 0 ? 0 : Math.Max(value,m_minimumFlow)); }
342 }
343
344 private bool m_enabled = false;
345
346 // <summary>
347 //
348 // </summary>
349 public virtual Int64 AdjustedDripRate
350 {
351 get { return m_dripRate; }
352 set {
353 m_dripRate = OpenSim.Framework.Util.Clamp<Int64>(value,m_minimumFlow,MaxDripRate);
354 m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst);
355 if (m_parent != null)
356 m_parent.RegisterRequest(this,m_dripRate);
357 }
358 }
359
360 // <summary>
361 //
362 // </summary>
363 public AdaptiveTokenBucket(TokenBucket parent, Int64 maxDripRate, bool enabled) : base(parent,maxDripRate)
364 {
365 m_enabled = enabled;
366
367 if (m_enabled)
368 {
369 // m_log.DebugFormat("[TOKENBUCKET] Adaptive throttle enabled");
370 MaxDripRate = maxDripRate;
371 AdjustedDripRate = m_minimumFlow;
372 }
373 }
374
375 // <summary>
376 //
377 // </summary>
378 public void ExpirePackets(Int32 count)
379 {
380 // m_log.WarnFormat("[ADAPTIVEBUCKET] drop {0} by {1} expired packets",AdjustedDripRate,count);
381 if (m_enabled)
382 AdjustedDripRate = (Int64) (AdjustedDripRate / Math.Pow(2,count));
383 }
384
385 // <summary>
386 //
387 // </summary>
388 public void AcknowledgePackets(Int32 count)
389 {
390 if (m_enabled)
391 AdjustedDripRate = AdjustedDripRate + count;
392 }
393 }
394}
diff --git a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs b/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs
index e43f7cf..9d6c09e 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs
@@ -1,4 +1,4 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
@@ -28,6 +28,7 @@
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Net; 30using System.Net;
31using System.Threading;
31using OpenMetaverse; 32using OpenMetaverse;
32 33
33namespace OpenSim.Region.ClientStack.LindenUDP 34namespace OpenSim.Region.ClientStack.LindenUDP
@@ -64,7 +65,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
64 /// <summary>Holds packets that need to be added to the unacknowledged list</summary> 65 /// <summary>Holds packets that need to be added to the unacknowledged list</summary>
65 private LocklessQueue<OutgoingPacket> m_pendingAdds = new LocklessQueue<OutgoingPacket>(); 66 private LocklessQueue<OutgoingPacket> m_pendingAdds = new LocklessQueue<OutgoingPacket>();
66 /// <summary>Holds information about pending acknowledgements</summary> 67 /// <summary>Holds information about pending acknowledgements</summary>
67 private LocklessQueue<PendingAck> m_pendingRemoves = new LocklessQueue<PendingAck>(); 68 private LocklessQueue<PendingAck> m_pendingAcknowledgements = new LocklessQueue<PendingAck>();
69 /// <summary>Holds information about pending removals</summary>
70 private LocklessQueue<uint> m_pendingRemoves = new LocklessQueue<uint>();
68 71
69 /// <summary> 72 /// <summary>
70 /// Add an unacked packet to the collection 73 /// Add an unacked packet to the collection
@@ -77,31 +80,55 @@ namespace OpenSim.Region.ClientStack.LindenUDP
77 public void Add(OutgoingPacket packet) 80 public void Add(OutgoingPacket packet)
78 { 81 {
79 m_pendingAdds.Enqueue(packet); 82 m_pendingAdds.Enqueue(packet);
83 Interlocked.Add(ref packet.Client.UnackedBytes, packet.Buffer.DataLength);
80 } 84 }
81 85
82 /// <summary> 86 /// <summary>
83 /// Marks a packet as acknowledged 87 /// Marks a packet as acknowledged
88 /// This method is used when an acknowledgement is received from the network for a previously
89 /// sent packet. Effects of removal this way are to update unacked byte count, adjust RTT
90 /// and increase throttle to the coresponding client.
84 /// </summary> 91 /// </summary>
85 /// <param name="sequenceNumber">Sequence number of the packet to 92 /// <param name="sequenceNumber">Sequence number of the packet to
86 /// acknowledge</param> 93 /// acknowledge</param>
87 /// <param name="currentTime">Current value of Environment.TickCount</param> 94 /// <param name="currentTime">Current value of Environment.TickCount</param>
88 /// <remarks>This does not immediately acknowledge the packet, it only 95 /// <remarks>This does not immediately acknowledge the packet, it only
89 /// queues the ack so it can be handled in a thread-safe way later</remarks> 96 /// queues the ack so it can be handled in a thread-safe way later</remarks>
90 public void Remove(uint sequenceNumber, int currentTime, bool fromResend) 97 public void Acknowledge(uint sequenceNumber, int currentTime, bool fromResend)
91 { 98 {
92 m_pendingRemoves.Enqueue(new PendingAck(sequenceNumber, currentTime, fromResend)); 99 m_pendingAcknowledgements.Enqueue(new PendingAck(sequenceNumber, currentTime, fromResend));
100 }
101
102 /// <summary>
103 /// Marks a packet as no longer needing acknowledgement without a received acknowledgement.
104 /// This method is called when a packet expires and we no longer need an acknowledgement.
105 /// When some reliable packet types expire, they are handled in a way other than simply
106 /// resending them. The only effect of removal this way is to update unacked byte count.
107 /// </summary>
108 /// <param name="sequenceNumber">Sequence number of the packet to
109 /// acknowledge</param>
110 /// <remarks>The does not immediately remove the packet, it only queues the removal
111 /// so it can be handled in a thread safe way later</remarks>
112 public void Remove(uint sequenceNumber)
113 {
114 m_pendingRemoves.Enqueue(sequenceNumber);
93 } 115 }
94 116
95 /// <summary> 117 /// <summary>
96 /// Returns a list of all of the packets with a TickCount older than 118 /// Returns a list of all of the packets with a TickCount older than
97 /// the specified timeout 119 /// the specified timeout
98 /// </summary> 120 /// </summary>
121 /// <remarks>
122 /// This function is not thread safe, and cannot be called
123 /// multiple times concurrently
124 /// </remarks>
99 /// <param name="timeoutMS">Number of ticks (milliseconds) before a 125 /// <param name="timeoutMS">Number of ticks (milliseconds) before a
100 /// packet is considered expired</param> 126 /// packet is considered expired
101 /// <returns>A list of all expired packets according to the given 127 /// </param>
102 /// expiration timeout</returns> 128 /// <returns>
103 /// <remarks>This function is not thread safe, and cannot be called 129 /// A list of all expired packets according to the given
104 /// multiple times concurrently</remarks> 130 /// expiration timeout
131 /// </returns>
105 public List<OutgoingPacket> GetExpiredPackets(int timeoutMS) 132 public List<OutgoingPacket> GetExpiredPackets(int timeoutMS)
106 { 133 {
107 ProcessQueues(); 134 ProcessQueues();
@@ -128,11 +155,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
128 // is actually sent out again 155 // is actually sent out again
129 packet.TickCount = 0; 156 packet.TickCount = 0;
130 157
158 // As with other network applications, assume that an expired packet is
159 // an indication of some network problem, slow transmission
160 packet.Client.FlowThrottle.ExpirePackets(1);
161
131 expiredPackets.Add(packet); 162 expiredPackets.Add(packet);
132 } 163 }
133 } 164 }
134 } 165 }
135 166
167 //if (expiredPackets != null)
168 // m_log.DebugFormat("[UNACKED PACKET COLLECTION]: Found {0} expired packets on timeout of {1}", expiredPackets.Count, timeoutMS);
169
136 return expiredPackets; 170 return expiredPackets;
137 } 171 }
138 172
@@ -140,30 +174,59 @@ namespace OpenSim.Region.ClientStack.LindenUDP
140 { 174 {
141 // Process all the pending adds 175 // Process all the pending adds
142 OutgoingPacket pendingAdd; 176 OutgoingPacket pendingAdd;
143 while (m_pendingAdds.Dequeue(out pendingAdd)) 177 while (m_pendingAdds.TryDequeue(out pendingAdd))
144 m_packets[pendingAdd.SequenceNumber] = pendingAdd; 178 if (pendingAdd != null)
145 179 m_packets[pendingAdd.SequenceNumber] = pendingAdd;
180
146 // Process all the pending removes, including updating statistics and round-trip times 181 // Process all the pending removes, including updating statistics and round-trip times
147 PendingAck pendingRemove; 182 PendingAck pendingAcknowledgement;
148 OutgoingPacket ackedPacket; 183 while (m_pendingAcknowledgements.TryDequeue(out pendingAcknowledgement))
149 while (m_pendingRemoves.Dequeue(out pendingRemove))
150 { 184 {
151 if (m_packets.TryGetValue(pendingRemove.SequenceNumber, out ackedPacket)) 185 //m_log.DebugFormat("[UNACKED PACKET COLLECTION]: Processing ack {0}", pendingAcknowledgement.SequenceNumber);
186 OutgoingPacket ackedPacket;
187 if (m_packets.TryGetValue(pendingAcknowledgement.SequenceNumber, out ackedPacket))
152 { 188 {
153 m_packets.Remove(pendingRemove.SequenceNumber); 189 if (ackedPacket != null)
154 190 {
155 // Update stats 191 m_packets.Remove(pendingAcknowledgement.SequenceNumber);
156 System.Threading.Interlocked.Add(ref ackedPacket.Client.UnackedBytes, -ackedPacket.Buffer.DataLength); 192
193 // As with other network applications, assume that an acknowledged packet is an
194 // indication that the network can handle a little more load, speed up the transmission
195 ackedPacket.Client.FlowThrottle.AcknowledgePackets(ackedPacket.Buffer.DataLength);
196
197 // Update stats
198 Interlocked.Add(ref ackedPacket.Client.UnackedBytes, -ackedPacket.Buffer.DataLength);
199
200 if (!pendingAcknowledgement.FromResend)
201 {
202 // Calculate the round-trip time for this packet and its ACK
203 int rtt = pendingAcknowledgement.RemoveTime - ackedPacket.TickCount;
204 if (rtt > 0)
205 ackedPacket.Client.UpdateRoundTrip(rtt);
206 }
207 }
208 else
209 {
210 //m_log.WarnFormat("[UNACKED PACKET COLLECTION]: Could not find packet with sequence number {0} to ack", pendingAcknowledgement.SequenceNumber);
211 }
212 }
213 }
157 214
158 if (!pendingRemove.FromResend) 215 uint pendingRemove;
216 while(m_pendingRemoves.TryDequeue(out pendingRemove))
217 {
218 OutgoingPacket removedPacket;
219 if (m_packets.TryGetValue(pendingRemove, out removedPacket))
220 {
221 if (removedPacket != null)
159 { 222 {
160 // Calculate the round-trip time for this packet and its ACK 223 m_packets.Remove(pendingRemove);
161 int rtt = pendingRemove.RemoveTime - ackedPacket.TickCount; 224
162 if (rtt > 0) 225 // Update stats
163 ackedPacket.Client.UpdateRoundTrip(rtt); 226 Interlocked.Add(ref removedPacket.Client.UnackedBytes, -removedPacket.Buffer.DataLength);
164 } 227 }
165 } 228 }
166 } 229 }
167 } 230 }
168 } 231 }
169} 232} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLFileTransfer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLFileTransfer.cs
deleted file mode 100644
index adf171e..0000000
--- a/OpenSim/Region/ClientStack/LindenUDP/LLFileTransfer.cs
+++ /dev/null
@@ -1,365 +0,0 @@
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 OpenSim.Framework;
32
33namespace OpenSim.Region.ClientStack.LindenUDP
34{
35 /// <summary>
36 /// A work in progress, to contain the SL specific file transfer code that is currently in various region modules
37 /// This file currently contains multiple classes that need to be split out into their own files.
38 /// </summary>
39 public class LLFileTransfer : IClientFileTransfer
40 {
41 protected IClientAPI m_clientAPI;
42
43 /// Dictionary of handlers for uploading files from client
44 /// TODO: Need to add cleanup code to remove handlers that have completed their upload
45 protected Dictionary<ulong, XferUploadHandler> m_uploadHandlers;
46 protected object m_uploadHandlersLock = new object();
47
48
49 /// <summary>
50 /// Dictionary of files ready to be sent to clients
51 /// </summary>
52 protected static Dictionary<string, byte[]> m_files;
53
54 /// <summary>
55 /// Dictionary of Download Transfers in progess
56 /// </summary>
57 protected Dictionary<ulong, XferDownloadHandler> m_downloadHandlers = new Dictionary<ulong, XferDownloadHandler>();
58
59
60 public LLFileTransfer(IClientAPI clientAPI)
61 {
62 m_uploadHandlers = new Dictionary<ulong, XferUploadHandler>();
63 m_clientAPI = clientAPI;
64
65 m_clientAPI.OnXferReceive += XferReceive;
66 m_clientAPI.OnAbortXfer += AbortXferUploadHandler;
67 }
68
69 public void Close()
70 {
71 if (m_clientAPI != null)
72 {
73 m_clientAPI.OnXferReceive -= XferReceive;
74 m_clientAPI.OnAbortXfer -= AbortXferUploadHandler;
75 m_clientAPI = null;
76 }
77 }
78
79 #region Upload Handling
80
81 public bool RequestUpload(string clientFileName, UploadComplete uploadCompleteCallback, UploadAborted abortCallback)
82 {
83 if ((String.IsNullOrEmpty(clientFileName)) || (uploadCompleteCallback == null))
84 {
85 return false;
86 }
87
88 XferUploadHandler uploader = new XferUploadHandler(m_clientAPI, clientFileName);
89
90 return StartUpload(uploader, uploadCompleteCallback, abortCallback);
91 }
92
93 public bool RequestUpload(UUID fileID, UploadComplete uploadCompleteCallback, UploadAborted abortCallback)
94 {
95 if ((fileID == UUID.Zero) || (uploadCompleteCallback == null))
96 {
97 return false;
98 }
99
100 XferUploadHandler uploader = new XferUploadHandler(m_clientAPI, fileID);
101
102 return StartUpload(uploader, uploadCompleteCallback, abortCallback);
103 }
104
105 private bool StartUpload(XferUploadHandler uploader, UploadComplete uploadCompleteCallback, UploadAborted abortCallback)
106 {
107 uploader.UploadDone += uploadCompleteCallback;
108 uploader.UploadDone += RemoveXferUploadHandler;
109
110 if (abortCallback != null)
111 {
112 uploader.UploadAborted += abortCallback;
113 }
114
115 lock (m_uploadHandlersLock)
116 {
117 if (!m_uploadHandlers.ContainsKey(uploader.XferID))
118 {
119 m_uploadHandlers.Add(uploader.XferID, uploader);
120 uploader.RequestStartXfer(m_clientAPI);
121 return true;
122 }
123 else
124 {
125 // something went wrong with the xferID allocation
126 uploader.UploadDone -= uploadCompleteCallback;
127 uploader.UploadDone -= RemoveXferUploadHandler;
128 if (abortCallback != null)
129 {
130 uploader.UploadAborted -= abortCallback;
131 }
132 return false;
133 }
134 }
135 }
136
137 protected void AbortXferUploadHandler(IClientAPI remoteClient, ulong xferID)
138 {
139 lock (m_uploadHandlersLock)
140 {
141 if (m_uploadHandlers.ContainsKey(xferID))
142 {
143 m_uploadHandlers[xferID].AbortUpload(remoteClient);
144 m_uploadHandlers.Remove(xferID);
145 }
146 }
147 }
148
149 protected void XferReceive(IClientAPI remoteClient, ulong xferID, uint packetID, byte[] data)
150 {
151 lock (m_uploadHandlersLock)
152 {
153 if (m_uploadHandlers.ContainsKey(xferID))
154 {
155 m_uploadHandlers[xferID].XferReceive(remoteClient, xferID, packetID, data);
156 }
157 }
158 }
159
160 protected void RemoveXferUploadHandler(string filename, UUID fileID, ulong transferID, byte[] fileData, IClientAPI remoteClient)
161 {
162
163 }
164 #endregion
165
166 }
167
168 public class XferUploadHandler
169 {
170 private AssetBase m_asset;
171
172 public event UploadComplete UploadDone;
173 public event UploadAborted UploadAborted;
174
175 private sbyte type = 0;
176
177 public ulong mXferID;
178 private UploadComplete handlerUploadDone;
179 private UploadAborted handlerAbort;
180
181 private bool m_complete = false;
182
183 public bool UploadComplete
184 {
185 get { return m_complete; }
186 }
187
188 public XferUploadHandler(IClientAPI pRemoteClient, string pClientFilename)
189 {
190 Initialise(UUID.Zero, pClientFilename);
191 }
192
193 public XferUploadHandler(IClientAPI pRemoteClient, UUID fileID)
194 {
195 Initialise(fileID, String.Empty);
196 }
197
198 private void Initialise(UUID fileID, string fileName)
199 {
200 m_asset = new AssetBase(fileID, fileName, type);
201 m_asset.Data = new byte[0];
202 m_asset.Description = "empty";
203 m_asset.Local = true;
204 m_asset.Temporary = true;
205 mXferID = Util.GetNextXferID();
206 }
207
208 public ulong XferID
209 {
210 get { return mXferID; }
211 }
212
213 public void RequestStartXfer(IClientAPI pRemoteClient)
214 {
215 if (!String.IsNullOrEmpty(m_asset.Name))
216 {
217 pRemoteClient.SendXferRequest(mXferID, m_asset.Type, m_asset.FullID, 0, Utils.StringToBytes(m_asset.Name));
218 }
219 else
220 {
221 pRemoteClient.SendXferRequest(mXferID, m_asset.Type, m_asset.FullID, 0, new byte[0]);
222 }
223 }
224
225 /// <summary>
226 /// Process transfer data received from the client.
227 /// </summary>
228 /// <param name="xferID"></param>
229 /// <param name="packetID"></param>
230 /// <param name="data"></param>
231 public void XferReceive(IClientAPI remoteClient, ulong xferID, uint packetID, byte[] data)
232 {
233 if (mXferID == xferID)
234 {
235 if (m_asset.Data.Length > 1)
236 {
237 byte[] destinationArray = new byte[m_asset.Data.Length + data.Length];
238 Array.Copy(m_asset.Data, 0, destinationArray, 0, m_asset.Data.Length);
239 Array.Copy(data, 0, destinationArray, m_asset.Data.Length, data.Length);
240 m_asset.Data = destinationArray;
241 }
242 else
243 {
244 byte[] buffer2 = new byte[data.Length - 4];
245 Array.Copy(data, 4, buffer2, 0, data.Length - 4);
246 m_asset.Data = buffer2;
247 }
248
249 remoteClient.SendConfirmXfer(xferID, packetID);
250
251 if ((packetID & 0x80000000) != 0)
252 {
253 SendCompleteMessage(remoteClient);
254
255 }
256 }
257 }
258
259 protected void SendCompleteMessage(IClientAPI remoteClient)
260 {
261 m_complete = true;
262 handlerUploadDone = UploadDone;
263 if (handlerUploadDone != null)
264 {
265 handlerUploadDone(m_asset.Name, m_asset.FullID, mXferID, m_asset.Data, remoteClient);
266 }
267 }
268
269 public void AbortUpload(IClientAPI remoteClient)
270 {
271 handlerAbort = UploadAborted;
272 if (handlerAbort != null)
273 {
274 handlerAbort(m_asset.Name, m_asset.FullID, mXferID, remoteClient);
275 }
276 }
277 }
278
279 public class XferDownloadHandler
280 {
281 public IClientAPI Client;
282 private bool complete;
283 public byte[] Data = new byte[0];
284 public int DataPointer = 0;
285 public string FileName = String.Empty;
286 public uint Packet = 0;
287 public uint Serial = 1;
288 public ulong XferID = 0;
289
290 public XferDownloadHandler(string fileName, byte[] data, ulong xferID, IClientAPI client)
291 {
292 FileName = fileName;
293 Data = data;
294 XferID = xferID;
295 Client = client;
296 }
297
298 public XferDownloadHandler()
299 {
300 }
301
302 /// <summary>
303 /// Start a transfer
304 /// </summary>
305 /// <returns>True if the transfer is complete, false if not</returns>
306 public bool StartSend()
307 {
308 if (Data.Length < 1000)
309 {
310 // for now (testing) we only support files under 1000 bytes
311 byte[] transferData = new byte[Data.Length + 4];
312 Array.Copy(Utils.IntToBytes(Data.Length), 0, transferData, 0, 4);
313 Array.Copy(Data, 0, transferData, 4, Data.Length);
314 Client.SendXferPacket(XferID, 0 + 0x80000000, transferData);
315
316 complete = true;
317 }
318 else
319 {
320 byte[] transferData = new byte[1000 + 4];
321 Array.Copy(Utils.IntToBytes(Data.Length), 0, transferData, 0, 4);
322 Array.Copy(Data, 0, transferData, 4, 1000);
323 Client.SendXferPacket(XferID, 0, transferData);
324 Packet++;
325 DataPointer = 1000;
326 }
327
328 return complete;
329 }
330
331 /// <summary>
332 /// Respond to an ack packet from the client
333 /// </summary>
334 /// <param name="packet"></param>
335 /// <returns>True if the transfer is complete, false otherwise</returns>
336 public bool AckPacket(uint packet)
337 {
338 if (!complete)
339 {
340 if ((Data.Length - DataPointer) > 1000)
341 {
342 byte[] transferData = new byte[1000];
343 Array.Copy(Data, DataPointer, transferData, 0, 1000);
344 Client.SendXferPacket(XferID, Packet, transferData);
345 Packet++;
346 DataPointer += 1000;
347 }
348 else
349 {
350 byte[] transferData = new byte[Data.Length - DataPointer];
351 Array.Copy(Data, DataPointer, transferData, 0, Data.Length - DataPointer);
352 uint endPacket = Packet |= (uint)0x80000000;
353 Client.SendXferPacket(XferID, endPacket, transferData);
354 Packet++;
355 DataPointer += (Data.Length - DataPointer);
356
357 complete = true;
358 }
359 }
360
361 return complete;
362 }
363 }
364
365}
diff --git a/OpenSim/Region/ClientStack/LindenUDP/Tests/BasicCircuitTests.cs b/OpenSim/Region/ClientStack/LindenUDP/Tests/BasicCircuitTests.cs
deleted file mode 100644
index daab84f..0000000
--- a/OpenSim/Region/ClientStack/LindenUDP/Tests/BasicCircuitTests.cs
+++ /dev/null
@@ -1,299 +0,0 @@
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.Net;
29using log4net.Config;
30using Nini.Config;
31using NUnit.Framework;
32using NUnit.Framework.SyntaxHelpers;
33using OpenMetaverse;
34using OpenMetaverse.Packets;
35using OpenSim.Framework;
36using OpenSim.Tests.Common;
37using OpenSim.Tests.Common.Mock;
38
39namespace OpenSim.Region.ClientStack.LindenUDP.Tests
40{
41 /// <summary>
42 /// This will contain basic tests for the LindenUDP client stack
43 /// </summary>
44 [TestFixture]
45 public class BasicCircuitTests
46 {
47 [SetUp]
48 public void Init()
49 {
50 try
51 {
52 XmlConfigurator.Configure();
53 }
54 catch
55 {
56 // I don't care, just leave log4net off
57 }
58 }
59
60 /// <summary>
61 /// Add a client for testing
62 /// </summary>
63 /// <param name="scene"></param>
64 /// <param name="testLLUDPServer"></param>
65 /// <param name="testPacketServer"></param>
66 /// <param name="acm">Agent circuit manager used in setting up the stack</param>
67 protected void SetupStack(
68 IScene scene, out TestLLUDPServer testLLUDPServer, out TestLLPacketServer testPacketServer,
69 out AgentCircuitManager acm)
70 {
71 IConfigSource configSource = new IniConfigSource();
72 ClientStackUserSettings userSettings = new ClientStackUserSettings();
73 testLLUDPServer = new TestLLUDPServer();
74 acm = new AgentCircuitManager();
75
76 uint port = 666;
77 testLLUDPServer.Initialise(null, ref port, 0, false, configSource, acm);
78 testPacketServer = new TestLLPacketServer(testLLUDPServer, userSettings);
79 testLLUDPServer.LocalScene = scene;
80 }
81
82 /// <summary>
83 /// Set up a client for tests which aren't concerned with this process itself and where only one client is being
84 /// tested
85 /// </summary>
86 /// <param name="circuitCode"></param>
87 /// <param name="epSender"></param>
88 /// <param name="testLLUDPServer"></param>
89 /// <param name="acm"></param>
90 protected void AddClient(
91 uint circuitCode, EndPoint epSender, TestLLUDPServer testLLUDPServer, AgentCircuitManager acm)
92 {
93 UUID myAgentUuid = UUID.Parse("00000000-0000-0000-0000-000000000001");
94 UUID mySessionUuid = UUID.Parse("00000000-0000-0000-0000-000000000002");
95
96 AddClient(circuitCode, epSender, myAgentUuid, mySessionUuid, testLLUDPServer, acm);
97 }
98
99 /// <summary>
100 /// Set up a client for tests which aren't concerned with this process itself
101 /// </summary>
102 /// <param name="circuitCode"></param>
103 /// <param name="epSender"></param>
104 /// <param name="agentId"></param>
105 /// <param name="sessionId"></param>
106 /// <param name="testLLUDPServer"></param>
107 /// <param name="acm"></param>
108 protected void AddClient(
109 uint circuitCode, EndPoint epSender, UUID agentId, UUID sessionId,
110 TestLLUDPServer testLLUDPServer, AgentCircuitManager acm)
111 {
112 AgentCircuitData acd = new AgentCircuitData();
113 acd.AgentID = agentId;
114 acd.SessionID = sessionId;
115
116 UseCircuitCodePacket uccp = new UseCircuitCodePacket();
117
118 UseCircuitCodePacket.CircuitCodeBlock uccpCcBlock
119 = new UseCircuitCodePacket.CircuitCodeBlock();
120 uccpCcBlock.Code = circuitCode;
121 uccpCcBlock.ID = agentId;
122 uccpCcBlock.SessionID = sessionId;
123 uccp.CircuitCode = uccpCcBlock;
124
125 acm.AddNewCircuit(circuitCode, acd);
126
127 testLLUDPServer.LoadReceive(uccp, epSender);
128 testLLUDPServer.ReceiveData(null);
129 }
130
131 /// <summary>
132 /// Build an object name packet for test purposes
133 /// </summary>
134 /// <param name="objectLocalId"></param>
135 /// <param name="objectName"></param>
136 protected ObjectNamePacket BuildTestObjectNamePacket(uint objectLocalId, string objectName)
137 {
138 ObjectNamePacket onp = new ObjectNamePacket();
139 ObjectNamePacket.ObjectDataBlock odb = new ObjectNamePacket.ObjectDataBlock();
140 odb.LocalID = objectLocalId;
141 odb.Name = Utils.StringToBytes(objectName);
142 onp.ObjectData = new ObjectNamePacket.ObjectDataBlock[] { odb };
143 onp.Header.Zerocoded = false;
144
145 return onp;
146 }
147
148 /// <summary>
149 /// Test adding a client to the stack
150 /// </summary>
151 [Test, LongRunning]
152 public void TestAddClient()
153 {
154 TestHelper.InMethod();
155
156 uint myCircuitCode = 123456;
157 UUID myAgentUuid = UUID.Parse("00000000-0000-0000-0000-000000000001");
158 UUID mySessionUuid = UUID.Parse("00000000-0000-0000-0000-000000000002");
159
160 TestLLUDPServer testLLUDPServer;
161 TestLLPacketServer testLLPacketServer;
162 AgentCircuitManager acm;
163 SetupStack(new MockScene(), out testLLUDPServer, out testLLPacketServer, out acm);
164
165 AgentCircuitData acd = new AgentCircuitData();
166 acd.AgentID = myAgentUuid;
167 acd.SessionID = mySessionUuid;
168
169 UseCircuitCodePacket uccp = new UseCircuitCodePacket();
170
171 UseCircuitCodePacket.CircuitCodeBlock uccpCcBlock
172 = new UseCircuitCodePacket.CircuitCodeBlock();
173 uccpCcBlock.Code = myCircuitCode;
174 uccpCcBlock.ID = myAgentUuid;
175 uccpCcBlock.SessionID = mySessionUuid;
176 uccp.CircuitCode = uccpCcBlock;
177
178 EndPoint testEp = new IPEndPoint(IPAddress.Loopback, 999);
179
180 testLLUDPServer.LoadReceive(uccp, testEp);
181 testLLUDPServer.ReceiveData(null);
182
183 // Circuit shouildn't exist since the circuit manager doesn't know about this circuit for authentication yet
184 Assert.IsFalse(testLLUDPServer.HasCircuit(myCircuitCode));
185
186 acm.AddNewCircuit(myCircuitCode, acd);
187
188 testLLUDPServer.LoadReceive(uccp, testEp);
189 testLLUDPServer.ReceiveData(null);
190
191 // Should succeed now
192 Assert.IsTrue(testLLUDPServer.HasCircuit(myCircuitCode));
193 Assert.IsFalse(testLLUDPServer.HasCircuit(101));
194 }
195
196 /// <summary>
197 /// Test removing a client from the stack
198 /// </summary>
199 [Test]
200 public void TestRemoveClient()
201 {
202 TestHelper.InMethod();
203
204 uint myCircuitCode = 123457;
205
206 TestLLUDPServer testLLUDPServer;
207 TestLLPacketServer testLLPacketServer;
208 AgentCircuitManager acm;
209 SetupStack(new MockScene(), out testLLUDPServer, out testLLPacketServer, out acm);
210 AddClient(myCircuitCode, new IPEndPoint(IPAddress.Loopback, 1000), testLLUDPServer, acm);
211
212 testLLUDPServer.RemoveClientCircuit(myCircuitCode);
213 Assert.IsFalse(testLLUDPServer.HasCircuit(myCircuitCode));
214
215 // Check that removing a non-existant circuit doesn't have any bad effects
216 testLLUDPServer.RemoveClientCircuit(101);
217 Assert.IsFalse(testLLUDPServer.HasCircuit(101));
218 }
219
220 /// <summary>
221 /// Make sure that the client stack reacts okay to malformed packets
222 /// </summary>
223 [Test]
224 public void TestMalformedPacketSend()
225 {
226 TestHelper.InMethod();
227
228 uint myCircuitCode = 123458;
229 EndPoint testEp = new IPEndPoint(IPAddress.Loopback, 1001);
230 MockScene scene = new MockScene();
231
232 TestLLUDPServer testLLUDPServer;
233 TestLLPacketServer testLLPacketServer;
234 AgentCircuitManager acm;
235 SetupStack(scene, out testLLUDPServer, out testLLPacketServer, out acm);
236 AddClient(myCircuitCode, testEp, testLLUDPServer, acm);
237
238 byte[] data = new byte[] { 0x01, 0x02, 0x03, 0x04 };
239
240 // Send two garbled 'packets' in succession
241 testLLUDPServer.LoadReceive(data, testEp);
242 testLLUDPServer.LoadReceive(data, testEp);
243 testLLUDPServer.ReceiveData(null);
244
245 // Check that we are still here
246 Assert.IsTrue(testLLUDPServer.HasCircuit(myCircuitCode));
247 Assert.That(testLLPacketServer.GetTotalPacketsReceived(), Is.EqualTo(0));
248
249 // Check that sending a valid packet to same circuit still succeeds
250 Assert.That(scene.ObjectNameCallsReceived, Is.EqualTo(0));
251
252 testLLUDPServer.LoadReceive(BuildTestObjectNamePacket(1, "helloooo"), testEp);
253 testLLUDPServer.ReceiveData(null);
254
255 Assert.That(testLLPacketServer.GetTotalPacketsReceived(), Is.EqualTo(1));
256 Assert.That(testLLPacketServer.GetPacketsReceivedFor(PacketType.ObjectName), Is.EqualTo(1));
257 }
258
259 /// <summary>
260 /// Test that the stack continues to work even if some client has caused a
261 /// SocketException on Socket.BeginReceive()
262 /// </summary>
263 [Test]
264 public void TestExceptionOnBeginReceive()
265 {
266 TestHelper.InMethod();
267
268 MockScene scene = new MockScene();
269
270 uint circuitCodeA = 130000;
271 EndPoint epA = new IPEndPoint(IPAddress.Loopback, 1300);
272 UUID agentIdA = UUID.Parse("00000000-0000-0000-0000-000000001300");
273 UUID sessionIdA = UUID.Parse("00000000-0000-0000-0000-000000002300");
274
275 uint circuitCodeB = 130001;
276 EndPoint epB = new IPEndPoint(IPAddress.Loopback, 1301);
277 UUID agentIdB = UUID.Parse("00000000-0000-0000-0000-000000001301");
278 UUID sessionIdB = UUID.Parse("00000000-0000-0000-0000-000000002301");
279
280 TestLLUDPServer testLLUDPServer;
281 TestLLPacketServer testLLPacketServer;
282 AgentCircuitManager acm;
283 SetupStack(scene, out testLLUDPServer, out testLLPacketServer, out acm);
284 AddClient(circuitCodeA, epA, agentIdA, sessionIdA, testLLUDPServer, acm);
285 AddClient(circuitCodeB, epB, agentIdB, sessionIdB, testLLUDPServer, acm);
286
287 testLLUDPServer.LoadReceive(BuildTestObjectNamePacket(1, "packet1"), epA);
288 testLLUDPServer.LoadReceive(BuildTestObjectNamePacket(1, "packet2"), epB);
289 testLLUDPServer.LoadReceiveWithBeginException(epA);
290 testLLUDPServer.LoadReceive(BuildTestObjectNamePacket(2, "packet3"), epB);
291 testLLUDPServer.ReceiveData(null);
292
293 Assert.IsFalse(testLLUDPServer.HasCircuit(circuitCodeA));
294
295 Assert.That(testLLPacketServer.GetTotalPacketsReceived(), Is.EqualTo(3));
296 Assert.That(testLLPacketServer.GetPacketsReceivedFor(PacketType.ObjectName), Is.EqualTo(3));
297 }
298 }
299}
diff --git a/OpenSim/Region/ClientStack/LindenUDP/Tests/PacketHandlerTests.cs b/OpenSim/Region/ClientStack/LindenUDP/Tests/PacketHandlerTests.cs
deleted file mode 100644
index 7d0757f..0000000
--- a/OpenSim/Region/ClientStack/LindenUDP/Tests/PacketHandlerTests.cs
+++ /dev/null
@@ -1,106 +0,0 @@
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 NUnit.Framework.SyntaxHelpers;
31using OpenMetaverse;
32using OpenMetaverse.Packets;
33using OpenSim.Framework;
34using OpenSim.Tests.Common.Mock;
35using OpenSim.Tests.Common;
36
37namespace OpenSim.Region.ClientStack.LindenUDP.Tests
38{
39 /// <summary>
40 /// Tests for the LL packet handler
41 /// </summary>
42 [TestFixture]
43 public class PacketHandlerTests
44 {
45 [Test]
46 /// <summary>
47 /// More a placeholder, really
48 /// </summary>
49 public void InPacketTest()
50 {
51 TestHelper.InMethod();
52
53 AgentCircuitData agent = new AgentCircuitData();
54 agent.AgentID = UUID.Random();
55 agent.firstname = "testfirstname";
56 agent.lastname = "testlastname";
57 agent.SessionID = UUID.Zero;
58 agent.SecureSessionID = UUID.Zero;
59 agent.circuitcode = 123;
60 agent.BaseFolder = UUID.Zero;
61 agent.InventoryFolder = UUID.Zero;
62 agent.startpos = Vector3.Zero;
63 agent.CapsPath = "http://wibble.com";
64
65 TestLLUDPServer testLLUDPServer;
66 TestLLPacketServer testLLPacketServer;
67 AgentCircuitManager acm;
68 IScene scene = new MockScene();
69 SetupStack(scene, out testLLUDPServer, out testLLPacketServer, out acm);
70
71 TestClient testClient = new TestClient(agent, scene);
72
73 LLPacketHandler packetHandler
74 = new LLPacketHandler(testClient, testLLPacketServer, new ClientStackUserSettings());
75
76 packetHandler.InPacket(new AgentAnimationPacket());
77 LLQueItem receivedPacket = packetHandler.PacketQueue.Dequeue();
78
79 Assert.That(receivedPacket, Is.Not.Null);
80 Assert.That(receivedPacket.Incoming, Is.True);
81 Assert.That(receivedPacket.Packet, Is.TypeOf(typeof(AgentAnimationPacket)));
82 }
83
84 /// <summary>
85 /// Add a client for testing
86 /// </summary>
87 /// <param name="scene"></param>
88 /// <param name="testLLUDPServer"></param>
89 /// <param name="testPacketServer"></param>
90 /// <param name="acm">Agent circuit manager used in setting up the stack</param>
91 protected void SetupStack(
92 IScene scene, out TestLLUDPServer testLLUDPServer, out TestLLPacketServer testPacketServer,
93 out AgentCircuitManager acm)
94 {
95 IConfigSource configSource = new IniConfigSource();
96 ClientStackUserSettings userSettings = new ClientStackUserSettings();
97 testLLUDPServer = new TestLLUDPServer();
98 acm = new AgentCircuitManager();
99
100 uint port = 666;
101 testLLUDPServer.Initialise(null, ref port, 0, false, configSource, acm);
102 testPacketServer = new TestLLPacketServer(testLLUDPServer, userSettings);
103 testLLUDPServer.LocalScene = scene;
104 }
105 }
106}
diff --git a/OpenSim/Region/ClientStack/LindenUDP/Tests/TestLLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/Tests/TestLLUDPServer.cs
deleted file mode 100644
index f98586d..0000000
--- a/OpenSim/Region/ClientStack/LindenUDP/Tests/TestLLUDPServer.cs
+++ /dev/null
@@ -1,153 +0,0 @@
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.Net.Sockets;
32using OpenMetaverse.Packets;
33
34namespace OpenSim.Region.ClientStack.LindenUDP.Tests
35{
36 /// <summary>
37 /// This class enables synchronous testing of the LLUDPServer by allowing us to load our own data into the end
38 /// receive event
39 /// </summary>
40 public class TestLLUDPServer : LLUDPServer
41 {
42 /// <summary>
43 /// The chunks of data to pass to the LLUDPServer when it calls EndReceive
44 /// </summary>
45 protected Queue<ChunkSenderTuple> m_chunksToLoad = new Queue<ChunkSenderTuple>();
46
47 protected override void BeginReceive()
48 {
49 if (m_chunksToLoad.Count > 0 && m_chunksToLoad.Peek().BeginReceiveException)
50 {
51 ChunkSenderTuple tuple = m_chunksToLoad.Dequeue();
52 reusedEpSender = tuple.Sender;
53 throw new SocketException();
54 }
55 }
56
57 protected override bool EndReceive(out int numBytes, IAsyncResult result, ref EndPoint epSender)
58 {
59 numBytes = 0;
60
61 //m_log.Debug("Queue size " + m_chunksToLoad.Count);
62
63 if (m_chunksToLoad.Count <= 0)
64 return false;
65
66 ChunkSenderTuple tuple = m_chunksToLoad.Dequeue();
67 RecvBuffer = tuple.Data;
68 numBytes = tuple.Data.Length;
69 epSender = tuple.Sender;
70
71 return true;
72 }
73
74 public override void SendPacketTo(byte[] buffer, int size, SocketFlags flags, uint circuitcode)
75 {
76 // Don't do anything just yet
77 }
78
79 /// <summary>
80 /// Signal that this chunk should throw an exception on Socket.BeginReceive()
81 /// </summary>
82 /// <param name="epSender"></param>
83 public void LoadReceiveWithBeginException(EndPoint epSender)
84 {
85 ChunkSenderTuple tuple = new ChunkSenderTuple(epSender);
86 tuple.BeginReceiveException = true;
87 m_chunksToLoad.Enqueue(tuple);
88 }
89
90 /// <summary>
91 /// Load some data to be received by the LLUDPServer on the next receive call
92 /// </summary>
93 /// <param name="data"></param>
94 /// <param name="epSender"></param>
95 public void LoadReceive(byte[] data, EndPoint epSender)
96 {
97 m_chunksToLoad.Enqueue(new ChunkSenderTuple(data, epSender));
98 }
99
100 /// <summary>
101 /// Load a packet to be received by the LLUDPServer on the next receive call
102 /// </summary>
103 /// <param name="packet"></param>
104 public void LoadReceive(Packet packet, EndPoint epSender)
105 {
106 LoadReceive(packet.ToBytes(), epSender);
107 }
108
109 /// <summary>
110 /// Calls the protected asynchronous result method. This fires out all data chunks currently queued for send
111 /// </summary>
112 /// <param name="result"></param>
113 public void ReceiveData(IAsyncResult result)
114 {
115 while (m_chunksToLoad.Count > 0)
116 OnReceivedData(result);
117 }
118
119 /// <summary>
120 /// Has a circuit with the given code been established?
121 /// </summary>
122 /// <param name="circuitCode"></param>
123 /// <returns></returns>
124 public bool HasCircuit(uint circuitCode)
125 {
126 lock (clientCircuits_reverse)
127 {
128 return clientCircuits_reverse.ContainsKey(circuitCode);
129 }
130 }
131 }
132
133 /// <summary>
134 /// Record the data and sender tuple
135 /// </summary>
136 public class ChunkSenderTuple
137 {
138 public byte[] Data;
139 public EndPoint Sender;
140 public bool BeginReceiveException;
141
142 public ChunkSenderTuple(byte[] data, EndPoint sender)
143 {
144 Data = data;
145 Sender = sender;
146 }
147
148 public ChunkSenderTuple(EndPoint sender)
149 {
150 Sender = sender;
151 }
152 }
153}
diff --git a/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs
deleted file mode 100644
index bdbd284..0000000
--- a/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs
+++ /dev/null
@@ -1,217 +0,0 @@
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;
29
30namespace OpenSim.Region.ClientStack.LindenUDP
31{
32 /// <summary>
33 /// A hierarchical token bucket for bandwidth throttling. See
34 /// http://en.wikipedia.org/wiki/Token_bucket for more information
35 /// </summary>
36 public class TokenBucket
37 {
38 /// <summary>Parent bucket to this bucket, or null if this is a root
39 /// bucket</summary>
40 TokenBucket parent;
41 /// <summary>Size of the bucket in bytes. If zero, the bucket has
42 /// infinite capacity</summary>
43 int maxBurst;
44 /// <summary>Rate that the bucket fills, in bytes per millisecond. If
45 /// zero, the bucket always remains full</summary>
46 int tokensPerMS;
47 /// <summary>Number of tokens currently in the bucket</summary>
48 int content;
49 /// <summary>Time of the last drip, in system ticks</summary>
50 int lastDrip;
51
52 #region Properties
53
54 /// <summary>
55 /// The parent bucket of this bucket, or null if this bucket has no
56 /// parent. The parent bucket will limit the aggregate bandwidth of all
57 /// of its children buckets
58 /// </summary>
59 public TokenBucket Parent
60 {
61 get { return parent; }
62 }
63
64 /// <summary>
65 /// Maximum burst rate in bytes per second. This is the maximum number
66 /// of tokens that can accumulate in the bucket at any one time
67 /// </summary>
68 public int MaxBurst
69 {
70 get { return maxBurst; }
71 set { maxBurst = (value >= 0 ? value : 0); }
72 }
73
74 /// <summary>
75 /// The speed limit of this bucket in bytes per second. This is the
76 /// number of tokens that are added to the bucket per second
77 /// </summary>
78 /// <remarks>Tokens are added to the bucket any time
79 /// <seealso cref="RemoveTokens"/> is called, at the granularity of
80 /// the system tick interval (typically around 15-22ms)</remarks>
81 public int DripRate
82 {
83 get { return tokensPerMS * 1000; }
84 set
85 {
86 if (value == 0)
87 tokensPerMS = 0;
88 else
89 {
90 int bpms = (int)((float)value / 1000.0f);
91
92 if (bpms <= 0)
93 tokensPerMS = 1; // 1 byte/ms is the minimum granularity
94 else
95 tokensPerMS = bpms;
96 }
97 }
98 }
99
100 /// <summary>
101 /// The speed limit of this bucket in bytes per millisecond
102 /// </summary>
103 public int DripPerMS
104 {
105 get { return tokensPerMS; }
106 }
107
108 /// <summary>
109 /// The number of bytes that can be sent at this moment. This is the
110 /// current number of tokens in the bucket
111 /// <remarks>If this bucket has a parent bucket that does not have
112 /// enough tokens for a request, <seealso cref="RemoveTokens"/> will
113 /// return false regardless of the content of this bucket</remarks>
114 /// </summary>
115 public int Content
116 {
117 get { return content; }
118 }
119
120 #endregion Properties
121
122 /// <summary>
123 /// Default constructor
124 /// </summary>
125 /// <param name="parent">Parent bucket if this is a child bucket, or
126 /// null if this is a root bucket</param>
127 /// <param name="maxBurst">Maximum size of the bucket in bytes, or
128 /// zero if this bucket has no maximum capacity</param>
129 /// <param name="dripRate">Rate that the bucket fills, in bytes per
130 /// second. If zero, the bucket always remains full</param>
131 public TokenBucket(TokenBucket parent, int maxBurst, int dripRate)
132 {
133 this.parent = parent;
134 MaxBurst = maxBurst;
135 DripRate = dripRate;
136 lastDrip = Environment.TickCount & Int32.MaxValue;
137 }
138
139 /// <summary>
140 /// Remove a given number of tokens from the bucket
141 /// </summary>
142 /// <param name="amount">Number of tokens to remove from the bucket</param>
143 /// <returns>True if the requested number of tokens were removed from
144 /// the bucket, otherwise false</returns>
145 public bool RemoveTokens(int amount)
146 {
147 bool dummy;
148 return RemoveTokens(amount, out dummy);
149 }
150
151 /// <summary>
152 /// Remove a given number of tokens from the bucket
153 /// </summary>
154 /// <param name="amount">Number of tokens to remove from the bucket</param>
155 /// <param name="dripSucceeded">True if tokens were added to the bucket
156 /// during this call, otherwise false</param>
157 /// <returns>True if the requested number of tokens were removed from
158 /// the bucket, otherwise false</returns>
159 public bool RemoveTokens(int amount, out bool dripSucceeded)
160 {
161 if (maxBurst == 0)
162 {
163 dripSucceeded = true;
164 return true;
165 }
166
167 dripSucceeded = Drip();
168
169 if (content - amount >= 0)
170 {
171 if (parent != null && !parent.RemoveTokens(amount))
172 return false;
173
174 content -= amount;
175 return true;
176 }
177 else
178 {
179 return false;
180 }
181 }
182
183 /// <summary>
184 /// Add tokens to the bucket over time. The number of tokens added each
185 /// call depends on the length of time that has passed since the last
186 /// call to Drip
187 /// </summary>
188 /// <returns>True if tokens were added to the bucket, otherwise false</returns>
189 public bool Drip()
190 {
191 if (tokensPerMS == 0)
192 {
193 content = maxBurst;
194 return true;
195 }
196 else
197 {
198 int now = Environment.TickCount & Int32.MaxValue;
199 int deltaMS = now - lastDrip;
200
201 if (deltaMS <= 0)
202 {
203 if (deltaMS < 0)
204 lastDrip = now;
205 return false;
206 }
207
208 int dripAmount = deltaMS * tokensPerMS;
209
210 content = Math.Min(content + dripAmount, maxBurst);
211 lastDrip = now;
212
213 return true;
214 }
215 }
216 }
217}
diff --git a/OpenSim/Region/ClientStack/RegionApplicationBase.cs b/OpenSim/Region/ClientStack/RegionApplicationBase.cs
index e57e298..6e3a58e 100644
--- a/OpenSim/Region/ClientStack/RegionApplicationBase.cs
+++ b/OpenSim/Region/ClientStack/RegionApplicationBase.cs
@@ -36,6 +36,7 @@ using OpenSim.Framework.Communications;
36using OpenSim.Framework.Servers; 36using OpenSim.Framework.Servers;
37using OpenSim.Framework.Servers.HttpServer; 37using OpenSim.Framework.Servers.HttpServer;
38using OpenSim.Region.Framework; 38using OpenSim.Region.Framework;
39using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes; 40using OpenSim.Region.Framework.Scenes;
40using OpenSim.Region.Physics.Manager; 41using OpenSim.Region.Physics.Manager;
41 42
@@ -48,30 +49,16 @@ namespace OpenSim.Region.ClientStack
48 49
49 protected Dictionary<EndPoint, uint> m_clientCircuits = new Dictionary<EndPoint, uint>(); 50 protected Dictionary<EndPoint, uint> m_clientCircuits = new Dictionary<EndPoint, uint>();
50 protected NetworkServersInfo m_networkServersInfo; 51 protected NetworkServersInfo m_networkServersInfo;
51
52 public NetworkServersInfo NetServersInfo
53 {
54 get { return m_networkServersInfo; }
55 }
56
57 protected uint m_httpServerPort; 52 protected uint m_httpServerPort;
58 53 protected ISimulationDataService m_simulationDataService;
59 public CommunicationsManager CommunicationsManager 54 protected IEstateDataService m_estateDataService;
60 {
61 get { return m_commsManager; }
62 set { m_commsManager = value; }
63 }
64 protected CommunicationsManager m_commsManager;
65
66 protected StorageManager m_storageManager;
67
68 protected ClientStackManager m_clientStackManager; 55 protected ClientStackManager m_clientStackManager;
69
70 public SceneManager SceneManager
71 {
72 get { return m_sceneManager; }
73 }
74 protected SceneManager m_sceneManager = new SceneManager(); 56 protected SceneManager m_sceneManager = new SceneManager();
57
58 public SceneManager SceneManager { get { return m_sceneManager; } }
59 public NetworkServersInfo NetServersInfo { get { return m_networkServersInfo; } }
60 public ISimulationDataService SimulationDataService { get { return m_simulationDataService; } }
61 public IEstateDataService EstateDataService { get { return m_estateDataService; } }
75 62
76 protected abstract void Initialize(); 63 protected abstract void Initialize();
77 64
@@ -85,15 +72,11 @@ namespace OpenSim.Region.ClientStack
85 /// <returns></returns> 72 /// <returns></returns>
86 protected abstract PhysicsScene GetPhysicsScene(string osSceneIdentifier); 73 protected abstract PhysicsScene GetPhysicsScene(string osSceneIdentifier);
87 74
88 protected abstract StorageManager CreateStorageManager();
89 protected abstract ClientStackManager CreateClientStackManager(); 75 protected abstract ClientStackManager CreateClientStackManager();
90 protected abstract Scene CreateScene(RegionInfo regionInfo, StorageManager storageManager, 76 protected abstract Scene CreateScene(RegionInfo regionInfo, ISimulationDataService simDataService, IEstateDataService estateDataService, AgentCircuitManager circuitManager);
91 AgentCircuitManager circuitManager);
92 77
93 protected override void StartupSpecific() 78 protected override void StartupSpecific()
94 { 79 {
95 m_storageManager = CreateStorageManager();
96
97 m_clientStackManager = CreateClientStackManager(); 80 m_clientStackManager = CreateClientStackManager();
98 81
99 Initialize(); 82 Initialize();
@@ -111,6 +94,24 @@ namespace OpenSim.Region.ClientStack
111 m_log.InfoFormat("[REGION SERVER]: Starting HTTP server on port {0}", m_httpServerPort); 94 m_log.InfoFormat("[REGION SERVER]: Starting HTTP server on port {0}", m_httpServerPort);
112 m_httpServer.Start(); 95 m_httpServer.Start();
113 96
97 MainServer.Instance = m_httpServer;
98
99 // "OOB" Server
100 if (m_networkServersInfo.ssl_listener)
101 {
102 BaseHttpServer server = null;
103 server = new BaseHttpServer(
104 m_networkServersInfo.https_port, m_networkServersInfo.ssl_listener, m_networkServersInfo.cert_path,
105 m_networkServersInfo.cert_pass);
106 // Add the server to m_Servers
107 if(server != null)
108 {
109 m_log.InfoFormat("[REGION SERVER]: Starting HTTPS server on port {0}", server.Port);
110 MainServer.AddHttpServer(server);
111 server.Start();
112 }
113 }
114
114 base.StartupSpecific(); 115 base.StartupSpecific();
115 } 116 }
116 117