diff options
Diffstat (limited to 'OpenSim/Region/ClientStack')
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 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.IO; | ||
32 | using System.Reflection; | ||
33 | using System.Text; | ||
34 | |||
35 | using OpenMetaverse; | ||
36 | using OpenMetaverse.StructuredData; | ||
37 | using Nini.Config; | ||
38 | using log4net; | ||
39 | |||
40 | using OpenSim.Framework; | ||
41 | using OpenSim.Framework.Capabilities; | ||
42 | using OpenSim.Region.Framework; | ||
43 | using OpenSim.Region.Framework.Scenes; | ||
44 | using OpenSim.Region.Framework.Scenes.Serialization; | ||
45 | using OpenSim.Framework.Servers; | ||
46 | using OpenSim.Framework.Servers.HttpServer; | ||
47 | using OpenSim.Services.Interfaces; | ||
48 | |||
49 | using Caps = OpenSim.Framework.Capabilities.Caps; | ||
50 | using OSDArray = OpenMetaverse.StructuredData.OSDArray; | ||
51 | using OSDMap = OpenMetaverse.StructuredData.OSDMap; | ||
52 | |||
53 | namespace 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 | ||
28 | using System; | ||
28 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
29 | using OpenMetaverse.Packets; | 30 | using System.Reflection; |
30 | 31 | ||
31 | namespace OpenSim.Region.ClientStack.LindenUDP.Tests | 32 | using log4net; |
32 | { | 33 | using Nini.Config; |
33 | public class TestLLPacketServer : LLPacketServer | 34 | using OpenMetaverse; |
35 | using Mono.Addins; | ||
36 | |||
37 | using OpenSim.Framework; | ||
38 | using OpenSim.Region.Framework; | ||
39 | using OpenSim.Region.Framework.Interfaces; | ||
40 | using OpenSim.Region.Framework.Scenes; | ||
41 | using Caps = OpenSim.Framework.Capabilities.Caps; | ||
42 | |||
43 | [assembly: Addin("LindenCaps", "0.1")] | ||
44 | [assembly: AddinDependency("OpenSim", "0.5")] | ||
45 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.Net; | ||
32 | using System.Reflection; | ||
33 | using System.Threading; | ||
34 | using log4net; | ||
35 | using Nini.Config; | ||
36 | using Mono.Addins; | ||
37 | using OpenMetaverse; | ||
38 | using OpenMetaverse.Messages.Linden; | ||
39 | using OpenMetaverse.Packets; | ||
40 | using OpenMetaverse.StructuredData; | ||
41 | using OpenSim.Framework; | ||
42 | using OpenSim.Framework.Console; | ||
43 | using OpenSim.Framework.Servers; | ||
44 | using OpenSim.Framework.Servers.HttpServer; | ||
45 | using OpenSim.Region.Framework.Interfaces; | ||
46 | using OpenSim.Region.Framework.Scenes; | ||
47 | using BlockingLLSDQueue = OpenSim.Framework.BlockingQueue<OpenMetaverse.StructuredData.OSD>; | ||
48 | using Caps=OpenSim.Framework.Capabilities.Caps; | ||
49 | |||
50 | namespace 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 | |||
28 | using System; | ||
29 | using System.Net; | ||
30 | using OpenMetaverse; | ||
31 | using OpenMetaverse.Packets; | ||
32 | using OpenMetaverse.StructuredData; | ||
33 | using OpenMetaverse.Messages.Linden; | ||
34 | |||
35 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Net; | ||
31 | using log4net.Config; | ||
32 | using Nini.Config; | ||
33 | using NUnit.Framework; | ||
34 | using OpenMetaverse; | ||
35 | using OpenMetaverse.Packets; | ||
36 | using OpenSim.Framework; | ||
37 | using OpenSim.Framework.Servers; | ||
38 | using OpenSim.Framework.Servers.HttpServer; | ||
39 | using OpenSim.Region.ClientStack.Linden; | ||
40 | using OpenSim.Region.CoreModules.Framework; | ||
41 | using OpenSim.Tests.Common; | ||
42 | using OpenSim.Tests.Common.Mock; | ||
43 | |||
44 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Specialized; | ||
31 | using System.Reflection; | ||
32 | using System.IO; | ||
33 | using System.Web; | ||
34 | using Mono.Addins; | ||
35 | using log4net; | ||
36 | using Nini.Config; | ||
37 | using OpenMetaverse; | ||
38 | using OpenMetaverse.StructuredData; | ||
39 | using OpenSim.Capabilities.Handlers; | ||
40 | using OpenSim.Framework; | ||
41 | using OpenSim.Framework.Servers; | ||
42 | using OpenSim.Framework.Servers.HttpServer; | ||
43 | using OpenSim.Region.Framework.Interfaces; | ||
44 | using OpenSim.Region.Framework.Scenes; | ||
45 | using OpenSim.Services.Interfaces; | ||
46 | using Caps = OpenSim.Framework.Capabilities.Caps; | ||
47 | |||
48 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Specialized; | ||
31 | using System.Drawing; | ||
32 | using System.Drawing.Imaging; | ||
33 | using System.Reflection; | ||
34 | using System.IO; | ||
35 | using System.Web; | ||
36 | using log4net; | ||
37 | using Nini.Config; | ||
38 | using Mono.Addins; | ||
39 | using OpenMetaverse; | ||
40 | using OpenMetaverse.StructuredData; | ||
41 | using OpenMetaverse.Imaging; | ||
42 | using OpenSim.Framework; | ||
43 | using OpenSim.Framework.Servers; | ||
44 | using OpenSim.Framework.Servers.HttpServer; | ||
45 | using OpenSim.Region.Framework.Interfaces; | ||
46 | using OpenSim.Region.Framework.Scenes; | ||
47 | using OpenSim.Services.Interfaces; | ||
48 | using Caps = OpenSim.Framework.Capabilities.Caps; | ||
49 | using OpenSim.Capabilities.Handlers; | ||
50 | |||
51 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Reflection; | ||
31 | using log4net; | ||
32 | using Nini.Config; | ||
33 | using Mono.Addins; | ||
34 | using OpenMetaverse; | ||
35 | using OpenMetaverse.StructuredData; | ||
36 | using OpenSim.Framework; | ||
37 | using OpenSim.Framework.Servers.HttpServer; | ||
38 | using OpenSim.Region.Framework.Interfaces; | ||
39 | using OpenSim.Region.Framework.Scenes; | ||
40 | using OpenSim.Services.Interfaces; | ||
41 | using Caps = OpenSim.Framework.Capabilities.Caps; | ||
42 | |||
43 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Specialized; | ||
31 | using System.Reflection; | ||
32 | using System.IO; | ||
33 | using System.Web; | ||
34 | using Mono.Addins; | ||
35 | using log4net; | ||
36 | using Nini.Config; | ||
37 | using OpenMetaverse; | ||
38 | using OpenMetaverse.StructuredData; | ||
39 | using OpenSim.Framework; | ||
40 | using OpenSim.Framework.Servers; | ||
41 | using OpenSim.Framework.Servers.HttpServer; | ||
42 | using OpenSim.Region.Framework.Interfaces; | ||
43 | using OpenSim.Region.Framework.Scenes; | ||
44 | using OpenSim.Services.Interfaces; | ||
45 | using Caps = OpenSim.Framework.Capabilities.Caps; | ||
46 | using OpenSim.Framework.Capabilities; | ||
47 | |||
48 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Reflection; | ||
31 | using log4net; | ||
32 | using Nini.Config; | ||
33 | using OpenMetaverse; | ||
34 | using OpenMetaverse.StructuredData; | ||
35 | using OpenSim.Framework; | ||
36 | using OpenSim.Framework.Servers; | ||
37 | using OpenSim.Framework.Servers.HttpServer; | ||
38 | using OpenSim.Region.Framework.Interfaces; | ||
39 | using OpenSim.Region.Framework.Scenes; | ||
40 | using Caps=OpenSim.Framework.Capabilities.Caps; | ||
41 | |||
42 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Specialized; | ||
31 | using System.Reflection; | ||
32 | using System.IO; | ||
33 | using System.Web; | ||
34 | using Mono.Addins; | ||
35 | using log4net; | ||
36 | using Nini.Config; | ||
37 | using OpenMetaverse; | ||
38 | using OpenMetaverse.StructuredData; | ||
39 | using OpenMetaverse.Messages.Linden; | ||
40 | using OpenSim.Framework; | ||
41 | using OpenSim.Framework.Servers; | ||
42 | using OpenSim.Framework.Servers.HttpServer; | ||
43 | using OpenSim.Region.Framework.Interfaces; | ||
44 | using OpenSim.Region.Framework.Scenes; | ||
45 | using OpenSim.Services.Interfaces; | ||
46 | using Caps = OpenSim.Framework.Capabilities.Caps; | ||
47 | using OSD = OpenMetaverse.StructuredData.OSD; | ||
48 | using OSDMap = OpenMetaverse.StructuredData.OSDMap; | ||
49 | using OpenSim.Framework.Capabilities; | ||
50 | using ExtraParamType = OpenMetaverse.ExtraParamType; | ||
51 | |||
52 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Reflection; | ||
31 | using log4net; | ||
32 | using Nini.Config; | ||
33 | using Mono.Addins; | ||
34 | using OpenMetaverse; | ||
35 | using OpenMetaverse.StructuredData; | ||
36 | using OpenSim.Framework; | ||
37 | using OpenSim.Framework.Servers.HttpServer; | ||
38 | using OpenSim.Region.Framework.Interfaces; | ||
39 | using OpenSim.Region.Framework.Scenes; | ||
40 | using OpenSim.Services.Interfaces; | ||
41 | using Caps = OpenSim.Framework.Capabilities.Caps; | ||
42 | |||
43 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Specialized; | ||
31 | using System.Drawing; | ||
32 | using System.Drawing.Imaging; | ||
33 | using System.Reflection; | ||
34 | using System.IO; | ||
35 | using System.Web; | ||
36 | using log4net; | ||
37 | using Nini.Config; | ||
38 | using Mono.Addins; | ||
39 | using OpenMetaverse; | ||
40 | using OpenMetaverse.StructuredData; | ||
41 | using OpenMetaverse.Imaging; | ||
42 | using OpenSim.Framework; | ||
43 | using OpenSim.Framework.Servers; | ||
44 | using OpenSim.Framework.Servers.HttpServer; | ||
45 | using OpenSim.Region.Framework.Interfaces; | ||
46 | using OpenSim.Region.Framework.Scenes; | ||
47 | using OpenSim.Services.Interfaces; | ||
48 | using Caps = OpenSim.Framework.Capabilities.Caps; | ||
49 | using OpenSim.Capabilities.Handlers; | ||
50 | |||
51 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Reflection; | ||
31 | using log4net; | ||
32 | using Nini.Config; | ||
33 | using Mono.Addins; | ||
34 | using OpenMetaverse; | ||
35 | using OpenSim.Framework; | ||
36 | using OpenSim.Framework.Servers.HttpServer; | ||
37 | using OpenSim.Region.Framework.Interfaces; | ||
38 | using OpenSim.Region.Framework.Scenes; | ||
39 | using OpenSim.Services.Interfaces; | ||
40 | using Caps = OpenSim.Framework.Capabilities.Caps; | ||
41 | using OpenSim.Capabilities.Handlers; | ||
42 | |||
43 | namespace 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; | |||
31 | using OpenMetaverse.Imaging; | 31 | using OpenMetaverse.Imaging; |
32 | using OpenSim.Framework; | 32 | using OpenSim.Framework; |
33 | using OpenSim.Region.Framework.Interfaces; | 33 | using OpenSim.Region.Framework.Interfaces; |
34 | using OpenSim.Region.Framework.Scenes.Hypergrid; | ||
35 | using OpenSim.Services.Interfaces; | 34 | using OpenSim.Services.Interfaces; |
36 | using log4net; | 35 | using log4net; |
37 | using System.Reflection; | 36 | using 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; | |||
37 | using log4net; | 37 | using log4net; |
38 | using OpenMetaverse; | 38 | using OpenMetaverse; |
39 | using OpenMetaverse.Packets; | 39 | using OpenMetaverse.Packets; |
40 | using OpenMetaverse.Messages.Linden; | ||
40 | using OpenMetaverse.StructuredData; | 41 | using OpenMetaverse.StructuredData; |
41 | using OpenSim.Framework; | 42 | using OpenSim.Framework; |
42 | using OpenSim.Framework.Client; | 43 | using OpenSim.Framework.Client; |
43 | using OpenSim.Framework.Communications.Cache; | ||
44 | using OpenSim.Framework.Statistics; | 44 | using OpenSim.Framework.Statistics; |
45 | using OpenSim.Region.Framework.Interfaces; | 45 | using OpenSim.Region.Framework.Interfaces; |
46 | using OpenSim.Region.Framework.Scenes; | 46 | using OpenSim.Region.Framework.Scenes; |
47 | using OpenSim.Region.Framework.Scenes.Hypergrid; | ||
48 | using OpenSim.Services.Interfaces; | 47 | using OpenSim.Services.Interfaces; |
49 | using Timer = System.Timers.Timer; | 48 | using Timer = System.Timers.Timer; |
50 | using AssetLandmark = OpenSim.Framework.AssetLandmark; | 49 | using AssetLandmark = OpenSim.Framework.AssetLandmark; |
51 | using Nini.Config; | 50 | using Nini.Config; |
52 | 51 | ||
52 | using System.IO; | ||
53 | |||
53 | namespace OpenSim.Region.ClientStack.LindenUDP | 54 | namespace 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 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Diagnostics; | ||
30 | using System.IO; | 31 | using System.IO; |
31 | using System.Net; | 32 | using System.Net; |
32 | using System.Net.Sockets; | 33 | using 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 | ||
32 | namespace OpenSim.Region.ClientStack.LindenUDP | 32 | namespace 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 | |||
28 | using System; | ||
29 | using System.Net; | ||
30 | using log4net.Config; | ||
31 | using Nini.Config; | ||
32 | using NUnit.Framework; | ||
33 | using OpenMetaverse; | ||
34 | using OpenMetaverse.Packets; | ||
35 | using OpenSim.Framework; | ||
36 | using OpenSim.Region.Framework.Scenes; | ||
37 | using OpenSim.Tests.Common; | ||
38 | using OpenSim.Tests.Common.Mock; | ||
39 | |||
40 | namespace 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 | ||
28 | using System.Net; | ||
28 | using OpenMetaverse; | 29 | using OpenMetaverse; |
29 | using OpenSim.Framework; | 30 | using OpenSim.Framework; |
30 | using OpenSim.Region.Framework.Scenes; | 31 | using 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 | |||
28 | using Nini.Config; | ||
29 | using NUnit.Framework; | ||
30 | using OpenMetaverse; | ||
31 | using OpenMetaverse.Packets; | ||
32 | using OpenSim.Framework; | ||
33 | using OpenSim.Tests.Common.Mock; | ||
34 | using OpenSim.Tests.Common; | ||
35 | |||
36 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Net; | ||
31 | using System.Net.Sockets; | ||
32 | using Nini.Config; | ||
33 | using OpenMetaverse.Packets; | ||
34 | using OpenSim.Framework; | ||
35 | |||
36 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.Reflection; | ||
32 | using OpenSim.Framework; | ||
33 | |||
34 | using log4net; | ||
35 | |||
36 | namespace 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 @@ | |||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Net; | 30 | using System.Net; |
31 | using System.Threading; | ||
31 | using OpenMetaverse; | 32 | using OpenMetaverse; |
32 | 33 | ||
33 | namespace OpenSim.Region.ClientStack.LindenUDP | 34 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using OpenMetaverse; | ||
31 | using OpenSim.Framework; | ||
32 | |||
33 | namespace 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 | |||
28 | using System.Net; | ||
29 | using log4net.Config; | ||
30 | using Nini.Config; | ||
31 | using NUnit.Framework; | ||
32 | using NUnit.Framework.SyntaxHelpers; | ||
33 | using OpenMetaverse; | ||
34 | using OpenMetaverse.Packets; | ||
35 | using OpenSim.Framework; | ||
36 | using OpenSim.Tests.Common; | ||
37 | using OpenSim.Tests.Common.Mock; | ||
38 | |||
39 | namespace 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 | |||
28 | using Nini.Config; | ||
29 | using NUnit.Framework; | ||
30 | using NUnit.Framework.SyntaxHelpers; | ||
31 | using OpenMetaverse; | ||
32 | using OpenMetaverse.Packets; | ||
33 | using OpenSim.Framework; | ||
34 | using OpenSim.Tests.Common.Mock; | ||
35 | using OpenSim.Tests.Common; | ||
36 | |||
37 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Net; | ||
31 | using System.Net.Sockets; | ||
32 | using OpenMetaverse.Packets; | ||
33 | |||
34 | namespace 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 | |||
28 | using System; | ||
29 | |||
30 | namespace 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; | |||
36 | using OpenSim.Framework.Servers; | 36 | using OpenSim.Framework.Servers; |
37 | using OpenSim.Framework.Servers.HttpServer; | 37 | using OpenSim.Framework.Servers.HttpServer; |
38 | using OpenSim.Region.Framework; | 38 | using OpenSim.Region.Framework; |
39 | using OpenSim.Region.Framework.Interfaces; | ||
39 | using OpenSim.Region.Framework.Scenes; | 40 | using OpenSim.Region.Framework.Scenes; |
40 | using OpenSim.Region.Physics.Manager; | 41 | using 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 | ||