aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ClientStack')
-rw-r--r--OpenSim/Region/ClientStack/IClientNetworkServer.cs15
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs136
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs150
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs38
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs618
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs36
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs8
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs53
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs20
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs4
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs1
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs2
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs2
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs33
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs166
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs115
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs4
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs1118
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs7
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs217
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs711
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs117
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs25
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs2
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs6
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs16
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs9
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs18
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs163
29 files changed, 2385 insertions, 1425 deletions
diff --git a/OpenSim/Region/ClientStack/IClientNetworkServer.cs b/OpenSim/Region/ClientStack/IClientNetworkServer.cs
index 54a441b..bb7e6d0 100644
--- a/OpenSim/Region/ClientStack/IClientNetworkServer.cs
+++ b/OpenSim/Region/ClientStack/IClientNetworkServer.cs
@@ -38,11 +38,22 @@ namespace OpenSim.Region.ClientStack
38 IPAddress _listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, 38 IPAddress _listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource,
39 AgentCircuitManager authenticateClass); 39 AgentCircuitManager authenticateClass);
40 40
41 void NetworkStop();
42 bool HandlesRegion(Location x); 41 bool HandlesRegion(Location x);
43 void AddScene(IScene x);
44 42
43 /// <summary>
44 /// Add the given scene to be handled by this IClientNetworkServer.
45 /// </summary>
46 /// <param name='scene'></param>
47 void AddScene(IScene scene);
48
49 /// <summary>
50 /// Start sending and receiving data.
51 /// </summary>
45 void Start(); 52 void Start();
53
54 /// <summary>
55 /// Stop sending and receiving data.
56 /// </summary>
46 void Stop(); 57 void Stop();
47 } 58 }
48} 59}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs
new file mode 100644
index 0000000..bbadc55
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs
@@ -0,0 +1,136 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Specialized;
31using System.Drawing;
32using System.Drawing.Imaging;
33using System.Reflection;
34using System.IO;
35using System.Web;
36using log4net;
37using Nini.Config;
38using Mono.Addins;
39using OpenMetaverse;
40using OpenMetaverse.StructuredData;
41using OpenSim.Framework;
42using OpenSim.Framework.Servers;
43using OpenSim.Framework.Servers.HttpServer;
44using OpenSim.Region.Framework.Interfaces;
45using OpenSim.Region.Framework.Scenes;
46using OpenSim.Services.Interfaces;
47using Caps = OpenSim.Framework.Capabilities.Caps;
48using OpenSim.Capabilities.Handlers;
49
50namespace OpenSim.Region.ClientStack.Linden
51{
52 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AvatarPickerSearchModule")]
53 public class AvatarPickerSearchModule : INonSharedRegionModule
54 {
55// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
56
57 private Scene m_scene;
58 private IPeople m_People;
59 private bool m_Enabled = false;
60
61 private string m_URL;
62
63 #region ISharedRegionModule Members
64
65 public void Initialise(IConfigSource source)
66 {
67 IConfig config = source.Configs["ClientStack.LindenCaps"];
68 if (config == null)
69 return;
70
71 m_URL = config.GetString("Cap_AvatarPickerSearch", string.Empty);
72 // Cap doesn't exist
73 if (m_URL != string.Empty)
74 m_Enabled = true;
75 }
76
77 public void AddRegion(Scene s)
78 {
79 if (!m_Enabled)
80 return;
81
82 m_scene = s;
83 }
84
85 public void RemoveRegion(Scene s)
86 {
87 if (!m_Enabled)
88 return;
89
90 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
91 m_scene = null;
92 }
93
94 public void RegionLoaded(Scene s)
95 {
96 if (!m_Enabled)
97 return;
98
99 m_People = m_scene.RequestModuleInterface<IPeople>();
100 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
101 }
102
103 public void PostInitialise()
104 {
105 }
106
107 public void Close() { }
108
109 public string Name { get { return "AvatarPickerSearchModule"; } }
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 UUID capID = UUID.Random();
121
122 if (m_URL == "localhost")
123 {
124// m_log.DebugFormat("[AVATAR PICKER SEARCH]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName);
125 caps.RegisterHandler(
126 "AvatarPickerSearch",
127 new AvatarPickerSearchHandler("/CAPS/" + capID + "/", m_People, "AvatarPickerSearch", "Search for avatars by name"));
128 }
129 else
130 {
131 // m_log.DebugFormat("[AVATAR PICKER SEARCH]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName);
132 caps.RegisterHandler("AvatarPickerSearch", m_URL);
133 }
134 }
135 }
136} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
index 8241e07..ab8f0c9 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
@@ -105,6 +105,7 @@ namespace OpenSim.Region.ClientStack.Linden
105 private static readonly string m_getObjectCostPath = "0102/"; 105 private static readonly string m_getObjectCostPath = "0102/";
106 private static readonly string m_ResourceCostSelectedPath = "0103/"; 106 private static readonly string m_ResourceCostSelectedPath = "0103/";
107 private static readonly string m_UpdateAgentInformationPath = "0500/"; 107 private static readonly string m_UpdateAgentInformationPath = "0500/";
108 private static readonly string m_animSetTaskUpdatePath = "0260/";
108 109
109 // These are callbacks which will be setup by the scene so that we can update scene data when we 110 // These are callbacks which will be setup by the scene so that we can update scene data when we
110 // receive capability calls 111 // receive capability calls
@@ -248,13 +249,31 @@ namespace OpenSim.Region.ClientStack.Linden
248 //m_capsHandlers["MapLayer"] = 249 //m_capsHandlers["MapLayer"] =
249 // new LLSDStreamhandler<OSDMapRequest, OSDMapLayerResponse>("POST", 250 // new LLSDStreamhandler<OSDMapRequest, OSDMapLayerResponse>("POST",
250 // capsBase + m_mapLayerPath, 251 // capsBase + m_mapLayerPath,
251 // GetMapLayer); 252 // GetMapLayer);
253
254 IRequestHandler getObjectPhysicsDataHandler
255 = new RestStreamHandler(
256 "POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData, "GetObjectPhysicsData", null);
257 m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler);
258
259 IRequestHandler getObjectCostHandler = new RestStreamHandler("POST", capsBase + m_getObjectCostPath, GetObjectCost);
260 m_HostCapsObj.RegisterHandler("GetObjectCost", getObjectCostHandler);
261 IRequestHandler ResourceCostSelectedHandler = new RestStreamHandler("POST", capsBase + m_ResourceCostSelectedPath, ResourceCostSelected);
262 m_HostCapsObj.RegisterHandler("ResourceCostSelected", ResourceCostSelectedHandler);
263
264
252 IRequestHandler req 265 IRequestHandler req
253 = new RestStreamHandler( 266 = new RestStreamHandler(
254 "POST", capsBase + m_notecardTaskUpdatePath, ScriptTaskInventory, "UpdateScript", null); 267 "POST", capsBase + m_notecardTaskUpdatePath, ScriptTaskInventory, "UpdateScript", null);
255 268
256 m_HostCapsObj.RegisterHandler("UpdateScriptTaskInventory", req); 269 m_HostCapsObj.RegisterHandler("UpdateScriptTaskInventory", req);
257 m_HostCapsObj.RegisterHandler("UpdateScriptTask", req); 270 m_HostCapsObj.RegisterHandler("UpdateScriptTask", req);
271
272// IRequestHandler animSetRequestHandler
273// = new RestStreamHandler(
274// "POST", capsBase + m_animSetTaskUpdatePath, AnimSetTaskInventory, "UpdateScript", null);
275
276// m_HostCapsObj.RegisterHandler("UpdateAnimSetTaskInventory", animSetRequestHandler);
258 } 277 }
259 catch (Exception e) 278 catch (Exception e)
260 { 279 {
@@ -280,15 +299,15 @@ namespace OpenSim.Region.ClientStack.Linden
280 "POST", capsBase + m_notecardUpdatePath, NoteCardAgentInventory, "Update*", null); 299 "POST", capsBase + m_notecardUpdatePath, NoteCardAgentInventory, "Update*", null);
281 300
282 m_HostCapsObj.RegisterHandler("UpdateNotecardAgentInventory", req); 301 m_HostCapsObj.RegisterHandler("UpdateNotecardAgentInventory", req);
302 m_HostCapsObj.RegisterHandler("UpdateAnimSetAgentInventory", req);
283 m_HostCapsObj.RegisterHandler("UpdateScriptAgentInventory", req); 303 m_HostCapsObj.RegisterHandler("UpdateScriptAgentInventory", req);
284 m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req); 304 m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req);
285 IRequestHandler getObjectPhysicsDataHandler = new RestStreamHandler("POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData); 305
286 m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler); 306
287 IRequestHandler getObjectCostHandler = new RestStreamHandler("POST", capsBase + m_getObjectCostPath, GetObjectCost); 307
288 m_HostCapsObj.RegisterHandler("GetObjectCost", getObjectCostHandler); 308 IRequestHandler UpdateAgentInformationHandler
289 IRequestHandler ResourceCostSelectedHandler = new RestStreamHandler("POST", capsBase + m_ResourceCostSelectedPath, ResourceCostSelected); 309 = new RestStreamHandler(
290 m_HostCapsObj.RegisterHandler("ResourceCostSelected", ResourceCostSelectedHandler); 310 "POST", capsBase + m_UpdateAgentInformationPath, UpdateAgentInformation, "UpdateAgentInformation", null);
291 IRequestHandler UpdateAgentInformationHandler = new RestStreamHandler("POST", capsBase + m_UpdateAgentInformationPath, UpdateAgentInformation);
292 m_HostCapsObj.RegisterHandler("UpdateAgentInformation", UpdateAgentInformationHandler); 311 m_HostCapsObj.RegisterHandler("UpdateAgentInformation", UpdateAgentInformationHandler);
293 312
294 m_HostCapsObj.RegisterHandler( 313 m_HostCapsObj.RegisterHandler(
@@ -361,18 +380,7 @@ namespace OpenSim.Region.ClientStack.Linden
361 foreach (OSD c in capsRequested) 380 foreach (OSD c in capsRequested)
362 validCaps.Add(c.AsString()); 381 validCaps.Add(c.AsString());
363 382
364 Hashtable caps = m_HostCapsObj.CapsHandlers.GetCapsDetails(true, validCaps); 383 string result = LLSDHelpers.SerialiseLLSDReply(m_HostCapsObj.GetCapsDetails(true, validCaps));
365
366 // Add the external too
367 foreach (KeyValuePair<string, string> kvp in m_HostCapsObj.ExternalCapsHandlers)
368 {
369 if (!validCaps.Contains(kvp.Key))
370 continue;
371
372 caps[kvp.Key] = kvp.Value;
373 }
374
375 string result = LLSDHelpers.SerialiseLLSDReply(caps);
376 384
377 //m_log.DebugFormat("[CAPS] CapsRequest {0}", result); 385 //m_log.DebugFormat("[CAPS] CapsRequest {0}", result);
378 386
@@ -530,6 +538,7 @@ namespace OpenSim.Region.ClientStack.Linden
530 538
531 if (llsdRequest.asset_type == "texture" || 539 if (llsdRequest.asset_type == "texture" ||
532 llsdRequest.asset_type == "animation" || 540 llsdRequest.asset_type == "animation" ||
541 llsdRequest.asset_type == "animatn" || // this is the asset name actually used by viewers
533 llsdRequest.asset_type == "mesh" || 542 llsdRequest.asset_type == "mesh" ||
534 llsdRequest.asset_type == "sound") 543 llsdRequest.asset_type == "sound")
535 { 544 {
@@ -571,6 +580,7 @@ namespace OpenSim.Region.ClientStack.Linden
571 string error; 580 string error;
572 int modelcost; 581 int modelcost;
573 582
583
574 if (!m_ModelCost.MeshModelCost(llsdRequest.asset_resources, baseCost, out modelcost, 584 if (!m_ModelCost.MeshModelCost(llsdRequest.asset_resources, baseCost, out modelcost,
575 meshcostdata, out error, ref warning)) 585 meshcostdata, out error, ref warning))
576 { 586 {
@@ -748,11 +758,21 @@ namespace OpenSim.Region.ClientStack.Linden
748 inType = (sbyte)InventoryType.Sound; 758 inType = (sbyte)InventoryType.Sound;
749 assType = (sbyte)AssetType.Sound; 759 assType = (sbyte)AssetType.Sound;
750 } 760 }
761 else if (inventoryType == "snapshot")
762 {
763 inType = (sbyte)InventoryType.Snapshot;
764 }
751 else if (inventoryType == "animation") 765 else if (inventoryType == "animation")
752 { 766 {
753 inType = (sbyte)InventoryType.Animation; 767 inType = (sbyte)InventoryType.Animation;
754 assType = (sbyte)AssetType.Animation; 768 assType = (sbyte)AssetType.Animation;
755 } 769 }
770 else if (inventoryType == "animset")
771 {
772 inType = (sbyte)CustomInventoryType.AnimationSet;
773 assType = (sbyte)CustomAssetType.AnimationSet;
774 m_log.Debug("got animset upload request");
775 }
756 else if (inventoryType == "wearable") 776 else if (inventoryType == "wearable")
757 { 777 {
758 inType = (sbyte)InventoryType.Wearable; 778 inType = (sbyte)InventoryType.Wearable;
@@ -778,7 +798,7 @@ namespace OpenSim.Region.ClientStack.Linden
778 OSDMap request = (OSDMap)OSDParser.DeserializeLLSDXml(data); 798 OSDMap request = (OSDMap)OSDParser.DeserializeLLSDXml(data);
779 799
780 // compare and get updated information 800 // compare and get updated information
781 801/* does nothing still we do need something to avoid special viewer to upload something diferent from the cost estimation
782 bool mismatchError = true; 802 bool mismatchError = true;
783 803
784 while (mismatchError) 804 while (mismatchError)
@@ -794,7 +814,7 @@ namespace OpenSim.Region.ClientStack.Linden
794 814
795 return; 815 return;
796 } 816 }
797 817*/
798 OSDArray instance_list = (OSDArray)request["instance_list"]; 818 OSDArray instance_list = (OSDArray)request["instance_list"];
799 OSDArray mesh_list = (OSDArray)request["mesh_list"]; 819 OSDArray mesh_list = (OSDArray)request["mesh_list"];
800 OSDArray texture_list = (OSDArray)request["texture_list"]; 820 OSDArray texture_list = (OSDArray)request["texture_list"];
@@ -808,7 +828,7 @@ namespace OpenSim.Region.ClientStack.Linden
808 List<UUID> textures = new List<UUID>(); 828 List<UUID> textures = new List<UUID>();
809 829
810 830
811 if (doTextInv) 831// if (doTextInv)
812 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client); 832 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
813 833
814 if(client == null) // don't put textures in inventory if there is no client 834 if(client == null) // don't put textures in inventory if there is no client
@@ -856,14 +876,73 @@ namespace OpenSim.Region.ClientStack.Linden
856 876
857 // create and store meshs assets 877 // create and store meshs assets
858 List<UUID> meshAssets = new List<UUID>(); 878 List<UUID> meshAssets = new List<UUID>();
879 List<bool> meshAvatarSkeletons = new List<bool>();
880 List<bool> meshAvatarColliders = new List<bool>();
881
882 bool curAvSkeleton;
883 bool curAvCollider;
859 for (int i = 0; i < mesh_list.Count; i++) 884 for (int i = 0; i < mesh_list.Count; i++)
860 { 885 {
886 curAvSkeleton = false;
887 curAvCollider = false;
888
889 // we do need to parse the mesh now
890 OSD osd = OSDParser.DeserializeLLSDBinary(mesh_list[i]);
891 if (osd is OSDMap)
892 {
893 OSDMap mosd = (OSDMap)osd;
894 if (mosd.ContainsKey("skeleton"))
895 {
896 OSDMap skeleton = (OSDMap)mosd["skeleton"];
897 int sksize = skeleton["size"].AsInteger();
898 if (sksize > 0)
899 curAvSkeleton = true;
900 }
901 }
902
861 AssetBase meshAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Mesh, creatorIDstr); 903 AssetBase meshAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Mesh, creatorIDstr);
862 meshAsset.Data = mesh_list[i].AsBinary(); 904 meshAsset.Data = mesh_list[i].AsBinary();
863 if (istest) 905 if (istest)
864 meshAsset.Local = true; 906 meshAsset.Local = true;
865 m_assetService.Store(meshAsset); 907 m_assetService.Store(meshAsset);
866 meshAssets.Add(meshAsset.FullID); 908 meshAssets.Add(meshAsset.FullID);
909 meshAvatarSkeletons.Add(curAvSkeleton);
910 meshAvatarColliders.Add(curAvCollider);
911
912 // test code
913 if (curAvSkeleton && client != null)
914 {
915 string name = assetName;
916 if (name.Length > 25)
917 name = name.Substring(0, 24);
918 name += "_Mesh#" + i.ToString();
919 InventoryItemBase meshitem = new InventoryItemBase();
920 meshitem.Owner = m_HostCapsObj.AgentID;
921 meshitem.CreatorId = creatorIDstr;
922 meshitem.CreatorData = String.Empty;
923 meshitem.ID = UUID.Random();
924 meshitem.AssetID = meshAsset.FullID;
925 meshitem.Description = "mesh ";
926 meshitem.Name = name;
927 meshitem.AssetType = (int)AssetType.Mesh;
928 meshitem.InvType = (int)InventoryType.Mesh;
929 // meshitem.Folder = UUID.Zero; // send to default
930
931 meshitem.Folder = parentFolder; // dont let it go to folder Meshes that viewers dont show
932
933 // If we set PermissionMask.All then when we rez the item the next permissions will replace the current
934 // (owner) permissions. This becomes a problem if next permissions are changed.
935 meshitem.CurrentPermissions
936 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer);
937
938 meshitem.BasePermissions = (uint)PermissionMask.All;
939 meshitem.EveryOnePermissions = 0;
940 meshitem.NextPermissions = (uint)PermissionMask.All;
941 meshitem.CreationDate = Util.UnixTimeSinceEpoch();
942
943 m_Scene.AddInventoryItem(client, meshitem);
944 meshitem = null;
945 }
867 } 946 }
868 947
869 int skipedMeshs = 0; 948 int skipedMeshs = 0;
@@ -1104,7 +1183,12 @@ namespace OpenSim.Region.ClientStack.Linden
1104 // If we set PermissionMask.All then when we rez the item the next permissions will replace the current 1183 // If we set PermissionMask.All then when we rez the item the next permissions will replace the current
1105 // (owner) permissions. This becomes a problem if next permissions are changed. 1184 // (owner) permissions. This becomes a problem if next permissions are changed.
1106 1185
1107 if (restrictPerms) 1186 if (inType == (sbyte)CustomInventoryType.AnimationSet)
1187 {
1188 AnimationSet.setCreateItemPermitions(item);
1189 }
1190
1191 else if (restrictPerms)
1108 { 1192 {
1109 item.BasePermissions = (uint)(PermissionMask.Move | PermissionMask.Modify); 1193 item.BasePermissions = (uint)(PermissionMask.Move | PermissionMask.Modify);
1110 item.CurrentPermissions = (uint)(PermissionMask.Move | PermissionMask.Modify); 1194 item.CurrentPermissions = (uint)(PermissionMask.Move | PermissionMask.Modify);
@@ -1380,6 +1464,17 @@ namespace OpenSim.Region.ClientStack.Linden
1380 1464
1381 resp[uuid.ToString()] = object_data; 1465 resp[uuid.ToString()] = object_data;
1382 } 1466 }
1467 else
1468 {
1469 OSDMap object_data = new OSDMap();
1470 object_data["linked_set_resource_cost"] = 0;
1471 object_data["resource_cost"] = 0;
1472 object_data["physics_cost"] = 0;
1473 object_data["linked_set_physics_cost"] = 0;
1474
1475 resp[uuid.ToString()] = object_data;
1476 }
1477
1383 } 1478 }
1384 } 1479 }
1385 1480
@@ -1444,7 +1539,7 @@ namespace OpenSim.Region.ClientStack.Linden
1444 } 1539 }
1445 } 1540 }
1446 1541
1447 if (simul != 0) 1542 // if (simul != 0)
1448 { 1543 {
1449 OSDMap object_data = new OSDMap(); 1544 OSDMap object_data = new OSDMap();
1450 1545
@@ -1505,7 +1600,7 @@ namespace OpenSim.Region.ClientStack.Linden
1505 private int m_nreqmeshs; 1600 private int m_nreqmeshs;
1506 private int m_nreqinstances; 1601 private int m_nreqinstances;
1507 private bool m_IsAtestUpload; 1602 private bool m_IsAtestUpload;
1508 1603
1509 public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem, 1604 public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem,
1510 UUID parentFolderID, string invType, string assetType, string path, 1605 UUID parentFolderID, string invType, string assetType, string path,
1511 IHttpServer httpServer, bool dumpAssetsToFile, 1606 IHttpServer httpServer, bool dumpAssetsToFile,
@@ -1573,7 +1668,8 @@ namespace OpenSim.Region.ClientStack.Linden
1573 if (handlerUpLoad != null) 1668 if (handlerUpLoad != null)
1574 { 1669 {
1575 handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType, 1670 handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType,
1576 m_cost, m_texturesFolder, m_nreqtextures, m_nreqmeshs, m_nreqinstances, m_IsAtestUpload, ref m_error); 1671 m_cost, m_texturesFolder, m_nreqtextures, m_nreqmeshs, m_nreqinstances, m_IsAtestUpload,
1672 ref m_error);
1577 } 1673 }
1578 if (m_IsAtestUpload) 1674 if (m_IsAtestUpload)
1579 { 1675 {
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs
index 4a3fae6..546bcd9 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs
@@ -96,11 +96,15 @@ namespace OpenSim.Region.ClientStack.Linden
96 // basicCost input region assets upload cost 96 // basicCost input region assets upload cost
97 // totalcost returns model total upload fee 97 // totalcost returns model total upload fee
98 // meshcostdata returns detailed costs for viewer 98 // meshcostdata returns detailed costs for viewer
99 public bool MeshModelCost(LLSDAssetResource resources, int basicCost, out int totalcost, 99 // avatarSkeleton if mesh includes a avatar skeleton
100 // useAvatarCollider if we should use physics mesh for avatar
101 public bool MeshModelCost(LLSDAssetResource resources, int basicCost, out int totalcost,
100 LLSDAssetUploadResponseData meshcostdata, out string error, ref string warning) 102 LLSDAssetUploadResponseData meshcostdata, out string error, ref string warning)
101 { 103 {
102 totalcost = 0; 104 totalcost = 0;
103 error = string.Empty; 105 error = string.Empty;
106
107 bool avatarSkeleton = false;
104 108
105 if (resources == null || 109 if (resources == null ||
106 resources.instance_list == null || 110 resources.instance_list == null ||
@@ -145,6 +149,10 @@ namespace OpenSim.Region.ClientStack.Linden
145 float meshsfee = 0; 149 float meshsfee = 0;
146 int numberMeshs = 0; 150 int numberMeshs = 0;
147 bool haveMeshs = false; 151 bool haveMeshs = false;
152
153 bool curskeleton;
154 bool curAvatarPhys;
155
148 List<ameshCostParam> meshsCosts = new List<ameshCostParam>(); 156 List<ameshCostParam> meshsCosts = new List<ameshCostParam>();
149 157
150 if (resources.mesh_list != null && resources.mesh_list.Array.Count > 0) 158 if (resources.mesh_list != null && resources.mesh_list.Array.Count > 0)
@@ -156,10 +164,20 @@ namespace OpenSim.Region.ClientStack.Linden
156 ameshCostParam curCost = new ameshCostParam(); 164 ameshCostParam curCost = new ameshCostParam();
157 byte[] data = (byte[])resources.mesh_list.Array[i]; 165 byte[] data = (byte[])resources.mesh_list.Array[i];
158 166
159 if (!MeshCost(data, curCost, out error)) 167 if (!MeshCost(data, curCost,out curskeleton, out curAvatarPhys, out error))
160 { 168 {
161 return false; 169 return false;
162 } 170 }
171
172 if (curskeleton)
173 {
174 if (avatarSkeleton)
175 {
176 error = "model can only contain a avatar skeleton";
177 return false;
178 }
179 avatarSkeleton = true;
180 }
163 meshsCosts.Add(curCost); 181 meshsCosts.Add(curCost);
164 meshsfee += curCost.costFee; 182 meshsfee += curCost.costFee;
165 } 183 }
@@ -273,7 +291,7 @@ namespace OpenSim.Region.ClientStack.Linden
273 } 291 }
274 292
275 // single mesh asset cost 293 // single mesh asset cost
276 private bool MeshCost(byte[] data, ameshCostParam cost, out string error) 294 private bool MeshCost(byte[] data, ameshCostParam cost,out bool skeleton, out bool avatarPhys, out string error)
277 { 295 {
278 cost.highLODSize = 0; 296 cost.highLODSize = 0;
279 cost.medLODSize = 0; 297 cost.medLODSize = 0;
@@ -284,6 +302,9 @@ namespace OpenSim.Region.ClientStack.Linden
284 302
285 error = string.Empty; 303 error = string.Empty;
286 304
305 skeleton = false;
306 avatarPhys = false;
307
287 if (data == null || data.Length == 0) 308 if (data == null || data.Length == 0)
288 { 309 {
289 error = "Missing model information."; 310 error = "Missing model information.";
@@ -330,6 +351,17 @@ namespace OpenSim.Region.ClientStack.Linden
330 351
331 int submesh_offset = -1; 352 int submesh_offset = -1;
332 353
354 if (map.ContainsKey("skeleton"))
355 {
356 tmpmap = (OSDMap)map["skeleton"];
357 if (tmpmap.ContainsKey("offset") && tmpmap.ContainsKey("size"))
358 {
359 int sksize = tmpmap["size"].AsInteger();
360 if(sksize > 0)
361 skeleton = true;
362 }
363 }
364
333 if (map.ContainsKey("physics_convex")) 365 if (map.ContainsKey("physics_convex"))
334 { 366 {
335 tmpmap = (OSDMap)map["physics_convex"]; 367 tmpmap = (OSDMap)map["physics_convex"];
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
index eb40eb1..ca6c3ca 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
@@ -65,12 +65,18 @@ namespace OpenSim.Region.ClientStack.Linden
65 /// </value> 65 /// </value>
66 public int DebugLevel { get; set; } 66 public int DebugLevel { get; set; }
67 67
68 // Viewer post requests timeout in 60 secs
69 // https://bitbucket.org/lindenlab/viewer-release/src/421c20423df93d650cc305dc115922bb30040999/indra/llmessage/llhttpclient.cpp?at=default#cl-44
70 //
71 private const int VIEWER_TIMEOUT = 60 * 1000;
72 // Just to be safe, we work on a 10 sec shorter cycle
73 private const int SERVER_EQ_TIME_NO_EVENTS = VIEWER_TIMEOUT - (10 * 1000);
74
68 protected Scene m_scene; 75 protected Scene m_scene;
69 76
70 private Dictionary<UUID, int> m_ids = new Dictionary<UUID, int>(); 77 private Dictionary<UUID, int> m_ids = new Dictionary<UUID, int>();
71 78
72 private Dictionary<UUID, Queue<OSD>> queues = new Dictionary<UUID, Queue<OSD>>(); 79 private Dictionary<UUID, Queue<OSD>> queues = new Dictionary<UUID, Queue<OSD>>();
73 private Dictionary<UUID, UUID> m_QueueUUIDAvatarMapping = new Dictionary<UUID, UUID>();
74 private Dictionary<UUID, UUID> m_AvatarQueueUUIDMapping = new Dictionary<UUID, UUID>(); 80 private Dictionary<UUID, UUID> m_AvatarQueueUUIDMapping = new Dictionary<UUID, UUID>();
75 81
76 #region INonSharedRegionModule methods 82 #region INonSharedRegionModule methods
@@ -84,7 +90,6 @@ namespace OpenSim.Region.ClientStack.Linden
84 scene.RegisterModuleInterface<IEventQueue>(this); 90 scene.RegisterModuleInterface<IEventQueue>(this);
85 91
86 scene.EventManager.OnClientClosed += ClientClosed; 92 scene.EventManager.OnClientClosed += ClientClosed;
87 scene.EventManager.OnMakeChildAgent += MakeChildAgent;
88 scene.EventManager.OnRegisterCaps += OnRegisterCaps; 93 scene.EventManager.OnRegisterCaps += OnRegisterCaps;
89 94
90 MainConsole.Instance.Commands.AddCommand( 95 MainConsole.Instance.Commands.AddCommand(
@@ -113,7 +118,6 @@ namespace OpenSim.Region.ClientStack.Linden
113 return; 118 return;
114 119
115 scene.EventManager.OnClientClosed -= ClientClosed; 120 scene.EventManager.OnClientClosed -= ClientClosed;
116 scene.EventManager.OnMakeChildAgent -= MakeChildAgent;
117 scene.EventManager.OnRegisterCaps -= OnRegisterCaps; 121 scene.EventManager.OnRegisterCaps -= OnRegisterCaps;
118 122
119 scene.UnregisterModuleInterface<IEventQueue>(this); 123 scene.UnregisterModuleInterface<IEventQueue>(this);
@@ -172,29 +176,6 @@ namespace OpenSim.Region.ClientStack.Linden
172 } 176 }
173 177
174 /// <summary> 178 /// <summary>
175 /// Always returns a valid queue
176 /// </summary>
177 /// <param name="agentId"></param>
178 /// <returns></returns>
179 private Queue<OSD> TryGetQueue(UUID agentId)
180 {
181 lock (queues)
182 {
183 if (!queues.ContainsKey(agentId))
184 {
185 /*
186 m_log.DebugFormat(
187 "[EVENTQUEUE]: Adding new queue for agent {0} in region {1}",
188 agentId, m_scene.RegionInfo.RegionName);
189 */
190 queues[agentId] = new Queue<OSD>();
191 }
192
193 return queues[agentId];
194 }
195 }
196
197 /// <summary>
198 /// May return a null queue 179 /// May return a null queue
199 /// </summary> 180 /// </summary>
200 /// <param name="agentId"></param> 181 /// <param name="agentId"></param>
@@ -221,8 +202,17 @@ namespace OpenSim.Region.ClientStack.Linden
221 { 202 {
222 Queue<OSD> queue = GetQueue(avatarID); 203 Queue<OSD> queue = GetQueue(avatarID);
223 if (queue != null) 204 if (queue != null)
205 {
224 lock (queue) 206 lock (queue)
225 queue.Enqueue(ev); 207 queue.Enqueue(ev);
208 }
209 else
210 {
211 OSDMap evMap = (OSDMap)ev;
212 m_log.WarnFormat(
213 "[EVENTQUEUE]: (Enqueue) No queue found for agent {0} when placing message {1} in region {2}",
214 avatarID, evMap["message"], m_scene.Name);
215 }
226 } 216 }
227 catch (NullReferenceException e) 217 catch (NullReferenceException e)
228 { 218 {
@@ -237,77 +227,22 @@ namespace OpenSim.Region.ClientStack.Linden
237 227
238 private void ClientClosed(UUID agentID, Scene scene) 228 private void ClientClosed(UUID agentID, Scene scene)
239 { 229 {
240// m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", agentID, m_scene.RegionInfo.RegionName); 230 //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 231
248 lock (queues) 232 lock (queues)
249 {
250 queues.Remove(agentID); 233 queues.Remove(agentID);
251 }
252 234
253 List<UUID> removeitems = new List<UUID>();
254 lock (m_AvatarQueueUUIDMapping) 235 lock (m_AvatarQueueUUIDMapping)
255 { 236 m_AvatarQueueUUIDMapping.Remove(agentID);
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 237
270 string eqgPath = GenerateEqgCapPath(eventQueueGetUuid); 238 lock (m_ids)
271 MainServer.Instance.RemovePollServiceHTTPHandler("", eqgPath);
272
273// m_log.DebugFormat(
274// "[EVENT QUEUE GET MODULE]: Removed EQG handler {0} for {1} in {2}",
275// eqgPath, agentID, m_scene.RegionInfo.RegionName);
276 }
277 }
278
279 UUID searchval = UUID.Zero;
280
281 removeitems.Clear();
282
283 lock (m_QueueUUIDAvatarMapping)
284 { 239 {
285 foreach (UUID ky in m_QueueUUIDAvatarMapping.Keys) 240 if (!m_ids.ContainsKey(agentID))
286 { 241 m_ids.Remove(agentID);
287 searchval = m_QueueUUIDAvatarMapping[ky];
288
289 if (searchval == agentID)
290 {
291 removeitems.Add(ky);
292 }
293 }
294
295 foreach (UUID ky in removeitems)
296 m_QueueUUIDAvatarMapping.Remove(ky);
297 } 242 }
298 }
299 243
300 private void MakeChildAgent(ScenePresence avatar) 244 // m_log.DebugFormat("[EVENTQUEUE]: Deleted queues for {0} in region {1}", agentID, m_scene.RegionInfo.RegionName);
301 { 245
302 //m_log.DebugFormat("[EVENTQUEUE]: Make Child agent {0} in region {1}.", avatar.UUID, m_scene.RegionInfo.RegionName);
303 //lock (m_ids)
304 // {
305 //if (m_ids.ContainsKey(avatar.UUID))
306 //{
307 // close the event queue.
308 //m_ids[avatar.UUID] = -1;
309 //}
310 //}
311 } 246 }
312 247
313 /// <summary> 248 /// <summary>
@@ -322,85 +257,109 @@ namespace OpenSim.Region.ClientStack.Linden
322 public void OnRegisterCaps(UUID agentID, Caps caps) 257 public void OnRegisterCaps(UUID agentID, Caps caps)
323 { 258 {
324 // Register an event queue for the client 259 // Register an event queue for the client
325 260 m_log.DebugFormat(
326 //m_log.DebugFormat( 261 "[EVENTQUEUE]: OnRegisterCaps: agentID {0} caps {1} region {2}",
327 // "[EVENTQUEUE]: OnRegisterCaps: agentID {0} caps {1} region {2}", 262 agentID, caps, m_scene.RegionInfo.RegionName);
328 // agentID, caps, m_scene.RegionInfo.RegionName);
329
330 // Let's instantiate a Queue for this agent right now
331 TryGetQueue(agentID);
332 263
333 UUID eventQueueGetUUID; 264 UUID eventQueueGetUUID;
265 Queue<OSD> queue;
266 Random rnd = new Random(Environment.TickCount);
267 int nrnd = rnd.Next(30000000);
268 if (nrnd < 0)
269 nrnd = -nrnd;
334 270
335 lock (m_AvatarQueueUUIDMapping) 271 lock (queues)
336 { 272 {
337 // Reuse open queues. The client does! 273 if (queues.ContainsKey(agentID))
338 if (m_AvatarQueueUUIDMapping.ContainsKey(agentID)) 274 queue = queues[agentID];
275 else
276 queue = null;
277
278 if (queue == null)
339 { 279 {
340 //m_log.DebugFormat("[EVENTQUEUE]: Found Existing UUID!"); 280 queue = new Queue<OSD>();
341 eventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID]; 281 queues[agentID] = queue;
282
283 // push markers to handle old responses still waiting
284 // this will cost at most viewer getting two forced noevents
285 // even being a new queue better be safe
286 queue.Enqueue(null);
287 queue.Enqueue(null); // one should be enough
288
289 lock (m_AvatarQueueUUIDMapping)
290 {
291 eventQueueGetUUID = UUID.Random();
292 if (m_AvatarQueueUUIDMapping.ContainsKey(agentID))
293 {
294 // oops this should not happen ?
295 m_log.DebugFormat("[EVENTQUEUE]: Found Existing UUID without a queue");
296 eventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID];
297 }
298 m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID);
299 }
300 lock (m_ids)
301 {
302 if (!m_ids.ContainsKey(agentID))
303 m_ids.Add(agentID, nrnd);
304 else
305 m_ids[agentID] = nrnd;
306 }
342 } 307 }
343 else 308 else
344 { 309 {
345 eventQueueGetUUID = UUID.Random(); 310 // push markers to handle old responses still waiting
346 //m_log.DebugFormat("[EVENTQUEUE]: Using random UUID!"); 311 // this will cost at most viewer getting two forced noevents
312 // even being a new queue better be safe
313 queue.Enqueue(null);
314 queue.Enqueue(null); // one should be enough
315
316 // reuse or not to reuse TODO FIX
317 lock (m_AvatarQueueUUIDMapping)
318 {
319 // Reuse open queues. The client does!
320 // Its reuse caps path not queues those are been reused already
321 if (m_AvatarQueueUUIDMapping.ContainsKey(agentID))
322 {
323 m_log.DebugFormat("[EVENTQUEUE]: Found Existing UUID!");
324 eventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID];
325 }
326 else
327 {
328 eventQueueGetUUID = UUID.Random();
329 m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID);
330 m_log.DebugFormat("[EVENTQUEUE]: Using random UUID!");
331 }
332 }
333 lock (m_ids)
334 {
335 // change to negative numbers so they are changed at end of sending first marker
336 // old data on a queue may be sent on a response for a new caps
337 // but at least will be sent with coerent IDs
338 if (!m_ids.ContainsKey(agentID))
339 m_ids.Add(agentID, -nrnd); // should not happen
340 else
341 m_ids[agentID] = -m_ids[agentID];
342 }
347 } 343 }
348 } 344 }
349 345
350 lock (m_QueueUUIDAvatarMapping) 346 caps.RegisterPollHandler(
351 { 347 "EventQueueGet",
352 if (!m_QueueUUIDAvatarMapping.ContainsKey(eventQueueGetUUID)) 348 new PollServiceEventArgs(null, GenerateEqgCapPath(eventQueueGetUUID), HasEvents, GetEvents, NoEvents, agentID, SERVER_EQ_TIME_NO_EVENTS));
353 m_QueueUUIDAvatarMapping.Add(eventQueueGetUUID, agentID);
354 }
355
356 lock (m_AvatarQueueUUIDMapping)
357 {
358 if (!m_AvatarQueueUUIDMapping.ContainsKey(agentID))
359 m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID);
360 }
361
362 string eventQueueGetPath = GenerateEqgCapPath(eventQueueGetUUID);
363
364 // Register this as a caps handler
365 // FIXME: Confusingly, we need to register separate as a capability so that the client is told about
366 // EventQueueGet when it receive capability information, but then we replace the rest handler immediately
367 // afterwards with the poll service. So for now, we'll pass a null instead to simplify code reading, but
368 // really it should be possible to directly register the poll handler as a capability.
369 caps.RegisterHandler("EventQueueGet", new RestHTTPHandler("POST", eventQueueGetPath, null));
370// delegate(Hashtable m_dhttpMethod)
371// {
372// return ProcessQueue(m_dhttpMethod, agentID, caps);
373// }));
374
375 // This will persist this beyond the expiry of the caps handlers
376 // TODO: Add EventQueueGet name/description for diagnostics
377 MainServer.Instance.AddPollServiceHTTPHandler(
378 eventQueueGetPath,
379 new PollServiceEventArgs(null, HasEvents, GetEvents, NoEvents, agentID, 40000));
380
381// m_log.DebugFormat(
382// "[EVENT QUEUE GET MODULE]: Registered EQG handler {0} for {1} in {2}",
383// eventQueueGetPath, agentID, m_scene.RegionInfo.RegionName);
384
385 Random rnd = new Random(Environment.TickCount);
386 lock (m_ids)
387 {
388 if (!m_ids.ContainsKey(agentID))
389 m_ids.Add(agentID, rnd.Next(30000000));
390 }
391 } 349 }
392 350
393 public bool HasEvents(UUID requestID, UUID agentID) 351 public bool HasEvents(UUID requestID, UUID agentID)
394 { 352 {
395 // Don't use this, because of race conditions at agent closing time
396 //Queue<OSD> queue = TryGetQueue(agentID);
397
398 Queue<OSD> queue = GetQueue(agentID); 353 Queue<OSD> queue = GetQueue(agentID);
399 if (queue != null) 354 if (queue != null)
400 lock (queue) 355 lock (queue)
356 {
357 //m_log.WarnFormat("POLLED FOR EVENTS BY {0} in {1} -- {2}", agentID, m_scene.RegionInfo.RegionName, queue.Count);
401 return queue.Count > 0; 358 return queue.Count > 0;
359 }
402 360
403 return false; 361 //m_log.WarnFormat("POLLED FOR EVENTS BY {0} unknown agent", agentID);
362 return true;
404 } 363 }
405 364
406 /// <summary> 365 /// <summary>
@@ -414,65 +373,80 @@ namespace OpenSim.Region.ClientStack.Linden
414 OSDMap ev = (OSDMap)element; 373 OSDMap ev = (OSDMap)element;
415 m_log.DebugFormat( 374 m_log.DebugFormat(
416 "Eq OUT {0,-30} to {1,-20} {2,-20}", 375 "Eq OUT {0,-30} to {1,-20} {2,-20}",
417 ev["message"], m_scene.GetScenePresence(agentId).Name, m_scene.RegionInfo.RegionName); 376 ev["message"], m_scene.GetScenePresence(agentId).Name, m_scene.Name);
418 } 377 }
419 } 378 }
420 379
421 public Hashtable GetEvents(UUID requestID, UUID pAgentId) 380 public Hashtable GetEvents(UUID requestID, UUID pAgentId)
422 { 381 {
423 if (DebugLevel >= 2) 382 if (DebugLevel >= 2)
424 m_log.DebugFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.RegionInfo.RegionName); 383 m_log.WarnFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.Name);
425 384
426 Queue<OSD> queue = TryGetQueue(pAgentId); 385 Queue<OSD> queue = GetQueue(pAgentId);
427 OSD element; 386 if (queue == null)
428 lock (queue)
429 { 387 {
430 if (queue.Count == 0) 388 return NoEvents(requestID, pAgentId);
431 return NoEvents(requestID, pAgentId);
432 element = queue.Dequeue(); // 15s timeout
433 } 389 }
434 390
391 OSD element = null;;
392 OSDArray array = new OSDArray();
435 int thisID = 0; 393 int thisID = 0;
436 lock (m_ids) 394 bool negativeID = false;
437 thisID = m_ids[pAgentId];
438 395
439 OSDArray array = new OSDArray(); 396 lock (queue)
440 if (element == null) // didn't have an event in 15s
441 {
442 // Send it a fake event to keep the client polling! It doesn't like 502s like the proxys say!
443 array.Add(EventQueueHelper.KeepAliveEvent());
444 //m_log.DebugFormat("[EVENTQUEUE]: adding fake event for {0} in region {1}", pAgentId, m_scene.RegionInfo.RegionName);
445 }
446 else
447 { 397 {
448 if (DebugLevel > 0) 398 if (queue.Count == 0)
449 LogOutboundDebugMessage(element, pAgentId); 399 return NoEvents(requestID, pAgentId);
450 400
451 array.Add(element); 401 lock (m_ids)
402 thisID = m_ids[pAgentId];
452 403
453 lock (queue) 404 if (thisID < 0)
454 { 405 {
455 while (queue.Count > 0) 406 negativeID = true;
456 { 407 thisID = -thisID;
457 element = queue.Dequeue(); 408 }
409
410 while (queue.Count > 0)
411 {
412 element = queue.Dequeue();
413 // add elements until a marker is found
414 // so they get into a response
415 if (element == null)
416 break;
417 if (DebugLevel > 0)
418 LogOutboundDebugMessage(element, pAgentId);
419 array.Add(element);
420 thisID++;
421 }
422 }
458 423
459 if (DebugLevel > 0) 424 OSDMap events = null;
460 LogOutboundDebugMessage(element, pAgentId);
461 425
462 array.Add(element); 426 if (array.Count > 0)
463 thisID++; 427 {
464 } 428 events = new OSDMap();
465 } 429 events.Add("events", array);
430 events.Add("id", new OSDInteger(thisID));
466 } 431 }
467 432
468 OSDMap events = new OSDMap(); 433 if (negativeID && element == null)
469 events.Add("events", array); 434 {
435 Random rnd = new Random(Environment.TickCount);
436 thisID = rnd.Next(30000000);
437 if (thisID < 0)
438 thisID = -thisID;
439 }
470 440
471 events.Add("id", new OSDInteger(thisID));
472 lock (m_ids) 441 lock (m_ids)
473 { 442 {
474 m_ids[pAgentId] = thisID + 1; 443 m_ids[pAgentId] = thisID + 1;
475 } 444 }
445
446 // if there where no elements before a marker send a NoEvents
447 if (array.Count == 0)
448 return NoEvents(requestID, pAgentId);
449
476 Hashtable responsedata = new Hashtable(); 450 Hashtable responsedata = new Hashtable();
477 responsedata["int_response_code"] = 200; 451 responsedata["int_response_code"] = 200;
478 responsedata["content_type"] = "application/xml"; 452 responsedata["content_type"] = "application/xml";
@@ -495,289 +469,53 @@ namespace OpenSim.Region.ClientStack.Linden
495 responsedata["http_protocol_version"] = "HTTP/1.0"; 469 responsedata["http_protocol_version"] = "HTTP/1.0";
496 return responsedata; 470 return responsedata;
497 } 471 }
498 472
499// public Hashtable ProcessQueue(Hashtable request, UUID agentID, Caps caps)
500// {
501// // TODO: this has to be redone to not busy-wait (and block the thread),
502// // TODO: as soon as we have a non-blocking way to handle HTTP-requests.
503//
504//// if (m_log.IsDebugEnabled)
505//// {
506//// String debug = "[EVENTQUEUE]: Got request for agent {0} in region {1} from thread {2}: [ ";
507//// foreach (object key in request.Keys)
508//// {
509//// debug += key.ToString() + "=" + request[key].ToString() + " ";
510//// }
511//// m_log.DebugFormat(debug + " ]", agentID, m_scene.RegionInfo.RegionName, System.Threading.Thread.CurrentThread.Name);
512//// }
513//
514// Queue<OSD> queue = TryGetQueue(agentID);
515// OSD element;
516//
517// lock (queue)
518// element = queue.Dequeue(); // 15s timeout
519//
520// Hashtable responsedata = new Hashtable();
521//
522// int thisID = 0;
523// lock (m_ids)
524// thisID = m_ids[agentID];
525//
526// if (element == null)
527// {
528// //m_log.ErrorFormat("[EVENTQUEUE]: Nothing to process in " + m_scene.RegionInfo.RegionName);
529// if (thisID == -1) // close-request
530// {
531// m_log.ErrorFormat("[EVENTQUEUE]: 404 in " + m_scene.RegionInfo.RegionName);
532// responsedata["int_response_code"] = 404; //501; //410; //404;
533// responsedata["content_type"] = "text/plain";
534// responsedata["keepalive"] = false;
535// responsedata["str_response_string"] = "Closed EQG";
536// return responsedata;
537// }
538// responsedata["int_response_code"] = 502;
539// responsedata["content_type"] = "text/plain";
540// responsedata["keepalive"] = false;
541// responsedata["str_response_string"] = "Upstream error: ";
542// responsedata["error_status_text"] = "Upstream error:";
543// responsedata["http_protocol_version"] = "HTTP/1.0";
544// return responsedata;
545// }
546//
547// OSDArray array = new OSDArray();
548// if (element == null) // didn't have an event in 15s
549// {
550// // Send it a fake event to keep the client polling! It doesn't like 502s like the proxys say!
551// array.Add(EventQueueHelper.KeepAliveEvent());
552// //m_log.DebugFormat("[EVENTQUEUE]: adding fake event for {0} in region {1}", agentID, m_scene.RegionInfo.RegionName);
553// }
554// else
555// {
556// array.Add(element);
557//
558// if (element is OSDMap)
559// {
560// OSDMap ev = (OSDMap)element;
561// m_log.DebugFormat(
562// "[EVENT QUEUE GET MODULE]: Eq OUT {0} to {1}",
563// ev["message"], m_scene.GetScenePresence(agentID).Name);
564// }
565//
566// lock (queue)
567// {
568// while (queue.Count > 0)
569// {
570// element = queue.Dequeue();
571//
572// if (element is OSDMap)
573// {
574// OSDMap ev = (OSDMap)element;
575// m_log.DebugFormat(
576// "[EVENT QUEUE GET MODULE]: Eq OUT {0} to {1}",
577// ev["message"], m_scene.GetScenePresence(agentID).Name);
578// }
579//
580// array.Add(element);
581// thisID++;
582// }
583// }
584// }
585//
586// OSDMap events = new OSDMap();
587// events.Add("events", array);
588//
589// events.Add("id", new OSDInteger(thisID));
590// lock (m_ids)
591// {
592// m_ids[agentID] = thisID + 1;
593// }
594//
595// responsedata["int_response_code"] = 200;
596// responsedata["content_type"] = "application/xml";
597// responsedata["keepalive"] = false;
598// responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(events);
599//
600// m_log.DebugFormat("[EVENTQUEUE]: sending response for {0} in region {1}: {2}", agentID, m_scene.RegionInfo.RegionName, responsedata["str_response_string"]);
601//
602// return responsedata;
603// }
604
605// public Hashtable EventQueuePath2(Hashtable request)
606// {
607// string capuuid = (string)request["uri"]; //path.Replace("/CAPS/EQG/","");
608// // pull off the last "/" in the path.
609// Hashtable responsedata = new Hashtable();
610// capuuid = capuuid.Substring(0, capuuid.Length - 1);
611// capuuid = capuuid.Replace("/CAPS/EQG/", "");
612// UUID AvatarID = UUID.Zero;
613// UUID capUUID = UUID.Zero;
614//
615// // parse the path and search for the avatar with it registered
616// if (UUID.TryParse(capuuid, out capUUID))
617// {
618// lock (m_QueueUUIDAvatarMapping)
619// {
620// if (m_QueueUUIDAvatarMapping.ContainsKey(capUUID))
621// {
622// AvatarID = m_QueueUUIDAvatarMapping[capUUID];
623// }
624// }
625//
626// if (AvatarID != UUID.Zero)
627// {
628// return ProcessQueue(request, AvatarID, m_scene.CapsModule.GetCapsForUser(AvatarID));
629// }
630// else
631// {
632// responsedata["int_response_code"] = 404;
633// responsedata["content_type"] = "text/plain";
634// responsedata["keepalive"] = false;
635// responsedata["str_response_string"] = "Not Found";
636// responsedata["error_status_text"] = "Not Found";
637// responsedata["http_protocol_version"] = "HTTP/1.0";
638// return responsedata;
639// // return 404
640// }
641// }
642// else
643// {
644// responsedata["int_response_code"] = 404;
645// responsedata["content_type"] = "text/plain";
646// responsedata["keepalive"] = false;
647// responsedata["str_response_string"] = "Not Found";
648// responsedata["error_status_text"] = "Not Found";
649// responsedata["http_protocol_version"] = "HTTP/1.0";
650// return responsedata;
651// // return 404
652// }
653// }
654
655 public OSD EventQueueFallBack(string path, OSD request, string endpoint)
656 {
657 // This is a fallback element to keep the client from loosing EventQueueGet
658 // Why does CAPS fail sometimes!?
659 m_log.Warn("[EVENTQUEUE]: In the Fallback handler! We lost the Queue in the rest handler!");
660 string capuuid = path.Replace("/CAPS/EQG/","");
661 capuuid = capuuid.Substring(0, capuuid.Length - 1);
662
663// UUID AvatarID = UUID.Zero;
664 UUID capUUID = UUID.Zero;
665 if (UUID.TryParse(capuuid, out capUUID))
666 {
667/* Don't remove this yet code cleaners!
668 * Still testing this!
669 *
670 lock (m_QueueUUIDAvatarMapping)
671 {
672 if (m_QueueUUIDAvatarMapping.ContainsKey(capUUID))
673 {
674 AvatarID = m_QueueUUIDAvatarMapping[capUUID];
675 }
676 }
677
678
679 if (AvatarID != UUID.Zero)
680 {
681 // Repair the CAP!
682 //OpenSim.Framework.Capabilities.Caps caps = m_scene.GetCapsHandlerForUser(AvatarID);
683 //string capsBase = "/CAPS/EQG/";
684 //caps.RegisterHandler("EventQueueGet",
685 //new RestHTTPHandler("POST", capsBase + capUUID.ToString() + "/",
686 //delegate(Hashtable m_dhttpMethod)
687 //{
688 // return ProcessQueue(m_dhttpMethod, AvatarID, caps);
689 //}));
690 // start new ID sequence.
691 Random rnd = new Random(System.Environment.TickCount);
692 lock (m_ids)
693 {
694 if (!m_ids.ContainsKey(AvatarID))
695 m_ids.Add(AvatarID, rnd.Next(30000000));
696 }
697
698
699 int thisID = 0;
700 lock (m_ids)
701 thisID = m_ids[AvatarID];
702
703 BlockingLLSDQueue queue = GetQueue(AvatarID);
704 OSDArray array = new OSDArray();
705 LLSD element = queue.Dequeue(15000); // 15s timeout
706 if (element == null)
707 {
708
709 array.Add(EventQueueHelper.KeepAliveEvent());
710 }
711 else
712 {
713 array.Add(element);
714 while (queue.Count() > 0)
715 {
716 array.Add(queue.Dequeue(1));
717 thisID++;
718 }
719 }
720 OSDMap events = new OSDMap();
721 events.Add("events", array);
722
723 events.Add("id", new LLSDInteger(thisID));
724
725 lock (m_ids)
726 {
727 m_ids[AvatarID] = thisID + 1;
728 }
729
730 return events;
731 }
732 else
733 {
734 return new LLSD();
735 }
736*
737*/
738 }
739 else
740 {
741 //return new LLSD();
742 }
743
744 return new OSDString("shutdown404!");
745 }
746
747 public void DisableSimulator(ulong handle, UUID avatarID) 473 public void DisableSimulator(ulong handle, UUID avatarID)
748 { 474 {
749 OSD item = EventQueueHelper.DisableSimulator(handle); 475 OSD item = EventQueueHelper.DisableSimulator(handle);
750 Enqueue(item, avatarID); 476 Enqueue(item, avatarID);
751 } 477 }
752 478
753 public virtual void EnableSimulator(ulong handle, IPEndPoint endPoint, UUID avatarID) 479 public virtual void EnableSimulator(ulong handle, IPEndPoint endPoint, UUID avatarID, int regionSizeX, int regionSizeY)
754 { 480 {
755 OSD item = EventQueueHelper.EnableSimulator(handle, endPoint); 481 m_log.DebugFormat("{0} EnableSimulator. handle={1}, avatarID={2}, regionSize={3},{4}>",
482 "[EVENT QUEUE GET MODULE]", handle, avatarID, regionSizeX, regionSizeY);
483
484 OSD item = EventQueueHelper.EnableSimulator(handle, endPoint, regionSizeX, regionSizeY);
756 Enqueue(item, avatarID); 485 Enqueue(item, avatarID);
757 } 486 }
758 487
759 public virtual void EstablishAgentCommunication(UUID avatarID, IPEndPoint endPoint, string capsPath) 488 public virtual void EstablishAgentCommunication(UUID avatarID, IPEndPoint endPoint, string capsPath,
489 ulong regionHandle, int regionSizeX, int regionSizeY)
760 { 490 {
761 OSD item = EventQueueHelper.EstablishAgentCommunication(avatarID, endPoint.ToString(), capsPath); 491 m_log.DebugFormat("{0} EstablishAgentCommunication. handle={1}, avatarID={2}, regionSize={3},{4}>",
492 "[EVENT QUEUE GET MODULE]", regionHandle, avatarID, regionSizeX, regionSizeY);
493 OSD item = EventQueueHelper.EstablishAgentCommunication(avatarID, endPoint.ToString(), capsPath, regionHandle, regionSizeX, regionSizeY);
762 Enqueue(item, avatarID); 494 Enqueue(item, avatarID);
763 } 495 }
764 496
765 public virtual void TeleportFinishEvent(ulong regionHandle, byte simAccess, 497 public virtual void TeleportFinishEvent(ulong regionHandle, byte simAccess,
766 IPEndPoint regionExternalEndPoint, 498 IPEndPoint regionExternalEndPoint,
767 uint locationID, uint flags, string capsURL, 499 uint locationID, uint flags, string capsURL,
768 UUID avatarID) 500 UUID avatarID, int regionSizeX, int regionSizeY)
769 { 501 {
502 m_log.DebugFormat("{0} TeleportFinishEvent. handle={1}, avatarID={2}, regionSize={3},{4}>",
503 "[EVENT QUEUE GET MODULE]", regionHandle, avatarID, regionSizeX, regionSizeY);
504
770 OSD item = EventQueueHelper.TeleportFinishEvent(regionHandle, simAccess, regionExternalEndPoint, 505 OSD item = EventQueueHelper.TeleportFinishEvent(regionHandle, simAccess, regionExternalEndPoint,
771 locationID, flags, capsURL, avatarID); 506 locationID, flags, capsURL, avatarID, regionSizeX, regionSizeY);
772 Enqueue(item, avatarID); 507 Enqueue(item, avatarID);
773 } 508 }
774 509
775 public virtual void CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt, 510 public virtual void CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt,
776 IPEndPoint newRegionExternalEndPoint, 511 IPEndPoint newRegionExternalEndPoint,
777 string capsURL, UUID avatarID, UUID sessionID) 512 string capsURL, UUID avatarID, UUID sessionID, int regionSizeX, int regionSizeY)
778 { 513 {
514 m_log.DebugFormat("{0} CrossRegion. handle={1}, avatarID={2}, regionSize={3},{4}>",
515 "[EVENT QUEUE GET MODULE]", handle, avatarID, regionSizeX, regionSizeY);
516
779 OSD item = EventQueueHelper.CrossRegion(handle, pos, lookAt, newRegionExternalEndPoint, 517 OSD item = EventQueueHelper.CrossRegion(handle, pos, lookAt, newRegionExternalEndPoint,
780 capsURL, avatarID, sessionID); 518 capsURL, avatarID, sessionID, regionSizeX, regionSizeY);
781 Enqueue(item, avatarID); 519 Enqueue(item, avatarID);
782 } 520 }
783 521
@@ -794,12 +532,12 @@ namespace OpenSim.Region.ClientStack.Linden
794 532
795 } 533 }
796 534
797 public void ChatterBoxSessionAgentListUpdates(UUID sessionID, UUID fromAgent, UUID toAgent, bool canVoiceChat, 535 public void ChatterBoxSessionAgentListUpdates(UUID sessionID, UUID fromAgent, UUID anotherAgent, bool canVoiceChat,
798 bool isModerator, bool textMute) 536 bool isModerator, bool textMute)
799 { 537 {
800 OSD item = EventQueueHelper.ChatterBoxSessionAgentListUpdates(sessionID, fromAgent, canVoiceChat, 538 OSD item = EventQueueHelper.ChatterBoxSessionAgentListUpdates(sessionID, fromAgent, canVoiceChat,
801 isModerator, textMute); 539 isModerator, textMute);
802 Enqueue(item, toAgent); 540 Enqueue(item, fromAgent);
803 //m_log.InfoFormat("########### eq ChatterBoxSessionAgentListUpdates #############\n{0}", item); 541 //m_log.InfoFormat("########### eq ChatterBoxSessionAgentListUpdates #############\n{0}", item);
804 } 542 }
805 543
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
index 7dcf137..3fb7de2 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
@@ -70,13 +70,15 @@ namespace OpenSim.Region.ClientStack.Linden
70 return llsdEvent; 70 return llsdEvent;
71 } 71 }
72 72
73 public static OSD EnableSimulator(ulong handle, IPEndPoint endPoint) 73 public static OSD EnableSimulator(ulong handle, IPEndPoint endPoint, int regionSizeX, int regionSizeY)
74 { 74 {
75 OSDMap llsdSimInfo = new OSDMap(3); 75 OSDMap llsdSimInfo = new OSDMap(5);
76 76
77 llsdSimInfo.Add("Handle", new OSDBinary(ulongToByteArray(handle))); 77 llsdSimInfo.Add("Handle", new OSDBinary(ulongToByteArray(handle)));
78 llsdSimInfo.Add("IP", new OSDBinary(endPoint.Address.GetAddressBytes())); 78 llsdSimInfo.Add("IP", new OSDBinary(endPoint.Address.GetAddressBytes()));
79 llsdSimInfo.Add("Port", new OSDInteger(endPoint.Port)); 79 llsdSimInfo.Add("Port", new OSDInteger(endPoint.Port));
80 llsdSimInfo.Add("RegionSizeX", new OSDInteger(regionSizeX));
81 llsdSimInfo.Add("RegionSizeY", new OSDInteger(regionSizeY));
80 82
81 OSDArray arr = new OSDArray(1); 83 OSDArray arr = new OSDArray(1);
82 arr.Add(llsdSimInfo); 84 arr.Add(llsdSimInfo);
@@ -104,7 +106,8 @@ namespace OpenSim.Region.ClientStack.Linden
104 106
105 public static OSD CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt, 107 public static OSD CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt,
106 IPEndPoint newRegionExternalEndPoint, 108 IPEndPoint newRegionExternalEndPoint,
107 string capsURL, UUID agentID, UUID sessionID) 109 string capsURL, UUID agentID, UUID sessionID,
110 int regionSizeX, int regionSizeY)
108 { 111 {
109 OSDArray lookAtArr = new OSDArray(3); 112 OSDArray lookAtArr = new OSDArray(3);
110 lookAtArr.Add(OSD.FromReal(lookAt.X)); 113 lookAtArr.Add(OSD.FromReal(lookAt.X));
@@ -130,11 +133,13 @@ namespace OpenSim.Region.ClientStack.Linden
130 OSDArray agentDataArr = new OSDArray(1); 133 OSDArray agentDataArr = new OSDArray(1);
131 agentDataArr.Add(agentDataMap); 134 agentDataArr.Add(agentDataMap);
132 135
133 OSDMap regionDataMap = new OSDMap(4); 136 OSDMap regionDataMap = new OSDMap(6);
134 regionDataMap.Add("RegionHandle", OSD.FromBinary(ulongToByteArray(handle))); 137 regionDataMap.Add("RegionHandle", OSD.FromBinary(ulongToByteArray(handle)));
135 regionDataMap.Add("SeedCapability", OSD.FromString(capsURL)); 138 regionDataMap.Add("SeedCapability", OSD.FromString(capsURL));
136 regionDataMap.Add("SimIP", OSD.FromBinary(newRegionExternalEndPoint.Address.GetAddressBytes())); 139 regionDataMap.Add("SimIP", OSD.FromBinary(newRegionExternalEndPoint.Address.GetAddressBytes()));
137 regionDataMap.Add("SimPort", OSD.FromInteger(newRegionExternalEndPoint.Port)); 140 regionDataMap.Add("SimPort", OSD.FromInteger(newRegionExternalEndPoint.Port));
141 regionDataMap.Add("RegionSizeX", new OSDInteger(regionSizeX));
142 regionDataMap.Add("RegionSizeY", new OSDInteger(regionSizeY));
138 143
139 OSDArray regionDataArr = new OSDArray(1); 144 OSDArray regionDataArr = new OSDArray(1);
140 regionDataArr.Add(regionDataMap); 145 regionDataArr.Add(regionDataMap);
@@ -148,8 +153,9 @@ namespace OpenSim.Region.ClientStack.Linden
148 } 153 }
149 154
150 public static OSD TeleportFinishEvent( 155 public static OSD TeleportFinishEvent(
151 ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint, 156 ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint,
152 uint locationID, uint flags, string capsURL, UUID agentID) 157 uint locationID, uint flags, string capsURL, UUID agentID,
158 int regionSizeX, int regionSizeY)
153 { 159 {
154 // not sure why flags get overwritten here 160 // not sure why flags get overwritten here
155 if ((flags & (uint)TeleportFlags.IsFlying) != 0) 161 if ((flags & (uint)TeleportFlags.IsFlying) != 0)
@@ -167,6 +173,8 @@ namespace OpenSim.Region.ClientStack.Linden
167 info.Add("SimPort", OSD.FromInteger(regionExternalEndPoint.Port)); 173 info.Add("SimPort", OSD.FromInteger(regionExternalEndPoint.Port));
168// info.Add("TeleportFlags", OSD.FromULong(1L << 4)); // AgentManager.TeleportFlags.ViaLocation 174// info.Add("TeleportFlags", OSD.FromULong(1L << 4)); // AgentManager.TeleportFlags.ViaLocation
169 info.Add("TeleportFlags", OSD.FromUInteger(flags)); 175 info.Add("TeleportFlags", OSD.FromUInteger(flags));
176 info.Add("RegionSizeX", new OSDInteger(regionSizeX));
177 info.Add("RegionSizeY", new OSDInteger(regionSizeY));
170 178
171 OSDArray infoArr = new OSDArray(); 179 OSDArray infoArr = new OSDArray();
172 infoArr.Add(info); 180 infoArr.Add(info);
@@ -194,12 +202,18 @@ namespace OpenSim.Region.ClientStack.Linden
194 return BuildEvent("ScriptRunningReply", body); 202 return BuildEvent("ScriptRunningReply", body);
195 } 203 }
196 204
197 public static OSD EstablishAgentCommunication(UUID agentID, string simIpAndPort, string seedcap) 205 public static OSD EstablishAgentCommunication(UUID agentID, string simIpAndPort, string seedcap,
206 ulong regionHandle, int regionSizeX, int regionSizeY)
198 { 207 {
199 OSDMap body = new OSDMap(3); 208 OSDMap body = new OSDMap(6)
200 body.Add("agent-id", new OSDUUID(agentID)); 209 {
201 body.Add("sim-ip-and-port", new OSDString(simIpAndPort)); 210 {"agent-id", new OSDUUID(agentID)},
202 body.Add("seed-capability", new OSDString(seedcap)); 211 {"sim-ip-and-port", new OSDString(simIpAndPort)},
212 {"seed-capability", new OSDString(seedcap)},
213 {"region-handle", OSD.FromULong(regionHandle)},
214 {"region-size-x", OSD.FromInteger(regionSizeX)},
215 {"region-size-y", OSD.FromInteger(regionSizeY)}
216 };
203 217
204 return BuildEvent("EstablishAgentCommunication", body); 218 return BuildEvent("EstablishAgentCommunication", body);
205 } 219 }
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs
index 141af8a..9e24bce 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs
@@ -76,7 +76,7 @@ namespace OpenSim.Region.ClientStack.Linden.Tests
76 } 76 }
77 77
78 [Test] 78 [Test]
79 public void AddForClient() 79 public void TestAddForClient()
80 { 80 {
81 TestHelpers.InMethod(); 81 TestHelpers.InMethod();
82// log4net.Config.XmlConfigurator.Configure(); 82// log4net.Config.XmlConfigurator.Configure();
@@ -88,15 +88,15 @@ namespace OpenSim.Region.ClientStack.Linden.Tests
88 } 88 }
89 89
90 [Test] 90 [Test]
91 public void RemoveForClient() 91 public void TestRemoveForClient()
92 { 92 {
93 TestHelpers.InMethod(); 93 TestHelpers.InMethod();
94// log4net.Config.XmlConfigurator.Configure(); 94// TestHelpers.EnableLogging();
95 95
96 UUID spId = TestHelpers.ParseTail(0x1); 96 UUID spId = TestHelpers.ParseTail(0x1);
97 97
98 SceneHelpers.AddScenePresence(m_scene, spId); 98 SceneHelpers.AddScenePresence(m_scene, spId);
99 m_scene.IncomingCloseAgent(spId, false); 99 m_scene.CloseAgent(spId, false);
100 100
101 // TODO: Add more assertions for the other aspects of event queues 101 // TODO: Add more assertions for the other aspects of event queues
102 Assert.That(MainServer.Instance.GetPollServiceHandlerKeys().Count, Is.EqualTo(0)); 102 Assert.That(MainServer.Instance.GetPollServiceHandlerKeys().Count, Is.EqualTo(0));
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs
index 6ec1115..a381a1b 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs
@@ -189,9 +189,8 @@ namespace OpenSim.Region.ClientStack.Linden
189 // Now we know when the throttle is changed by the client in the case of a root agent or by a neighbor region in the case of a child agent. 189 // Now we know when the throttle is changed by the client in the case of a root agent or by a neighbor region in the case of a child agent.
190 public void ThrottleUpdate(ScenePresence p) 190 public void ThrottleUpdate(ScenePresence p)
191 { 191 {
192 byte[] throttles = p.ControllingClient.GetThrottlesPacked(1);
193 UUID user = p.UUID; 192 UUID user = p.UUID;
194 int imagethrottle = ExtractTaskThrottle(throttles); 193 int imagethrottle = p.ControllingClient.GetAgentThrottleSilent((int)ThrottleOutPacketType.Asset);
195 PollServiceMeshEventArgs args; 194 PollServiceMeshEventArgs args;
196 if (m_pollservices.TryGetValue(user, out args)) 195 if (m_pollservices.TryGetValue(user, out args))
197 { 196 {
@@ -199,44 +198,6 @@ namespace OpenSim.Region.ClientStack.Linden
199 } 198 }
200 } 199 }
201 200
202 private int ExtractTaskThrottle(byte[] pthrottles)
203 {
204
205 byte[] adjData;
206 int pos = 0;
207
208 if (!BitConverter.IsLittleEndian)
209 {
210 byte[] newData = new byte[7 * 4];
211 Buffer.BlockCopy(pthrottles, 0, newData, 0, 7 * 4);
212
213 for (int i = 0; i < 7; i++)
214 Array.Reverse(newData, i * 4, 4);
215
216 adjData = newData;
217 }
218 else
219 {
220 adjData = pthrottles;
221 }
222
223 // 0.125f converts from bits to bytes
224 //int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
225 //pos += 4;
226 // int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
227 //pos += 4;
228 // int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
229 // pos += 4;
230 // int cloud = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
231 // pos += 4;
232 pos += 16;
233 int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
234 // pos += 4;
235 //int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); //pos += 4;
236 //int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
237 return task;
238 }
239
240 private class PollServiceMeshEventArgs : PollServiceEventArgs 201 private class PollServiceMeshEventArgs : PollServiceEventArgs
241 { 202 {
242 private List<Hashtable> requests = 203 private List<Hashtable> requests =
@@ -246,8 +207,8 @@ namespace OpenSim.Region.ClientStack.Linden
246 207
247 private Scene m_scene; 208 private Scene m_scene;
248 private MeshCapsDataThrottler m_throttler; 209 private MeshCapsDataThrottler m_throttler;
249 public PollServiceMeshEventArgs(UUID pId, Scene scene) : 210 public PollServiceMeshEventArgs(string uri, UUID pId, Scene scene) :
250 base(null, null, null, null, pId, int.MaxValue) 211 base(null, uri, null, null, null, pId, int.MaxValue)
251 { 212 {
252 m_scene = scene; 213 m_scene = scene;
253 m_throttler = new MeshCapsDataThrottler(100000, 1400000, 10000, scene, pId); 214 m_throttler = new MeshCapsDataThrottler(100000, 1400000, 10000, scene, pId);
@@ -361,7 +322,7 @@ namespace OpenSim.Region.ClientStack.Linden
361 string capUrl = "/CAPS/" + UUID.Random() + "/"; 322 string capUrl = "/CAPS/" + UUID.Random() + "/";
362 323
363 // Register this as a poll service 324 // Register this as a poll service
364 PollServiceMeshEventArgs args = new PollServiceMeshEventArgs(agentID, m_scene); 325 PollServiceMeshEventArgs args = new PollServiceMeshEventArgs(capUrl, agentID, m_scene);
365 326
366 args.Type = PollServiceEventArgs.EventType.Mesh; 327 args.Type = PollServiceEventArgs.EventType.Mesh;
367 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args); 328 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
@@ -425,7 +386,7 @@ namespace OpenSim.Region.ClientStack.Linden
425 { 386 {
426 ThrottleBytes = pBytes; 387 ThrottleBytes = pBytes;
427 lastTimeElapsed = Util.EnvironmentTickCount(); 388 lastTimeElapsed = Util.EnvironmentTickCount();
428 Throttle = ThrottleOutPacketType.Task; 389 Throttle = ThrottleOutPacketType.Asset;
429 m_scene = pScene; 390 m_scene = pScene;
430 User = puser; 391 User = puser;
431 } 392 }
@@ -550,8 +511,8 @@ namespace OpenSim.Region.ClientStack.Linden
550// UDPSetThrottle = (int) (pimagethrottle*(100 - CapThrottleDistributon)); 511// UDPSetThrottle = (int) (pimagethrottle*(100 - CapThrottleDistributon));
551 512
552 float udp = 1.0f - CapThrottleDistributon; 513 float udp = 1.0f - CapThrottleDistributon;
553 if(udp < 0.5f) 514 if(udp < 0.7f)
554 udp = 0.5f; 515 udp = 0.7f;
555 UDPSetThrottle = (int) ((float)pimagethrottle * udp); 516 UDPSetThrottle = (int) ((float)pimagethrottle * udp);
556 if (CapSetThrottle < 4068) 517 if (CapSetThrottle < 4068)
557 CapSetThrottle = 4068; // at least two discovery mesh 518 CapSetThrottle = 4068; // at least two discovery mesh
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
index 0570144..e053054 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
@@ -84,6 +84,8 @@ namespace OpenSim.Region.ClientStack.Linden
84 84
85 private Dictionary<UUID,PollServiceTextureEventArgs> m_pollservices = new Dictionary<UUID,PollServiceTextureEventArgs>(); 85 private Dictionary<UUID,PollServiceTextureEventArgs> m_pollservices = new Dictionary<UUID,PollServiceTextureEventArgs>();
86 86
87 private string m_URL;
88
87 #region ISharedRegionModule Members 89 #region ISharedRegionModule Members
88 90
89 public void Initialise(IConfigSource source) 91 public void Initialise(IConfigSource source)
@@ -215,7 +217,7 @@ namespace OpenSim.Region.ClientStack.Linden
215 private Scene m_scene; 217 private Scene m_scene;
216 private CapsDataThrottler m_throttler = new CapsDataThrottler(100000, 1400000,10000); 218 private CapsDataThrottler m_throttler = new CapsDataThrottler(100000, 1400000,10000);
217 public PollServiceTextureEventArgs(UUID pId, Scene scene) : 219 public PollServiceTextureEventArgs(UUID pId, Scene scene) :
218 base(null, null, null, null, pId, int.MaxValue) 220 base(null, "", null, null, null, pId, int.MaxValue)
219 { 221 {
220 m_scene = scene; 222 m_scene = scene;
221 // x is request id, y is userid 223 // x is request id, y is userid
@@ -368,7 +370,11 @@ namespace OpenSim.Region.ClientStack.Linden
368 port = MainServer.Instance.SSLPort; 370 port = MainServer.Instance.SSLPort;
369 protocol = "https"; 371 protocol = "https";
370 } 372 }
371 caps.RegisterHandler("GetTexture", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl)); 373 IExternalCapsModule handler = m_scene.RequestModuleInterface<IExternalCapsModule>();
374 if (handler != null)
375 handler.RegisterExternalUserCapsHandler(agentID, caps, "GetTexture", capUrl);
376 else
377 caps.RegisterHandler("GetTexture", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
372 m_pollservices[agentID] = args; 378 m_pollservices[agentID] = args;
373 m_capsDict[agentID] = capUrl; 379 m_capsDict[agentID] = capUrl;
374 } 380 }
@@ -380,13 +386,11 @@ namespace OpenSim.Region.ClientStack.Linden
380 386
381 private void DeregisterCaps(UUID agentID, Caps caps) 387 private void DeregisterCaps(UUID agentID, Caps caps)
382 { 388 {
383 string capUrl;
384 PollServiceTextureEventArgs args; 389 PollServiceTextureEventArgs args;
385 if (m_capsDict.TryGetValue(agentID, out capUrl)) 390
386 { 391 MainServer.Instance.RemoveHTTPHandler("", m_URL);
387 MainServer.Instance.RemoveHTTPHandler("", capUrl); 392 m_capsDict.Remove(agentID);
388 m_capsDict.Remove(agentID); 393
389 }
390 if (m_pollservices.TryGetValue(agentID, out args)) 394 if (m_pollservices.TryGetValue(agentID, out args))
391 { 395 {
392 m_pollservices.Remove(agentID); 396 m_pollservices.Remove(agentID);
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs
index 92805e2..94f8bc1 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs
@@ -155,6 +155,7 @@ namespace OpenSim.Region.ClientStack.Linden
155 Quaternion rotation = Quaternion.Identity; 155 Quaternion rotation = Quaternion.Identity;
156 Vector3 scale = Vector3.Zero; 156 Vector3 scale = Vector3.Zero;
157 int state = 0; 157 int state = 0;
158 int lastattach = 0;
158 159
159 if (r.Type != OSDType.Map) // not a proper req 160 if (r.Type != OSDType.Map) // not a proper req
160 return responsedata; 161 return responsedata;
@@ -224,6 +225,7 @@ namespace OpenSim.Region.ClientStack.Linden
224 225
225 ray_target_id = ObjMap["RayTargetId"].AsUUID(); 226 ray_target_id = ObjMap["RayTargetId"].AsUUID();
226 state = ObjMap["State"].AsInteger(); 227 state = ObjMap["State"].AsInteger();
228 lastattach = ObjMap["LastAttachPoint"].AsInteger();
227 try 229 try
228 { 230 {
229 ray_end = ((OSDArray)ObjMap["RayEnd"]).AsVector3(); 231 ray_end = ((OSDArray)ObjMap["RayEnd"]).AsVector3();
@@ -290,6 +292,7 @@ namespace OpenSim.Region.ClientStack.Linden
290 292
291 //session_id = rm["session_id"].AsUUID(); 293 //session_id = rm["session_id"].AsUUID();
292 state = rm["state"].AsInteger(); 294 state = rm["state"].AsInteger();
295 lastattach = rm["last_attach_point"].AsInteger();
293 try 296 try
294 { 297 {
295 ray_end = ((OSDArray)rm["ray_end"]).AsVector3(); 298 ray_end = ((OSDArray)rm["ray_end"]).AsVector3();
@@ -331,6 +334,7 @@ namespace OpenSim.Region.ClientStack.Linden
331 pbs.ProfileEnd = (ushort)profile_end; 334 pbs.ProfileEnd = (ushort)profile_end;
332 pbs.Scale = scale; 335 pbs.Scale = scale;
333 pbs.State = (byte)state; 336 pbs.State = (byte)state;
337 pbs.LastAttachPoint = (byte)lastattach;
334 338
335 SceneObjectGroup obj = null; ; 339 SceneObjectGroup obj = null; ;
336 340
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs
index 55a503e..769fe28 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs
@@ -277,6 +277,7 @@ namespace OpenSim.Region.ClientStack.Linden
277 pbs.ProfileEnd = (ushort) obj.ProfileEnd; 277 pbs.ProfileEnd = (ushort) obj.ProfileEnd;
278 pbs.Scale = obj.Scale; 278 pbs.Scale = obj.Scale;
279 pbs.State = (byte) 0; 279 pbs.State = (byte) 0;
280 pbs.LastAttachPoint = (byte) 0;
280 SceneObjectPart prim = new SceneObjectPart(); 281 SceneObjectPart prim = new SceneObjectPart();
281 prim.UUID = UUID.Random(); 282 prim.UUID = UUID.Random();
282 prim.CreatorID = AgentId; 283 prim.CreatorID = AgentId;
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs b/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs
index 595d01a..112608b 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.6.*")] 32[assembly: AssemblyVersion("0.8.0.*")]
33 33
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
index 79d56c4..5196368 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
@@ -183,7 +183,7 @@ namespace OpenSim.Region.ClientStack.Linden
183 m_isGod = m_scene.Permissions.IsGod(agentID); 183 m_isGod = m_scene.Permissions.IsGod(agentID);
184 } 184 }
185 185
186 public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) 186 protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
187 { 187 {
188 StreamReader reader = new StreamReader(request); 188 StreamReader reader = new StreamReader(request);
189 string message = reader.ReadToEnd(); 189 string message = reader.ReadToEnd();
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs
index 7d9f935..bedec80 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs
@@ -68,7 +68,6 @@ namespace OpenSim.Region.ClientStack.Linden
68 /// </summary> 68 /// </summary>
69 private OSDMap m_features = new OSDMap(); 69 private OSDMap m_features = new OSDMap();
70 70
71 private string m_MapImageServerURL = string.Empty;
72 private string m_SearchURL = string.Empty; 71 private string m_SearchURL = string.Empty;
73 private bool m_ExportSupported = false; 72 private bool m_ExportSupported = false;
74 73
@@ -78,15 +77,7 @@ namespace OpenSim.Region.ClientStack.Linden
78 { 77 {
79 IConfig config = source.Configs["SimulatorFeatures"]; 78 IConfig config = source.Configs["SimulatorFeatures"];
80 if (config != null) 79 if (config != null)
81 { 80 {
82 m_MapImageServerURL = config.GetString("MapImageServerURI", string.Empty);
83 if (m_MapImageServerURL != string.Empty)
84 {
85 m_MapImageServerURL = m_MapImageServerURL.Trim();
86 if (!m_MapImageServerURL.EndsWith("/"))
87 m_MapImageServerURL = m_MapImageServerURL + "/";
88 }
89
90 m_SearchURL = config.GetString("SearchServerURI", string.Empty); 81 m_SearchURL = config.GetString("SearchServerURI", string.Empty);
91 82
92 m_ExportSupported = config.GetBoolean("ExportSupported", m_ExportSupported); 83 m_ExportSupported = config.GetBoolean("ExportSupported", m_ExportSupported);
@@ -140,8 +131,9 @@ namespace OpenSim.Region.ClientStack.Linden
140 m_features["MeshRezEnabled"] = true; 131 m_features["MeshRezEnabled"] = true;
141 m_features["MeshUploadEnabled"] = true; 132 m_features["MeshUploadEnabled"] = true;
142 m_features["MeshXferEnabled"] = true; 133 m_features["MeshXferEnabled"] = true;
134
143 m_features["PhysicsMaterialsEnabled"] = true; 135 m_features["PhysicsMaterialsEnabled"] = true;
144 136
145 OSDMap typesMap = new OSDMap(); 137 OSDMap typesMap = new OSDMap();
146 typesMap["convex"] = true; 138 typesMap["convex"] = true;
147 typesMap["none"] = true; 139 typesMap["none"] = true;
@@ -149,15 +141,20 @@ namespace OpenSim.Region.ClientStack.Linden
149 m_features["PhysicsShapeTypes"] = typesMap; 141 m_features["PhysicsShapeTypes"] = typesMap;
150 142
151 // Extra information for viewers that want to use it 143 // Extra information for viewers that want to use it
152 OSDMap gridServicesMap = new OSDMap(); 144
153 if (m_MapImageServerURL != string.Empty) 145 OSDMap extrasMap = new OSDMap();
154 gridServicesMap["map-server-url"] = m_MapImageServerURL;
155 if (m_SearchURL != string.Empty)
156 gridServicesMap["search"] = m_SearchURL;
157 m_features["GridServices"] = gridServicesMap;
158 146
147 extrasMap["AvatarSkeleton"] = true;
148 extrasMap["AnimationSet"] = true;
149
150 // TODO: Take these out of here into their respective modules, like map-server-url
151 if (m_SearchURL != string.Empty)
152 extrasMap["search-server-url"] = m_SearchURL;
159 if (m_ExportSupported) 153 if (m_ExportSupported)
160 m_features["ExportSupported"] = true; 154 extrasMap["ExportSupported"] = true;
155
156 m_features["OpenSimExtras"] = extrasMap;
157
161 } 158 }
162 } 159 }
163 160
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs
index eca576d..50e9275 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs
@@ -64,11 +64,18 @@ namespace OpenSim.Region.ClientStack.Linden
64 64
65 private Scene m_scene; 65 private Scene m_scene;
66 private bool m_persistBakedTextures; 66 private bool m_persistBakedTextures;
67 private string m_URL;
67 68
68 private IBakedTextureModule m_BakedTextureModule; 69 private IBakedTextureModule m_BakedTextureModule;
69 70
70 public void Initialise(IConfigSource source) 71 public void Initialise(IConfigSource source)
71 { 72 {
73 IConfig config = source.Configs["ClientStack.LindenCaps"];
74 if (config == null)
75 return;
76
77 m_URL = config.GetString("Cap_UploadBakedTexture", string.Empty);
78
72 IConfig appearanceConfig = source.Configs["Appearance"]; 79 IConfig appearanceConfig = source.Configs["Appearance"];
73 if (appearanceConfig != null) 80 if (appearanceConfig != null)
74 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures); 81 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures);
@@ -89,9 +96,7 @@ namespace OpenSim.Region.ClientStack.Linden
89 s.EventManager.OnRemovePresence -= DeRegisterPresence; 96 s.EventManager.OnRemovePresence -= DeRegisterPresence;
90 m_BakedTextureModule = null; 97 m_BakedTextureModule = null;
91 m_scene = null; 98 m_scene = null;
92 } 99 }
93
94
95 100
96 public void RegionLoaded(Scene s) 101 public void RegionLoaded(Scene s)
97 { 102 {
@@ -103,44 +108,58 @@ namespace OpenSim.Region.ClientStack.Linden
103 108
104 private void DeRegisterPresence(UUID agentId) 109 private void DeRegisterPresence(UUID agentId)
105 { 110 {
106 ScenePresence presence = null; 111// ScenePresence presence = null;
107 if (m_scene.TryGetScenePresence(agentId, out presence)) 112// if (m_scene.TryGetScenePresence(agentId, out presence))
108 { 113 {
109 presence.ControllingClient.OnSetAppearance -= CaptureAppearanceSettings; 114// presence.ControllingClient.OnSetAppearance -= CaptureAppearanceSettings;
110 } 115 }
111 116
112 } 117 }
113 118
114 private void RegisterNewPresence(ScenePresence presence) 119 private void RegisterNewPresence(ScenePresence presence)
115 { 120 {
116 presence.ControllingClient.OnSetAppearance += CaptureAppearanceSettings; 121// presence.ControllingClient.OnSetAppearance += CaptureAppearanceSettings;
117
118 } 122 }
119 123
120 private void CaptureAppearanceSettings(IClientAPI remoteClient, Primitive.TextureEntry textureEntry, byte[] visualParams, Vector3 avSize, WearableCacheItem[] cacheItems) 124/* not in use. work done in AvatarFactoryModule ValidateBakedTextureCache() and UpdateBakedTextureCache()
121 { 125 private void CaptureAppearanceSettings(IClientAPI remoteClient, Primitive.TextureEntry textureEntry, byte[] visualParams, Vector3 avSize, WearableCacheItem[] cacheItems)
122 int maxCacheitemsLoop = cacheItems.Length;
123 if (maxCacheitemsLoop > AvatarWearable.MAX_WEARABLES)
124 {
125 maxCacheitemsLoop = AvatarWearable.MAX_WEARABLES;
126 m_log.WarnFormat("[CACHEDBAKES]: Too Many Cache items Provided {0}, the max is {1}. Truncating!", cacheItems.Length, AvatarWearable.MAX_WEARABLES);
127 }
128
129 m_BakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
130 if (cacheItems.Length > 0)
131 {
132 m_log.Debug("[Cacheitems]: " + cacheItems.Length);
133 for (int iter = 0; iter < maxCacheitemsLoop; iter++)
134 {
135 m_log.Debug("[Cacheitems] {" + iter + "/" + cacheItems[iter].TextureIndex + "}: c-" + cacheItems[iter].CacheId + ", t-" +
136 cacheItems[iter].TextureID);
137 }
138
139 ScenePresence p = null;
140 if (m_scene.TryGetScenePresence(remoteClient.AgentId, out p))
141 { 126 {
127 // if cacheItems.Length > 0 viewer is giving us current textures information.
128 // baked ones should had been uploaded and in assets cache as local itens
129
130
131 if (cacheItems.Length == 0)
132 return; // no textures information, nothing to do
133
134 ScenePresence p = null;
135 if (!m_scene.TryGetScenePresence(remoteClient.AgentId, out p))
136 return; // what are we doing if there is no presence to cache for?
137
138 if (p.IsDeleted)
139 return; // does this really work?
140
141 int maxCacheitemsLoop = cacheItems.Length;
142 if (maxCacheitemsLoop > 20)
143 {
144 maxCacheitemsLoop = AvatarWearable.MAX_WEARABLES;
145 m_log.WarnFormat("[CACHEDBAKES]: Too Many Cache items Provided {0}, the max is {1}. Truncating!", cacheItems.Length, AvatarWearable.MAX_WEARABLES);
146 }
147
148 m_BakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
149
150
151 // some nice debug
152 m_log.Debug("[Cacheitems]: " + cacheItems.Length);
153 for (int iter = 0; iter < maxCacheitemsLoop; iter++)
154 {
155 m_log.Debug("[Cacheitems] {" + iter + "/" + cacheItems[iter].TextureIndex + "}: c-" + cacheItems[iter].CacheId + ", t-" +
156 cacheItems[iter].TextureID);
157 }
158
159 // p.Appearance.WearableCacheItems is in memory primary cashID to textures mapper
142 160
143 WearableCacheItem[] existingitems = p.Appearance.WearableCacheItems; 161 WearableCacheItem[] existingitems = p.Appearance.WearableCacheItems;
162
144 if (existingitems == null) 163 if (existingitems == null)
145 { 164 {
146 if (m_BakedTextureModule != null) 165 if (m_BakedTextureModule != null)
@@ -154,38 +173,22 @@ namespace OpenSim.Region.ClientStack.Linden
154 p.Appearance.WearableCacheItems = savedcache; 173 p.Appearance.WearableCacheItems = savedcache;
155 p.Appearance.WearableCacheItemsDirty = false; 174 p.Appearance.WearableCacheItemsDirty = false;
156 } 175 }
157
158 }
159 /*
160 * The following Catch types DO NOT WORK with m_BakedTextureModule.Get
161 * it jumps to the General Packet Exception Handler if you don't catch Exception!
162 *
163 catch (System.Net.Sockets.SocketException)
164 {
165 cacheItems = null;
166 }
167 catch (WebException)
168 {
169 cacheItems = null;
170 } 176 }
171 catch (InvalidOperationException) 177
172 {
173 cacheItems = null;
174 } */
175 catch (Exception) 178 catch (Exception)
176 { 179 {
177 // The service logs a sufficient error message. 180 // The service logs a sufficient error message.
178 } 181 }
179 182
180 183
181 if (savedcache != null) 184 if (savedcache != null)
182 existingitems = savedcache; 185 existingitems = savedcache;
183 } 186 }
184 } 187 }
188
185 // Existing items null means it's a fully new appearance 189 // Existing items null means it's a fully new appearance
186 if (existingitems == null) 190 if (existingitems == null)
187 { 191 {
188
189 for (int i = 0; i < maxCacheitemsLoop; i++) 192 for (int i = 0; i < maxCacheitemsLoop; i++)
190 { 193 {
191 if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex) 194 if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex)
@@ -198,7 +201,7 @@ namespace OpenSim.Region.ClientStack.Linden
198 AppearanceManager.DEFAULT_AVATAR_TEXTURE; 201 AppearanceManager.DEFAULT_AVATAR_TEXTURE;
199 continue; 202 continue;
200 } 203 }
201 cacheItems[i].TextureID =face.TextureID; 204 cacheItems[i].TextureID = face.TextureID;
202 if (m_scene.AssetService != null) 205 if (m_scene.AssetService != null)
203 cacheItems[i].TextureAsset = 206 cacheItems[i].TextureAsset =
204 m_scene.AssetService.GetCached(cacheItems[i].TextureID.ToString()); 207 m_scene.AssetService.GetCached(cacheItems[i].TextureID.ToString());
@@ -207,15 +210,10 @@ namespace OpenSim.Region.ClientStack.Linden
207 { 210 {
208 m_log.WarnFormat("[CACHEDBAKES]: Invalid Texture Index Provided, Texture doesn't exist or hasn't been uploaded yet {0}, the max is {1}. Skipping!", cacheItems[i].TextureIndex, textureEntry.FaceTextures.Length); 211 m_log.WarnFormat("[CACHEDBAKES]: Invalid Texture Index Provided, Texture doesn't exist or hasn't been uploaded yet {0}, the max is {1}. Skipping!", cacheItems[i].TextureIndex, textureEntry.FaceTextures.Length);
209 } 212 }
210
211
212 } 213 }
213 } 214 }
214 else 215 else
215 216 {
216
217 {
218 // for each uploaded baked texture
219 for (int i = 0; i < maxCacheitemsLoop; i++) 217 for (int i = 0; i < maxCacheitemsLoop; i++)
220 { 218 {
221 if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex) 219 if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex)
@@ -246,23 +244,24 @@ namespace OpenSim.Region.ClientStack.Linden
246 } 244 }
247 } 245 }
248 } 246 }
249
250
251
252 p.Appearance.WearableCacheItems = cacheItems; 247 p.Appearance.WearableCacheItems = cacheItems;
253
254
255 248
256 if (m_BakedTextureModule != null) 249 if (m_BakedTextureModule != null)
257 { 250 {
258 m_BakedTextureModule.Store(remoteClient.AgentId, cacheItems); 251 m_BakedTextureModule.Store(remoteClient.AgentId, cacheItems);
259 p.Appearance.WearableCacheItemsDirty = true; 252 p.Appearance.WearableCacheItemsDirty = true;
260 253
261 } 254 }
262 } 255 else
263 } 256 p.Appearance.WearableCacheItemsDirty = false;
264 }
265 257
258 for (int iter = 0; iter < maxCacheitemsLoop; iter++)
259 {
260 m_log.Debug("[CacheitemsLeaving] {" + iter + "/" + cacheItems[iter].TextureIndex + "}: c-" + cacheItems[iter].CacheId + ", t-" +
261 cacheItems[iter].TextureID);
262 }
263 }
264 */
266 public void PostInitialise() 265 public void PostInitialise()
267 { 266 {
268 } 267 }
@@ -280,23 +279,28 @@ namespace OpenSim.Region.ClientStack.Linden
280 279
281 public void RegisterCaps(UUID agentID, Caps caps) 280 public void RegisterCaps(UUID agentID, Caps caps)
282 { 281 {
283 UploadBakedTextureHandler avatarhandler = new UploadBakedTextureHandler( 282// UUID capID = UUID.Random();
284 caps, m_scene.AssetService, m_persistBakedTextures);
285
286
287
288 caps.RegisterHandler(
289 "UploadBakedTexture",
290 new RestStreamHandler(
291 "POST",
292 "/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath,
293 avatarhandler.UploadBakedTexture,
294 "UploadBakedTexture",
295 agentID.ToString()));
296 283
297 284 //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture));
298 285 if (m_URL == "localhost")
286 {
287 UploadBakedTextureHandler avatarhandler = new UploadBakedTextureHandler(
288 caps, m_scene.AssetService, m_persistBakedTextures);
299 289
290 caps.RegisterHandler(
291 "UploadBakedTexture",
292 new RestStreamHandler(
293 "POST",
294 "/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath,
295 avatarhandler.UploadBakedTexture,
296 "UploadBakedTexture",
297 agentID.ToString()));
298
299 }
300 else
301 {
302 caps.RegisterHandler("UploadBakedTexture", m_URL);
303 }
300 } 304 }
301 } 305 }
302} \ No newline at end of file 306}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
index 707cc93..6fc35cd 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
@@ -71,9 +71,13 @@ namespace OpenSim.Region.ClientStack.Linden
71 private IInventoryService m_InventoryService; 71 private IInventoryService m_InventoryService;
72 private ILibraryService m_LibraryService; 72 private ILibraryService m_LibraryService;
73 73
74 private bool m_Enabled;
75
76 private string m_fetchInventoryDescendents2Url;
77 private string m_webFetchInventoryDescendentsUrl;
78
74 private static WebFetchInvDescHandler m_webFetchHandler; 79 private static WebFetchInvDescHandler m_webFetchHandler;
75 80
76 private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>();
77 private static Thread[] m_workerThreads = null; 81 private static Thread[] m_workerThreads = null;
78 82
79 private static DoubleQueue<aPollRequest> m_queue = 83 private static DoubleQueue<aPollRequest> m_queue =
@@ -83,22 +87,45 @@ namespace OpenSim.Region.ClientStack.Linden
83 87
84 public void Initialise(IConfigSource source) 88 public void Initialise(IConfigSource source)
85 { 89 {
90 IConfig config = source.Configs["ClientStack.LindenCaps"];
91 if (config == null)
92 return;
93
94 m_fetchInventoryDescendents2Url = config.GetString("Cap_FetchInventoryDescendents2", string.Empty);
95 m_webFetchInventoryDescendentsUrl = config.GetString("Cap_WebFetchInventoryDescendents", string.Empty);
96
97 if (m_fetchInventoryDescendents2Url != string.Empty || m_webFetchInventoryDescendentsUrl != string.Empty)
98 {
99 m_Enabled = true;
100 }
86 } 101 }
87 102
88 public void AddRegion(Scene s) 103 public void AddRegion(Scene s)
89 { 104 {
105 if (!m_Enabled)
106 return;
107
90 m_scene = s; 108 m_scene = s;
91 } 109 }
92 110
93 public void RemoveRegion(Scene s) 111 public void RemoveRegion(Scene s)
94 { 112 {
113 if (!m_Enabled)
114 return;
115
95 m_scene.EventManager.OnRegisterCaps -= RegisterCaps; 116 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
96 m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps; 117
118 foreach (Thread t in m_workerThreads)
119 Watchdog.AbortThread(t.ManagedThreadId);
120
97 m_scene = null; 121 m_scene = null;
98 } 122 }
99 123
100 public void RegionLoaded(Scene s) 124 public void RegionLoaded(Scene s)
101 { 125 {
126 if (!m_Enabled)
127 return;
128
102 m_InventoryService = m_scene.InventoryService; 129 m_InventoryService = m_scene.InventoryService;
103 m_LibraryService = m_scene.LibraryService; 130 m_LibraryService = m_scene.LibraryService;
104 131
@@ -106,7 +133,6 @@ namespace OpenSim.Region.ClientStack.Linden
106 m_webFetchHandler = new WebFetchInvDescHandler(m_InventoryService, m_LibraryService); 133 m_webFetchHandler = new WebFetchInvDescHandler(m_InventoryService, m_LibraryService);
107 134
108 m_scene.EventManager.OnRegisterCaps += RegisterCaps; 135 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
109 m_scene.EventManager.OnDeregisterCaps += DeregisterCaps;
110 136
111 if (m_workerThreads == null) 137 if (m_workerThreads == null)
112 { 138 {
@@ -140,12 +166,6 @@ namespace OpenSim.Region.ClientStack.Linden
140 166
141 #endregion 167 #endregion
142 168
143 ~WebFetchInvDescModule()
144 {
145 foreach (Thread t in m_workerThreads)
146 Watchdog.AbortThread(t.ManagedThreadId);
147 }
148
149 private class PollServiceInventoryEventArgs : PollServiceEventArgs 169 private class PollServiceInventoryEventArgs : PollServiceEventArgs
150 { 170 {
151 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 171 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
@@ -155,8 +175,8 @@ namespace OpenSim.Region.ClientStack.Linden
155 175
156 private Scene m_scene; 176 private Scene m_scene;
157 177
158 public PollServiceInventoryEventArgs(Scene scene, UUID pId) : 178 public PollServiceInventoryEventArgs(Scene scene, string url, UUID pId) :
159 base(null, null, null, null, pId, int.MaxValue) 179 base(null, url, null, null, null, pId, int.MaxValue)
160 { 180 {
161 m_scene = scene; 181 m_scene = scene;
162 182
@@ -278,53 +298,72 @@ namespace OpenSim.Region.ClientStack.Linden
278 requestinfo.request["body"].ToString(), String.Empty, String.Empty, null, null); 298 requestinfo.request["body"].ToString(), String.Empty, String.Empty, null, null);
279 299
280 lock (responses) 300 lock (responses)
281 responses[requestID] = response; 301 responses[requestID] = response;
282 } 302 }
283 } 303 }
284 304
285 private void RegisterCaps(UUID agentID, Caps caps) 305 private void RegisterCaps(UUID agentID, Caps caps)
286 { 306 {
287 string capUrl = "/CAPS/" + UUID.Random() + "/"; 307 RegisterFetchDescendentsCap(agentID, caps, "FetchInventoryDescendents2", m_fetchInventoryDescendents2Url);
288
289 // Register this as a poll service
290 PollServiceInventoryEventArgs args = new PollServiceInventoryEventArgs(m_scene, agentID);
291
292 args.Type = PollServiceEventArgs.EventType.Inventory;
293 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
294
295 string hostName = m_scene.RegionInfo.ExternalHostName;
296 uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
297 string protocol = "http";
298
299 if (MainServer.Instance.UseSSL)
300 {
301 hostName = MainServer.Instance.SSLCommonName;
302 port = MainServer.Instance.SSLPort;
303 protocol = "https";
304 }
305 caps.RegisterHandler("FetchInventoryDescendents2", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
306
307 m_capsDict[agentID] = capUrl;
308 } 308 }
309 309
310 private void DeregisterCaps(UUID agentID, Caps caps) 310 private void RegisterFetchDescendentsCap(UUID agentID, Caps caps, string capName, string url)
311 { 311 {
312 string capUrl; 312 string capUrl;
313 313
314 if (m_capsDict.TryGetValue(agentID, out capUrl)) 314 // disable the cap clause
315 if (url == "")
316 {
317 return;
318 }
319 // handled by the simulator
320 else if (url == "localhost")
321 {
322 capUrl = "/CAPS/" + UUID.Random() + "/";
323
324 // Register this as a poll service
325 PollServiceInventoryEventArgs args = new PollServiceInventoryEventArgs(m_scene, capUrl, agentID);
326 args.Type = PollServiceEventArgs.EventType.Inventory;
327
328 caps.RegisterPollHandler(capName, args);
329 }
330 // external handler
331 else
315 { 332 {
316 MainServer.Instance.RemoveHTTPHandler("", capUrl); 333 capUrl = url;
317 m_capsDict.Remove(agentID); 334 IExternalCapsModule handler = m_scene.RequestModuleInterface<IExternalCapsModule>();
335 if (handler != null)
336 handler.RegisterExternalUserCapsHandler(agentID,caps,capName,capUrl);
337 else
338 caps.RegisterHandler(capName, capUrl);
318 } 339 }
340
341 // m_log.DebugFormat(
342 // "[FETCH INVENTORY DESCENDENTS2 MODULE]: Registered capability {0} at {1} in region {2} for {3}",
343 // capName, capUrl, m_scene.RegionInfo.RegionName, agentID);
319 } 344 }
320 345
346// private void DeregisterCaps(UUID agentID, Caps caps)
347// {
348// string capUrl;
349//
350// if (m_capsDict.TryGetValue(agentID, out capUrl))
351// {
352// MainServer.Instance.RemoveHTTPHandler("", capUrl);
353// m_capsDict.Remove(agentID);
354// }
355// }
356
321 private void DoInventoryRequests() 357 private void DoInventoryRequests()
322 { 358 {
323 while (true) 359 while (true)
324 { 360 {
361 Watchdog.UpdateThread();
362
325 aPollRequest poolreq = m_queue.Dequeue(); 363 aPollRequest poolreq = m_queue.Dequeue();
326 364
327 poolreq.thepoll.Process(poolreq); 365 if (poolreq != null && poolreq.thepoll != null)
366 poolreq.thepoll.Process(poolreq);
328 } 367 }
329 } 368 }
330 } 369 }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
index 3995620..15d6f7f 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
@@ -424,12 +424,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
424 // foreign user is visiting, we need to try again after the first fail to the local 424 // foreign user is visiting, we need to try again after the first fail to the local
425 // asset service. 425 // asset service.
426 string assetServerURL = string.Empty; 426 string assetServerURL = string.Empty;
427 if (InventoryAccessModule.IsForeignUser(AgentID, out assetServerURL)) 427 if (InventoryAccessModule.IsForeignUser(AgentID, out assetServerURL) && !string.IsNullOrEmpty(assetServerURL))
428 { 428 {
429 if (!assetServerURL.EndsWith("/") && !assetServerURL.EndsWith("=")) 429 if (!assetServerURL.EndsWith("/") && !assetServerURL.EndsWith("="))
430 assetServerURL = assetServerURL + "/"; 430 assetServerURL = assetServerURL + "/";
431 431
432 m_log.DebugFormat("[J2KIMAGE]: texture {0} not found in local asset storage. Trying user's storage.", assetServerURL + id); 432// m_log.DebugFormat("[J2KIMAGE]: texture {0} not found in local asset storage. Trying user's storage.", assetServerURL + id);
433 AssetService.Get(assetServerURL + id, InventoryAccessModule, AssetReceived); 433 AssetService.Get(assetServerURL + id, InventoryAccessModule, AssetReceived);
434 return; 434 return;
435 } 435 }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
index 5ee1596..b7a4b93 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -84,6 +84,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
84 public event ModifyTerrain OnModifyTerrain; 84 public event ModifyTerrain OnModifyTerrain;
85 public event Action<IClientAPI> OnRegionHandShakeReply; 85 public event Action<IClientAPI> OnRegionHandShakeReply;
86 public event GenericCall1 OnRequestWearables; 86 public event GenericCall1 OnRequestWearables;
87 public event CachedTextureRequest OnCachedTextureRequest;
87 public event SetAppearance OnSetAppearance; 88 public event SetAppearance OnSetAppearance;
88 public event AvatarNowWearing OnAvatarNowWearing; 89 public event AvatarNowWearing OnAvatarNowWearing;
89 public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv; 90 public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv;
@@ -95,6 +96,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
95 public event Action<IClientAPI, bool> OnCompleteMovementToRegion; 96 public event Action<IClientAPI, bool> OnCompleteMovementToRegion;
96 public event UpdateAgent OnPreAgentUpdate; 97 public event UpdateAgent OnPreAgentUpdate;
97 public event UpdateAgent OnAgentUpdate; 98 public event UpdateAgent OnAgentUpdate;
99 public event UpdateAgent OnAgentCameraUpdate;
98 public event AgentRequestSit OnAgentRequestSit; 100 public event AgentRequestSit OnAgentRequestSit;
99 public event AgentSit OnAgentSit; 101 public event AgentSit OnAgentSit;
100 public event AvatarPickerRequest OnAvatarPickerRequest; 102 public event AvatarPickerRequest OnAvatarPickerRequest;
@@ -335,6 +337,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
335 private bool m_VelocityInterpolate = false; 337 private bool m_VelocityInterpolate = false;
336 private const uint MaxTransferBytesPerPacket = 600; 338 private const uint MaxTransferBytesPerPacket = 600;
337 339
340 private volatile bool m_justEditedTerrain = false;
338 341
339 /// <value> 342 /// <value>
340 /// List used in construction of data blocks for an object update packet. This is to stop us having to 343 /// List used in construction of data blocks for an object update packet. This is to stop us having to
@@ -355,7 +358,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
355// protected HashSet<uint> m_attachmentsSent; 358// protected HashSet<uint> m_attachmentsSent;
356 359
357 private bool m_deliverPackets = true; 360 private bool m_deliverPackets = true;
358 private int m_animationSequenceNumber = 1; 361
359 private bool m_SendLogoutPacketWhenClosing = true; 362 private bool m_SendLogoutPacketWhenClosing = true;
360 363
361 /// <summary> 364 /// <summary>
@@ -367,7 +370,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
367 /// This does mean that agent updates must be processed synchronously, at least for each client, and called methods 370 /// This does mean that agent updates must be processed synchronously, at least for each client, and called methods
368 /// cannot retain a reference to it outside of that method. 371 /// cannot retain a reference to it outside of that method.
369 /// </remarks> 372 /// </remarks>
370 private AgentUpdateArgs m_lastAgentUpdateArgs; 373 private AgentUpdateArgs m_thisAgentUpdateArgs = new AgentUpdateArgs();
371 374
372 protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>(); 375 protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>();
373 protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers 376 protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers
@@ -416,6 +419,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
416 public ulong ActiveGroupPowers { get { return m_activeGroupPowers; } } 419 public ulong ActiveGroupPowers { get { return m_activeGroupPowers; } }
417 public bool IsGroupMember(UUID groupID) { return m_groupPowers.ContainsKey(groupID); } 420 public bool IsGroupMember(UUID groupID) { return m_groupPowers.ContainsKey(groupID); }
418 421
422 public int PingTimeMS
423 {
424 get
425 {
426 if (UDPClient != null)
427 return UDPClient.PingTimeMS;
428 return 0;
429 }
430 }
431
419 /// <summary> 432 /// <summary>
420 /// Entity update queues 433 /// Entity update queues
421 /// </summary> 434 /// </summary>
@@ -437,7 +450,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
437 public string Name { get { return FirstName + " " + LastName; } } 450 public string Name { get { return FirstName + " " + LastName; } }
438 451
439 public uint CircuitCode { get { return m_circuitCode; } } 452 public uint CircuitCode { get { return m_circuitCode; } }
440 public int NextAnimationSequenceNumber { get { return m_animationSequenceNumber++; } } 453 public int NextAnimationSequenceNumber
454 {
455 get { return m_udpServer.NextAnimationSequenceNumber; }
456 }
441 457
442 /// <summary> 458 /// <summary>
443 /// As well as it's function in IClientAPI, in LLClientView we are locking on this property in order to 459 /// As well as it's function in IClientAPI, in LLClientView we are locking on this property in order to
@@ -458,6 +474,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
458 set { m_disableFacelights = value; } 474 set { m_disableFacelights = value; }
459 } 475 }
460 476
477
461 public bool SendLogoutPacketWhenClosing { set { m_SendLogoutPacketWhenClosing = value; } } 478 public bool SendLogoutPacketWhenClosing { set { m_SendLogoutPacketWhenClosing = value; } }
462 479
463 480
@@ -504,6 +521,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
504 m_udpServer = udpServer; 521 m_udpServer = udpServer;
505 m_udpClient = udpClient; 522 m_udpClient = udpClient;
506 m_udpClient.OnQueueEmpty += HandleQueueEmpty; 523 m_udpClient.OnQueueEmpty += HandleQueueEmpty;
524 m_udpClient.HasUpdates += HandleHasUpdates;
507 m_udpClient.OnPacketStats += PopulateStats; 525 m_udpClient.OnPacketStats += PopulateStats;
508 526
509 m_prioritizer = new Prioritizer(m_scene); 527 m_prioritizer = new Prioritizer(m_scene);
@@ -533,7 +551,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
533 // We still perform a force close inside the sync lock since this is intended to attempt close where 551 // We still perform a force close inside the sync lock since this is intended to attempt close where
534 // there is some unidentified connection problem, not where we have issues due to deadlock 552 // there is some unidentified connection problem, not where we have issues due to deadlock
535 if (!IsActive && !force) 553 if (!IsActive && !force)
554 {
555 m_log.DebugFormat(
556 "[CLIENT]: Not attempting to close inactive client {0} in {1} since force flag is not set",
557 Name, m_scene.Name);
558
536 return; 559 return;
560 }
537 561
538 IsActive = false; 562 IsActive = false;
539 CloseWithoutChecks(sendStop); 563 CloseWithoutChecks(sendStop);
@@ -583,7 +607,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
583 607
584 // Disable UDP handling for this client 608 // Disable UDP handling for this client
585 m_udpClient.Shutdown(); 609 m_udpClient.Shutdown();
586 610
587 611
588 //m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false)); 612 //m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false));
589 //GC.Collect(); 613 //GC.Collect();
@@ -709,12 +733,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
709 //there is a local handler for this packet type 733 //there is a local handler for this packet type
710 if (pprocessor.Async) 734 if (pprocessor.Async)
711 { 735 {
736 ClientInfo cinfo = UDPClient.GetClientInfo();
737 if (!cinfo.AsyncRequests.ContainsKey(packet.Type.ToString()))
738 cinfo.AsyncRequests[packet.Type.ToString()] = 0;
739 cinfo.AsyncRequests[packet.Type.ToString()]++;
740
712 object obj = new AsyncPacketProcess(this, pprocessor.method, packet); 741 object obj = new AsyncPacketProcess(this, pprocessor.method, packet);
713 Util.FireAndForget(ProcessSpecificPacketAsync, obj); 742 Util.FireAndForget(ProcessSpecificPacketAsync, obj);
714 result = true; 743 result = true;
715 } 744 }
716 else 745 else
717 { 746 {
747 ClientInfo cinfo = UDPClient.GetClientInfo();
748 if (!cinfo.SyncRequests.ContainsKey(packet.Type.ToString()))
749 cinfo.SyncRequests[packet.Type.ToString()] = 0;
750 cinfo.SyncRequests[packet.Type.ToString()]++;
751
718 result = pprocessor.method(this, packet); 752 result = pprocessor.method(this, packet);
719 } 753 }
720 } 754 }
@@ -729,6 +763,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
729 } 763 }
730 if (found) 764 if (found)
731 { 765 {
766 ClientInfo cinfo = UDPClient.GetClientInfo();
767 if (!cinfo.GenericRequests.ContainsKey(packet.Type.ToString()))
768 cinfo.GenericRequests[packet.Type.ToString()] = 0;
769 cinfo.GenericRequests[packet.Type.ToString()]++;
770
732 result = method(this, packet); 771 result = method(this, packet);
733 } 772 }
734 } 773 }
@@ -758,7 +797,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
758 797
759 public virtual void Start() 798 public virtual void Start()
760 { 799 {
761 m_scene.AddNewClient(this, PresenceType.User); 800 m_scene.AddNewAgent(this, PresenceType.User);
762 801
763 RefreshGroupMembership(); 802 RefreshGroupMembership();
764 } 803 }
@@ -820,14 +859,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
820 handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType); 859 handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType);
821 handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes; 860 handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes;
822 861
823 handshake.RegionInfo4 = new RegionHandshakePacket.RegionInfo4Block[0]; 862 handshake.RegionInfo4 = new RegionHandshakePacket.RegionInfo4Block[1];
824// OutPacket(handshake, ThrottleOutPacketType.Task); 863 handshake.RegionInfo4[0] = new RegionHandshakePacket.RegionInfo4Block();
825 // use same as MoveAgentIntoRegion (both should be task ) 864 handshake.RegionInfo4[0].RegionFlagsExtended = args.regionFlags;
865 handshake.RegionInfo4[0].RegionProtocols = 0; // 1 here would indicate that SSB is supported
866
826 OutPacket(handshake, ThrottleOutPacketType.Unknown); 867 OutPacket(handshake, ThrottleOutPacketType.Unknown);
827 } 868 }
828 869
870
829 public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look) 871 public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look)
830 { 872 {
873 m_thisAgentUpdateArgs.CameraAtAxis.X = float.MinValue;
874 m_thisAgentUpdateArgs.ControlFlags = uint.MaxValue;
875
831 AgentMovementCompletePacket mov = (AgentMovementCompletePacket)PacketPool.Instance.GetPacket(PacketType.AgentMovementComplete); 876 AgentMovementCompletePacket mov = (AgentMovementCompletePacket)PacketPool.Instance.GetPacket(PacketType.AgentMovementComplete);
832 mov.SimData.ChannelVersion = m_channelVersion; 877 mov.SimData.ChannelVersion = m_channelVersion;
833 mov.AgentData.SessionID = m_sessionId; 878 mov.AgentData.SessionID = m_sessionId;
@@ -1210,9 +1255,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1210 LLHeightFieldMoronize(map); 1255 LLHeightFieldMoronize(map);
1211 1256
1212 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); 1257 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
1213 layerpack.Header.Reliable = true; 1258
1259 // When a user edits the terrain, so much data is sent, the data queues up fast and presents a sub optimal editing experience.
1260 // To alleviate this issue, when the user edits the terrain, we start skipping the queues until they're done editing the terrain.
1261 // We also make them unreliable because it's extremely likely that multiple packets will be sent for a terrain patch area
1262 // invalidating previous packets for that area.
1263
1264 // It's possible for an editing user to flood themselves with edited packets but the majority of use cases are such that only a
1265 // tiny percentage of users will be editing the terrain. Other, non-editing users will see the edits much slower.
1266
1267 // One last note on this topic, by the time users are going to be editing the terrain, it's extremely likely that the sim will
1268 // have rezzed already and therefore this is not likely going to cause any additional issues with lost packets, objects or terrain
1269 // patches.
1214 1270
1215 OutPacket(layerpack, ThrottleOutPacketType.Task); 1271 // m_justEditedTerrain is volatile, so test once and duplicate two affected statements so we only have one cache miss.
1272 if (m_justEditedTerrain)
1273 {
1274 layerpack.Header.Reliable = false;
1275 OutPacket(layerpack,
1276 ThrottleOutPacketType.Unknown );
1277 }
1278 else
1279 {
1280 layerpack.Header.Reliable = true;
1281 OutPacket(layerpack,
1282 ThrottleOutPacketType.Task);
1283 }
1216 } 1284 }
1217 catch (Exception e) 1285 catch (Exception e)
1218 { 1286 {
@@ -1405,6 +1473,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1405 1473
1406 mapReply.AgentData.AgentID = AgentId; 1474 mapReply.AgentData.AgentID = AgentId;
1407 mapReply.Data = new MapBlockReplyPacket.DataBlock[mapBlocks2.Length]; 1475 mapReply.Data = new MapBlockReplyPacket.DataBlock[mapBlocks2.Length];
1476 mapReply.Size = new MapBlockReplyPacket.SizeBlock[mapBlocks2.Length];
1408 mapReply.AgentData.Flags = flag; 1477 mapReply.AgentData.Flags = flag;
1409 1478
1410 for (int i = 0; i < mapBlocks2.Length; i++) 1479 for (int i = 0; i < mapBlocks2.Length; i++)
@@ -1419,6 +1488,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1419 mapReply.Data[i].RegionFlags = mapBlocks2[i].RegionFlags; 1488 mapReply.Data[i].RegionFlags = mapBlocks2[i].RegionFlags;
1420 mapReply.Data[i].Access = mapBlocks2[i].Access; 1489 mapReply.Data[i].Access = mapBlocks2[i].Access;
1421 mapReply.Data[i].Agents = mapBlocks2[i].Agents; 1490 mapReply.Data[i].Agents = mapBlocks2[i].Agents;
1491
1492 // TODO: hookup varregion sim size here
1493 mapReply.Size[i] = new MapBlockReplyPacket.SizeBlock();
1494 mapReply.Size[i].SizeX = 256;
1495 mapReply.Size[i].SizeY = 256;
1422 } 1496 }
1423 OutPacket(mapReply, ThrottleOutPacketType.Land); 1497 OutPacket(mapReply, ThrottleOutPacketType.Land);
1424 } 1498 }
@@ -1578,13 +1652,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1578 pc.PingID.OldestUnacked = 0; 1652 pc.PingID.OldestUnacked = 0;
1579 1653
1580 OutPacket(pc, ThrottleOutPacketType.Unknown); 1654 OutPacket(pc, ThrottleOutPacketType.Unknown);
1655 UDPClient.m_lastStartpingTimeMS = Util.EnvironmentTickCount();
1581 } 1656 }
1582 1657
1583 public void SendKillObject(ulong regionHandle, List<uint> localIDs) 1658 public void SendKillObject(List<uint> localIDs)
1584 { 1659 {
1585// foreach (uint id in localIDs) 1660// foreach (uint id in localIDs)
1586// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle); 1661// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle);
1587 1662
1663 // remove pending entities
1664 lock (m_entityProps.SyncRoot)
1665 m_entityProps.Remove(localIDs);
1666 lock (m_entityUpdates.SyncRoot)
1667 m_entityUpdates.Remove(localIDs);
1668
1588 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject); 1669 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject);
1589 // TODO: don't create new blocks if recycling an old packet 1670 // TODO: don't create new blocks if recycling an old packet
1590 kill.ObjectData = new KillObjectPacket.ObjectDataBlock[localIDs.Count]; 1671 kill.ObjectData = new KillObjectPacket.ObjectDataBlock[localIDs.Count];
@@ -1596,28 +1677,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1596 kill.Header.Reliable = true; 1677 kill.Header.Reliable = true;
1597 kill.Header.Zerocoded = true; 1678 kill.Header.Zerocoded = true;
1598 1679
1599 if (localIDs.Count == 1 && m_scene.GetScenePresence(localIDs[0]) != null) 1680 OutPacket(kill, ThrottleOutPacketType.Task);
1600 { 1681 }
1601 OutPacket(kill, ThrottleOutPacketType.Task);
1602 }
1603 else
1604 {
1605 // We MUST lock for both manipulating the kill record and sending the packet, in order to avoid a race
1606 // condition where a kill can be processed before an out-of-date update for the same object.
1607 // ProcessEntityUpdates() also takes the m_killRecord lock.
1608// lock (m_killRecord)
1609// {
1610// foreach (uint localID in localIDs)
1611// m_killRecord.Add(localID);
1612
1613 // The throttle queue used here must match that being used for updates. Otherwise, there is a
1614 // chance that a kill packet put on a separate queue will be sent to the client before an existing
1615 // update packet on another queue. Receiving updates after kills results in unowned and undeletable
1616 // scene objects in a viewer until that viewer is relogged in.
1617 OutPacket(kill, ThrottleOutPacketType.Task);
1618// }
1619 }
1620 }
1621 1682
1622 /// <summary> 1683 /// <summary>
1623 /// Send information about the items contained in a folder to the client. 1684 /// Send information about the items contained in a folder to the client.
@@ -2594,11 +2655,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2594 { 2655 {
2595 AvatarSitResponsePacket avatarSitResponse = new AvatarSitResponsePacket(); 2656 AvatarSitResponsePacket avatarSitResponse = new AvatarSitResponsePacket();
2596 avatarSitResponse.SitObject.ID = TargetID; 2657 avatarSitResponse.SitObject.ID = TargetID;
2597 if (CameraAtOffset != Vector3.Zero) 2658 avatarSitResponse.SitTransform.CameraAtOffset = CameraAtOffset;
2598 { 2659 avatarSitResponse.SitTransform.CameraEyeOffset = CameraEyeOffset;
2599 avatarSitResponse.SitTransform.CameraAtOffset = CameraAtOffset;
2600 avatarSitResponse.SitTransform.CameraEyeOffset = CameraEyeOffset;
2601 }
2602 avatarSitResponse.SitTransform.ForceMouselook = ForceMouseLook; 2660 avatarSitResponse.SitTransform.ForceMouselook = ForceMouseLook;
2603 avatarSitResponse.SitTransform.AutoPilot = autopilot; 2661 avatarSitResponse.SitTransform.AutoPilot = autopilot;
2604 avatarSitResponse.SitTransform.SitPosition = OffsetPos; 2662 avatarSitResponse.SitTransform.SitPosition = OffsetPos;
@@ -3630,8 +3688,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3630 avp.Sender.IsTrial = false; 3688 avp.Sender.IsTrial = false;
3631 avp.Sender.ID = agentID; 3689 avp.Sender.ID = agentID;
3632 avp.AppearanceData = new AvatarAppearancePacket.AppearanceDataBlock[0]; 3690 avp.AppearanceData = new AvatarAppearancePacket.AppearanceDataBlock[0];
3691
3692 // this need be use in future
3693 // avp.AppearanceData[0].AppearanceVersion = 0;
3694 // avp.AppearanceData[0].CofVersion = 0;
3695
3633 //m_log.DebugFormat("[CLIENT]: Sending appearance for {0} to {1}", agentID.ToString(), AgentId.ToString()); 3696 //m_log.DebugFormat("[CLIENT]: Sending appearance for {0} to {1}", agentID.ToString(), AgentId.ToString());
3634 OutPacket(avp, ThrottleOutPacketType.Task); 3697 OutPacket(avp, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority);
3635 } 3698 }
3636 3699
3637 public void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs) 3700 public void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs)
@@ -3659,7 +3722,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3659 ani.AnimationSourceList[i].ObjectID = objectIDs[i]; 3722 ani.AnimationSourceList[i].ObjectID = objectIDs[i];
3660 } 3723 }
3661 ani.Header.Reliable = false; 3724 ani.Header.Reliable = false;
3662 OutPacket(ani, ThrottleOutPacketType.Task); 3725 OutPacket(ani, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority);
3663 } 3726 }
3664 3727
3665 #endregion 3728 #endregion
@@ -3688,7 +3751,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3688 objupdate.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1]; 3751 objupdate.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1];
3689 objupdate.ObjectData[0] = CreateAvatarUpdateBlock(presence); 3752 objupdate.ObjectData[0] = CreateAvatarUpdateBlock(presence);
3690 3753
3691 OutPacket(objupdate, ThrottleOutPacketType.Task); 3754 OutPacket(objupdate, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority);
3692 3755
3693 // We need to record the avatar local id since the root prim of an attachment points to this. 3756 // We need to record the avatar local id since the root prim of an attachment points to this.
3694// m_attachmentsSent.Add(avatar.LocalId); 3757// m_attachmentsSent.Add(avatar.LocalId);
@@ -3751,8 +3814,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3751 { 3814 {
3752 SceneObjectPart e = (SceneObjectPart)entity; 3815 SceneObjectPart e = (SceneObjectPart)entity;
3753 SceneObjectGroup g = e.ParentGroup; 3816 SceneObjectGroup g = e.ParentGroup;
3754 if (g.RootPart.Shape.State > 30) // HUD 3817 if (g.HasPrivateAttachmentPoint && g.OwnerID != AgentId)
3755 if (g.OwnerID != AgentId)
3756 return; // Don't send updates for other people's HUDs 3818 return; // Don't send updates for other people's HUDs
3757 } 3819 }
3758 3820
@@ -3762,6 +3824,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3762 m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation)); 3824 m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation));
3763 } 3825 }
3764 3826
3827
3765 /// <summary> 3828 /// <summary>
3766 /// Requeue an EntityUpdate when it was not acknowledged by the client. 3829 /// Requeue an EntityUpdate when it was not acknowledged by the client.
3767 /// We will update the priority and put it in the correct queue, merging update flags 3830 /// We will update the priority and put it in the correct queue, merging update flags
@@ -3769,8 +3832,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3769 /// The original update time is used for the merged update. 3832 /// The original update time is used for the merged update.
3770 /// </summary> 3833 /// </summary>
3771 private void ResendPrimUpdate(EntityUpdate update) 3834 private void ResendPrimUpdate(EntityUpdate update)
3772 { 3835 {
3773 // If the update exists in priority queue, it will be updated. 3836 // If the update exists in priority queue, it will be updated.
3774 // If it does not exist then it will be added with the current (rather than its original) priority 3837 // If it does not exist then it will be added with the current (rather than its original) priority
3775 uint priority = m_prioritizer.GetUpdatePriority(this, update.Entity); 3838 uint priority = m_prioritizer.GetUpdatePriority(this, update.Entity);
3776 3839
@@ -3796,10 +3859,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3796 // Count this as a resent packet since we are going to requeue all of the updates contained in it 3859 // Count this as a resent packet since we are going to requeue all of the updates contained in it
3797 Interlocked.Increment(ref m_udpClient.PacketsResent); 3860 Interlocked.Increment(ref m_udpClient.PacketsResent);
3798 3861
3862 // We're not going to worry about interlock yet since its not currently critical that this total count
3863 // is 100% correct
3864 m_udpServer.PacketsResentCount++;
3865
3799 foreach (EntityUpdate update in updates) 3866 foreach (EntityUpdate update in updates)
3800 ResendPrimUpdate(update); 3867 ResendPrimUpdate(update);
3801 } 3868 }
3802 3869
3803 private void ProcessEntityUpdates(int maxUpdates) 3870 private void ProcessEntityUpdates(int maxUpdates)
3804 { 3871 {
3805 OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>(); 3872 OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>();
@@ -3841,13 +3908,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3841 { 3908 {
3842 SceneObjectPart part = (SceneObjectPart)update.Entity; 3909 SceneObjectPart part = (SceneObjectPart)update.Entity;
3843 3910
3844 if (part.ParentGroup.IsDeleted) 3911 if (part.ParentGroup.IsDeleted || part.ParentGroup.inTransit)
3845 continue; 3912 continue;
3846 3913
3847 if (part.ParentGroup.IsAttachment) 3914 if (part.ParentGroup.IsAttachment)
3848 { // Someone else's HUD, why are we getting these? 3915 { // Someone else's HUD, why are we getting these?
3849 if (part.ParentGroup.OwnerID != AgentId && 3916 if (part.ParentGroup.OwnerID != AgentId && part.ParentGroup.HasPrivateAttachmentPoint)
3850 part.ParentGroup.RootPart.Shape.State > 30)
3851 continue; 3917 continue;
3852 ScenePresence sp; 3918 ScenePresence sp;
3853 // Owner is not in the sim, don't update it to 3919 // Owner is not in the sim, don't update it to
@@ -3879,36 +3945,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3879 if (sp.IsChildAgent) 3945 if (sp.IsChildAgent)
3880 continue; 3946 continue;
3881 3947
3882 // If the object is an attachment we don't want it to be in the kill
3883 // record. Else attaching from inworld and subsequently dropping
3884 // it will no longer work.
3885// lock (m_killRecord)
3886// {
3887// m_killRecord.Remove(part.LocalId);
3888// m_killRecord.Remove(part.ParentGroup.RootPart.LocalId);
3889// }
3890 }
3891 else
3892 {
3893 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client
3894 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good
3895 // safety measure.
3896 //
3897 // If a Linden Lab 1.23.5 client (and possibly later and earlier) receives an object update
3898 // after a kill, it will keep displaying the deleted object until relog. OpenSim currently performs
3899 // updates and kills on different threads with different scheduling strategies, hence this protection.
3900 //
3901 // This doesn't appear to apply to child prims - a client will happily ignore these updates
3902 // after the root prim has been deleted.
3903 //
3904 // We ignore this for attachments because attaching something from inworld breaks unless we do.
3905// lock (m_killRecord)
3906// {
3907// if (m_killRecord.Contains(part.LocalId))
3908// continue;
3909// if (m_killRecord.Contains(part.ParentGroup.RootPart.LocalId))
3910// continue;
3911// }
3912 } 3948 }
3913 3949
3914 if (part.ParentGroup.IsAttachment && m_disableFacelights) 3950 if (part.ParentGroup.IsAttachment && m_disableFacelights)
@@ -3939,7 +3975,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3939 else if (update.Entity is ScenePresence) 3975 else if (update.Entity is ScenePresence)
3940 { 3976 {
3941 ScenePresence presence = (ScenePresence)update.Entity; 3977 ScenePresence presence = (ScenePresence)update.Entity;
3942 3978 if (presence.IsDeleted)
3979 continue;
3943 // If ParentUUID is not UUID.Zero and ParentID is 0, this 3980 // If ParentUUID is not UUID.Zero and ParentID is 0, this
3944 // avatar is in the process of crossing regions while 3981 // avatar is in the process of crossing regions while
3945 // sat on an object. In this state, we don't want any 3982 // sat on an object. In this state, we don't want any
@@ -4022,8 +4059,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4022 } 4059 }
4023 else 4060 else
4024 { 4061 {
4025 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId) 4062 if (update.Entity is ScenePresence)
4026 // Self updates go into a special list 4063 // ALL presence updates go into a special list
4027 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures))); 4064 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
4028 else 4065 else
4029 // Everything else goes here 4066 // Everything else goes here
@@ -4035,7 +4072,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4035 4072
4036 #region Packet Sending 4073 #region Packet Sending
4037 4074
4038 const float TIME_DILATION = 1.0f; 4075// const float TIME_DILATION = 1.0f;
4039 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f); 4076 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f);
4040 4077
4041 if (terseAgentUpdateBlocks.IsValueCreated) 4078 if (terseAgentUpdateBlocks.IsValueCreated)
@@ -4051,7 +4088,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4051 for (int i = 0; i < blocks.Count; i++) 4088 for (int i = 0; i < blocks.Count; i++)
4052 packet.ObjectData[i] = blocks[i]; 4089 packet.ObjectData[i] = blocks[i];
4053 4090
4054 OutPacket(packet, ThrottleOutPacketType.Unknown, true); 4091 OutPacket(packet, ThrottleOutPacketType.Unknown, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); });
4055 } 4092 }
4056 4093
4057 if (objectUpdateBlocks.IsValueCreated) 4094 if (objectUpdateBlocks.IsValueCreated)
@@ -4097,13 +4134,36 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4097 4134
4098 for (int i = 0; i < blocks.Count; i++) 4135 for (int i = 0; i < blocks.Count; i++)
4099 packet.ObjectData[i] = blocks[i]; 4136 packet.ObjectData[i] = blocks[i];
4100 4137
4101 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); }); 4138 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); });
4102 } 4139 }
4103 4140
4104 #endregion Packet Sending 4141 #endregion Packet Sending
4105 } 4142 }
4106 4143
4144 // hack.. dont use
4145 public void SendPartFullUpdate(ISceneEntity ent, uint? parentID)
4146 {
4147 if (ent is SceneObjectPart)
4148 {
4149 SceneObjectPart part = (SceneObjectPart)ent;
4150 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
4151 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4152 packet.RegionData.TimeDilation = 1;
4153 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1];
4154
4155 ObjectUpdatePacket.ObjectDataBlock blk = CreatePrimUpdateBlock(part, this.m_agentId);
4156 if (parentID.HasValue)
4157 {
4158 blk.ParentID = parentID.Value;
4159 }
4160
4161 packet.ObjectData[0] = blk;
4162
4163 OutPacket(packet, ThrottleOutPacketType.Task, true);
4164 }
4165 }
4166
4107 public void ReprioritizeUpdates() 4167 public void ReprioritizeUpdates()
4108 { 4168 {
4109 lock (m_entityUpdates.SyncRoot) 4169 lock (m_entityUpdates.SyncRoot)
@@ -4140,8 +4200,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4140 4200
4141 void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories) 4201 void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories)
4142 { 4202 {
4203// if (!m_udpServer.IsRunningOutbound)
4204// return;
4205
4143 if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) 4206 if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
4144 { 4207 {
4208// if (!m_udpServer.IsRunningOutbound)
4209// return;
4210
4145 if (m_maxUpdates == 0 || m_LastQueueFill == 0) 4211 if (m_maxUpdates == 0 || m_LastQueueFill == 0)
4146 { 4212 {
4147 m_maxUpdates = m_udpServer.PrimUpdatesPerCallback; 4213 m_maxUpdates = m_udpServer.PrimUpdatesPerCallback;
@@ -4167,6 +4233,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4167 ImageManager.ProcessImageQueue(m_udpServer.TextureSendLimit); 4233 ImageManager.ProcessImageQueue(m_udpServer.TextureSendLimit);
4168 } 4234 }
4169 4235
4236 internal bool HandleHasUpdates(ThrottleOutPacketTypeFlags categories)
4237 {
4238 bool hasUpdates = false;
4239
4240 if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
4241 {
4242 if (m_entityUpdates.Count > 0)
4243 hasUpdates = true;
4244 else if (m_entityProps.Count > 0)
4245 hasUpdates = true;
4246 }
4247
4248 if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0)
4249 {
4250 if (ImageManager.HasUpdates())
4251 hasUpdates = true;
4252 }
4253
4254 return hasUpdates;
4255 }
4256
4170 public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID) 4257 public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID)
4171 { 4258 {
4172 AssetUploadCompletePacket newPack = new AssetUploadCompletePacket(); 4259 AssetUploadCompletePacket newPack = new AssetUploadCompletePacket();
@@ -4312,6 +4399,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4312 // Count this as a resent packet since we are going to requeue all of the updates contained in it 4399 // Count this as a resent packet since we are going to requeue all of the updates contained in it
4313 Interlocked.Increment(ref m_udpClient.PacketsResent); 4400 Interlocked.Increment(ref m_udpClient.PacketsResent);
4314 4401
4402 // We're not going to worry about interlock yet since its not currently critical that this total count
4403 // is 100% correct
4404 m_udpServer.PacketsResentCount++;
4405
4315 foreach (ObjectPropertyUpdate update in updates) 4406 foreach (ObjectPropertyUpdate update in updates)
4316 ResendPropertyUpdate(update); 4407 ResendPropertyUpdate(update);
4317 } 4408 }
@@ -4499,6 +4590,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4499 SceneObjectPart root = sop.ParentGroup.RootPart; 4590 SceneObjectPart root = sop.ParentGroup.RootPart;
4500 4591
4501 block.TouchName = Util.StringToBytes256(root.TouchName); 4592 block.TouchName = Util.StringToBytes256(root.TouchName);
4593
4594 // SL 3.3.4, at least, appears to read this information as a concatenated byte[] stream of UUIDs but
4595 // it's not yet clear whether this is actually used. If this is done in the future then a pre-cached
4596 // copy is really needed since it's less efficient to be constantly recreating this byte array.
4597// using (MemoryStream memStream = new MemoryStream())
4598// {
4599// using (BinaryWriter binWriter = new BinaryWriter(memStream))
4600// {
4601// for (int i = 0; i < sop.GetNumberOfSides(); i++)
4602// {
4603// Primitive.TextureEntryFace teFace = sop.Shape.Textures.FaceTextures[i];
4604//
4605// UUID textureID;
4606//
4607// if (teFace != null)
4608// textureID = teFace.TextureID;
4609// else
4610// textureID = sop.Shape.Textures.DefaultTexture.TextureID;
4611//
4612// binWriter.Write(textureID.GetBytes());
4613// }
4614//
4615// block.TextureID = memStream.ToArray();
4616// }
4617// }
4618
4502 block.TextureID = new byte[0]; // TextureID ??? 4619 block.TextureID = new byte[0]; // TextureID ???
4503 block.SitName = Util.StringToBytes256(root.SitName); 4620 block.SitName = Util.StringToBytes256(root.SitName);
4504 block.OwnerMask = root.OwnerMask; 4621 block.OwnerMask = root.OwnerMask;
@@ -4839,7 +4956,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4839 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>(); 4956 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>();
4840 if (eq != null) 4957 if (eq != null)
4841 { 4958 {
4842 eq.ParcelProperties(updateMessage, this.AgentId); 4959
4960 OSD message_body = updateMessage.Serialize();
4961 // Add new fields here until OMV has them
4962 OSDMap bodyMap = (OSDMap)message_body;
4963 OSDArray parcelDataArray = (OSDArray)bodyMap["ParcelData"];
4964 OSDMap parcelData = (OSDMap)parcelDataArray[0];
4965 parcelData["SeeAVs"] = OSD.FromBoolean(landData.SeeAVs);
4966 parcelData["AnyAVSounds"] = OSD.FromBoolean(landData.AnyAVSounds);
4967 parcelData["GroupAVSounds"] = OSD.FromBoolean(landData.GroupAVSounds);
4968 OSDMap message = new OSDMap();
4969 message.Add("message", OSD.FromString("ParcelProperties"));
4970 message.Add("body", message_body);
4971
4972 eq.Enqueue (message, this.AgentId);
4973
4974// eq.ParcelProperties(updateMessage, this.AgentId);
4843 } 4975 }
4844 else 4976 else
4845 { 4977 {
@@ -4877,7 +5009,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4877 5009
4878 public void SendForceClientSelectObjects(List<uint> ObjectIDs) 5010 public void SendForceClientSelectObjects(List<uint> ObjectIDs)
4879 { 5011 {
4880 m_log.WarnFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count); 5012// m_log.DebugFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count);
4881 5013
4882 bool firstCall = true; 5014 bool firstCall = true;
4883 const int MAX_OBJECTS_PER_PACKET = 251; 5015 const int MAX_OBJECTS_PER_PACKET = 251;
@@ -4997,35 +5129,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4997 5129
4998 position = presence.OffsetPosition; 5130 position = presence.OffsetPosition;
4999 rotation = presence.Rotation; 5131 rotation = presence.Rotation;
5000 5132 angularVelocity = presence.AngularVelocity;
5001 if (presence.ParentID != 0) 5133 rotation = presence.Rotation;
5002 {
5003 SceneObjectPart part = m_scene.GetSceneObjectPart(presence.ParentID);
5004 if (part != null && part != part.ParentGroup.RootPart)
5005 {
5006 position = part.OffsetPosition + presence.OffsetPosition * part.RotationOffset;
5007 rotation = part.RotationOffset * presence.Rotation;
5008 }
5009 angularVelocity = Vector3.Zero;
5010 }
5011 else
5012 {
5013 angularVelocity = presence.AngularVelocity;
5014 rotation = presence.Rotation;
5015 }
5016 5134
5017 attachPoint = 0; 5135 attachPoint = 0;
5136// m_log.DebugFormat(
5137// "[LLCLIENTVIEW]: Sending terse update to {0} with position {1} in {2}", Name, presence.OffsetPosition, m_scene.Name);
5138
5139 // attachPoint = presence.State; // Core: commented
5018 collisionPlane = presence.CollisionPlane; 5140 collisionPlane = presence.CollisionPlane;
5019 velocity = presence.Velocity; 5141 velocity = presence.Velocity;
5020 acceleration = Vector3.Zero; 5142 acceleration = Vector3.Zero;
5021 5143
5022 // Interestingly, sending this to non-zero will cause the client's avatar to start moving & accelerating
5023 // in that direction, even though we don't model this on the server. Implementing this in the future
5024 // may improve movement smoothness.
5025// acceleration = new Vector3(1, 0, 0);
5026
5027 if (sendTexture) 5144 if (sendTexture)
5028 textureEntry = presence.Appearance.Texture.GetBytes(); 5145 {
5146 if (presence.Invisible)
5147 textureEntry = AvatarAppearance.Invisible.GetBytes();
5148 else
5149 textureEntry = presence.Appearance.Texture.GetBytes();
5150 }
5029 else 5151 else
5030 textureEntry = null; 5152 textureEntry = null;
5031 } 5153 }
@@ -5034,7 +5156,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5034 SceneObjectPart part = (SceneObjectPart)entity; 5156 SceneObjectPart part = (SceneObjectPart)entity;
5035 5157
5036 attachPoint = part.ParentGroup.AttachmentPoint; 5158 attachPoint = part.ParentGroup.AttachmentPoint;
5037 5159 attachPoint = ((attachPoint % 16) * 16 + (attachPoint / 16));
5038// m_log.DebugFormat( 5160// m_log.DebugFormat(
5039// "[LLCLIENTVIEW]: Sending attachPoint {0} for {1} {2} to {3}", 5161// "[LLCLIENTVIEW]: Sending attachPoint {0} for {1} {2} to {3}",
5040// attachPoint, part.Name, part.LocalId, Name); 5162// attachPoint, part.Name, part.LocalId, Name);
@@ -5062,7 +5184,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5062 pos += 4; 5184 pos += 4;
5063 5185
5064 // Avatar/CollisionPlane 5186 // Avatar/CollisionPlane
5065 data[pos++] = (byte)((attachPoint % 16) * 16 + (attachPoint / 16)); ; 5187 data[pos++] = (byte) attachPoint;
5066 if (avatar) 5188 if (avatar)
5067 { 5189 {
5068 data[pos++] = 1; 5190 data[pos++] = 1;
@@ -5132,30 +5254,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5132 Vector3 offsetPosition = data.OffsetPosition; 5254 Vector3 offsetPosition = data.OffsetPosition;
5133 Quaternion rotation = data.Rotation; 5255 Quaternion rotation = data.Rotation;
5134 uint parentID = data.ParentID; 5256 uint parentID = data.ParentID;
5135 5257
5136 if (parentID != 0) 5258// m_log.DebugFormat(
5137 { 5259// "[LLCLIENTVIEW]: Sending full update to {0} with position {1} in {2}", Name, data.OffsetPosition, m_scene.Name);
5138 SceneObjectPart part = m_scene.GetSceneObjectPart(parentID);
5139 if (part != null && part != part.ParentGroup.RootPart)
5140 {
5141 offsetPosition = part.OffsetPosition + data.OffsetPosition * part.RotationOffset;
5142 rotation = part.RotationOffset * data.Rotation;
5143 parentID = part.ParentGroup.RootPart.LocalId;
5144 }
5145 }
5146 5260
5147 byte[] objectData = new byte[76]; 5261 byte[] objectData = new byte[76];
5148 5262
5149 data.CollisionPlane.ToBytes(objectData, 0);
5150 offsetPosition.ToBytes(objectData, 16);
5151 Vector3 velocity = new Vector3(0, 0, 0); 5263 Vector3 velocity = new Vector3(0, 0, 0);
5152 Vector3 acceleration = new Vector3(0, 0, 0); 5264 Vector3 acceleration = new Vector3(0, 0, 0);
5265 rotation.Normalize();
5266
5267 data.CollisionPlane.ToBytes(objectData, 0);
5268 offsetPosition.ToBytes(objectData, 16);
5153 velocity.ToBytes(objectData, 28); 5269 velocity.ToBytes(objectData, 28);
5154 acceleration.ToBytes(objectData, 40); 5270 acceleration.ToBytes(objectData, 40);
5155// data.Velocity.ToBytes(objectData, 28);
5156// data.Acceleration.ToBytes(objectData, 40);
5157 rotation.ToBytes(objectData, 52); 5271 rotation.ToBytes(objectData, 52);
5158 //data.AngularVelocity.ToBytes(objectData, 64); 5272 data.AngularVelocity.ToBytes(objectData, 64);
5159 5273
5160 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); 5274 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock();
5161 5275
@@ -5168,7 +5282,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5168 update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " + 5282 update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " +
5169 data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle); 5283 data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle);
5170 update.ObjectData = objectData; 5284 update.ObjectData = objectData;
5171 update.ParentID = parentID; 5285
5286 SceneObjectPart parentPart = data.ParentPart;
5287 if (parentPart != null)
5288 update.ParentID = parentPart.ParentGroup.LocalId;
5289 else
5290 update.ParentID = 0;
5291
5172 update.PathCurve = 16; 5292 update.PathCurve = 16;
5173 update.PathScaleX = 100; 5293 update.PathScaleX = 100;
5174 update.PathScaleY = 100; 5294 update.PathScaleY = 100;
@@ -5205,15 +5325,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5205 data.RelativePosition.ToBytes(objectData, 0); 5325 data.RelativePosition.ToBytes(objectData, 0);
5206 data.Velocity.ToBytes(objectData, 12); 5326 data.Velocity.ToBytes(objectData, 12);
5207 data.Acceleration.ToBytes(objectData, 24); 5327 data.Acceleration.ToBytes(objectData, 24);
5208 try 5328
5209 { 5329 Quaternion rotation = data.RotationOffset;
5210 data.RotationOffset.ToBytes(objectData, 36); 5330 rotation.Normalize();
5211 } 5331 rotation.ToBytes(objectData, 36);
5212 catch (Exception e)
5213 {
5214 m_log.Warn("[LLClientView]: exception converting quaternion to bytes, using Quaternion.Identity. Exception: " + e.ToString());
5215 OpenMetaverse.Quaternion.Identity.ToBytes(objectData, 36);
5216 }
5217 data.AngularVelocity.ToBytes(objectData, 48); 5332 data.AngularVelocity.ToBytes(objectData, 48);
5218 5333
5219 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); 5334 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock();
@@ -5227,6 +5342,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5227 //update.JointType = 0; 5342 //update.JointType = 0;
5228 update.Material = data.Material; 5343 update.Material = data.Material;
5229 update.MediaURL = Utils.EmptyBytes; // FIXME: Support this in OpenSim 5344 update.MediaURL = Utils.EmptyBytes; // FIXME: Support this in OpenSim
5345/*
5230 if (data.ParentGroup.IsAttachment) 5346 if (data.ParentGroup.IsAttachment)
5231 { 5347 {
5232 update.NameValue = Util.StringToBytes256("AttachItemID STRING RW SV " + data.ParentGroup.FromItemID); 5348 update.NameValue = Util.StringToBytes256("AttachItemID STRING RW SV " + data.ParentGroup.FromItemID);
@@ -5240,6 +5356,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5240 // case for attachments may contain conflicting values that can end up crashing the viewer. 5356 // case for attachments may contain conflicting values that can end up crashing the viewer.
5241 update.State = data.ParentGroup.RootPart.Shape.State; 5357 update.State = data.ParentGroup.RootPart.Shape.State;
5242 } 5358 }
5359 */
5360
5361 if (data.ParentGroup.IsAttachment)
5362 {
5363 if (data.IsRoot)
5364 {
5365 update.NameValue = Util.StringToBytes256("AttachItemID STRING RW SV " + data.ParentGroup.FromItemID);
5366 }
5367 else
5368 update.NameValue = Utils.EmptyBytes;
5369
5370 int st = (int)data.ParentGroup.AttachmentPoint;
5371 update.State = (byte)(((st & 0xf0) >> 4) + ((st & 0x0f) << 4)); ;
5372 }
5373 else
5374 {
5375 update.NameValue = Utils.EmptyBytes;
5376 update.State = data.Shape.State; // not sure about this
5377 }
5378
5243 5379
5244// m_log.DebugFormat( 5380// m_log.DebugFormat(
5245// "[LLCLIENTVIEW]: Sending state {0} for {1} {2} to {3}", 5381// "[LLCLIENTVIEW]: Sending state {0} for {1} {2} to {3}",
@@ -5387,7 +5523,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5387 AddLocalPacketHandler(PacketType.RezObject, HandlerRezObject); 5523 AddLocalPacketHandler(PacketType.RezObject, HandlerRezObject);
5388 AddLocalPacketHandler(PacketType.DeRezObject, HandlerDeRezObject); 5524 AddLocalPacketHandler(PacketType.DeRezObject, HandlerDeRezObject);
5389 AddLocalPacketHandler(PacketType.ModifyLand, HandlerModifyLand); 5525 AddLocalPacketHandler(PacketType.ModifyLand, HandlerModifyLand);
5390 AddLocalPacketHandler(PacketType.RegionHandshakeReply, HandlerRegionHandshakeReply); 5526 AddLocalPacketHandler(PacketType.RegionHandshakeReply, HandlerRegionHandshakeReply, false);
5391 AddLocalPacketHandler(PacketType.AgentWearablesRequest, HandlerAgentWearablesRequest); 5527 AddLocalPacketHandler(PacketType.AgentWearablesRequest, HandlerAgentWearablesRequest);
5392 AddLocalPacketHandler(PacketType.AgentSetAppearance, HandlerAgentSetAppearance); 5528 AddLocalPacketHandler(PacketType.AgentSetAppearance, HandlerAgentSetAppearance);
5393 AddLocalPacketHandler(PacketType.AgentIsNowWearing, HandlerAgentIsNowWearing); 5529 AddLocalPacketHandler(PacketType.AgentIsNowWearing, HandlerAgentIsNowWearing);
@@ -5448,8 +5584,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5448 AddLocalPacketHandler(PacketType.ScriptAnswerYes, HandleScriptAnswerYes, false); 5584 AddLocalPacketHandler(PacketType.ScriptAnswerYes, HandleScriptAnswerYes, false);
5449 AddLocalPacketHandler(PacketType.ObjectClickAction, HandleObjectClickAction, false); 5585 AddLocalPacketHandler(PacketType.ObjectClickAction, HandleObjectClickAction, false);
5450 AddLocalPacketHandler(PacketType.ObjectMaterial, HandleObjectMaterial, false); 5586 AddLocalPacketHandler(PacketType.ObjectMaterial, HandleObjectMaterial, false);
5451 AddLocalPacketHandler(PacketType.RequestImage, HandleRequestImage); 5587 AddLocalPacketHandler(PacketType.RequestImage, HandleRequestImage, false);
5452 AddLocalPacketHandler(PacketType.TransferRequest, HandleTransferRequest); 5588 AddLocalPacketHandler(PacketType.TransferRequest, HandleTransferRequest, false);
5453 AddLocalPacketHandler(PacketType.AssetUploadRequest, HandleAssetUploadRequest); 5589 AddLocalPacketHandler(PacketType.AssetUploadRequest, HandleAssetUploadRequest);
5454 AddLocalPacketHandler(PacketType.RequestXfer, HandleRequestXfer); 5590 AddLocalPacketHandler(PacketType.RequestXfer, HandleRequestXfer);
5455 AddLocalPacketHandler(PacketType.SendXferPacket, HandleSendXferPacket); 5591 AddLocalPacketHandler(PacketType.SendXferPacket, HandleSendXferPacket);
@@ -5481,7 +5617,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5481 AddLocalPacketHandler(PacketType.TeleportCancel, HandleTeleportCancel); 5617 AddLocalPacketHandler(PacketType.TeleportCancel, HandleTeleportCancel);
5482 AddLocalPacketHandler(PacketType.TeleportLocationRequest, HandleTeleportLocationRequest); 5618 AddLocalPacketHandler(PacketType.TeleportLocationRequest, HandleTeleportLocationRequest);
5483 AddLocalPacketHandler(PacketType.UUIDNameRequest, HandleUUIDNameRequest, false); 5619 AddLocalPacketHandler(PacketType.UUIDNameRequest, HandleUUIDNameRequest, false);
5484 AddLocalPacketHandler(PacketType.RegionHandleRequest, HandleRegionHandleRequest); 5620 AddLocalPacketHandler(PacketType.RegionHandleRequest, HandleRegionHandleRequest, false);
5485 AddLocalPacketHandler(PacketType.ParcelInfoRequest, HandleParcelInfoRequest); 5621 AddLocalPacketHandler(PacketType.ParcelInfoRequest, HandleParcelInfoRequest);
5486 AddLocalPacketHandler(PacketType.ParcelAccessListRequest, HandleParcelAccessListRequest, false); 5622 AddLocalPacketHandler(PacketType.ParcelAccessListRequest, HandleParcelAccessListRequest, false);
5487 AddLocalPacketHandler(PacketType.ParcelAccessListUpdate, HandleParcelAccessListUpdate, false); 5623 AddLocalPacketHandler(PacketType.ParcelAccessListUpdate, HandleParcelAccessListUpdate, false);
@@ -5594,82 +5730,146 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5594 5730
5595 #region Packet Handlers 5731 #region Packet Handlers
5596 5732
5733 public int TotalAgentUpdates { get; set; }
5734
5597 #region Scene/Avatar 5735 #region Scene/Avatar
5598 5736
5599 private bool HandleAgentUpdate(IClientAPI sener, Packet packet) 5737 // Threshold for body rotation to be a significant agent update
5738 // use the abs of cos
5739 private const float QDELTABody = 1.0f - 0.0001f;
5740 private const float QDELTAHead = 1.0f - 0.0001f;
5741 // Threshold for camera rotation to be a significant agent update
5742 private const float VDELTA = 0.01f;
5743
5744 /// <summary>
5745 /// This checks the update significance against the last update made.
5746 /// </summary>
5747 /// <remarks>Can only be called by one thread at a time</remarks>
5748 /// <returns></returns>
5749 /// <param name='x'></param>
5750 public bool CheckAgentUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
5600 { 5751 {
5601 if (OnAgentUpdate != null) 5752 return CheckAgentMovementUpdateSignificance(x) || CheckAgentCameraUpdateSignificance(x);
5753 }
5754
5755 /// <summary>
5756 /// This checks the movement/state update significance against the last update made.
5757 /// </summary>
5758 /// <remarks>Can only be called by one thread at a time</remarks>
5759 /// <returns></returns>
5760 /// <param name='x'></param>
5761 private bool CheckAgentMovementUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
5762 {
5763 float qdelta1 = Math.Abs(Quaternion.Dot(x.BodyRotation, m_thisAgentUpdateArgs.BodyRotation));
5764 //qdelta2 = Math.Abs(Quaternion.Dot(x.HeadRotation, m_thisAgentUpdateArgs.HeadRotation));
5765
5766 bool movementSignificant =
5767 (x.ControlFlags != m_thisAgentUpdateArgs.ControlFlags) // significant if control flags changed
5768 || (x.ControlFlags != (byte)AgentManager.ControlFlags.NONE) // significant if user supplying any movement update commands
5769 || (x.Flags != m_thisAgentUpdateArgs.Flags) // significant if Flags changed
5770 || (x.State != m_thisAgentUpdateArgs.State) // significant if Stats changed
5771 || (qdelta1 < QDELTABody) // significant if body rotation above(below cos) threshold
5772 // Ignoring head rotation altogether, because it's not being used for anything interesting up the stack
5773 // || (qdelta2 < QDELTAHead) // significant if head rotation above(below cos) threshold
5774 || (Math.Abs(x.Far - m_thisAgentUpdateArgs.Far) >= 32) // significant if far distance changed
5775 ;
5776 //if (movementSignificant)
5777 //{
5778 //m_log.DebugFormat("[LLCLIENTVIEW]: Bod {0} {1}",
5779 // qdelta1, qdelta2);
5780 //m_log.DebugFormat("[LLCLIENTVIEW]: St {0} {1} {2} {3}",
5781 // x.ControlFlags, x.Flags, x.Far, x.State);
5782 //}
5783 return movementSignificant;
5784 }
5785
5786 /// <summary>
5787 /// This checks the camera update significance against the last update made.
5788 /// </summary>
5789 /// <remarks>Can only be called by one thread at a time</remarks>
5790 /// <returns></returns>
5791 /// <param name='x'></param>
5792 private bool CheckAgentCameraUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
5793 {
5794 float vdelta1 = Vector3.Distance(x.CameraAtAxis, m_thisAgentUpdateArgs.CameraAtAxis);
5795 float vdelta2 = Vector3.Distance(x.CameraCenter, m_thisAgentUpdateArgs.CameraCenter);
5796 float vdelta3 = Vector3.Distance(x.CameraLeftAxis, m_thisAgentUpdateArgs.CameraLeftAxis);
5797 float vdelta4 = Vector3.Distance(x.CameraUpAxis, m_thisAgentUpdateArgs.CameraUpAxis);
5798
5799 bool cameraSignificant =
5800 (vdelta1 > VDELTA) ||
5801 (vdelta2 > VDELTA) ||
5802 (vdelta3 > VDELTA) ||
5803 (vdelta4 > VDELTA)
5804 ;
5805
5806 //if (cameraSignificant)
5807 //{
5808 //m_log.DebugFormat("[LLCLIENTVIEW]: Cam1 {0} {1}",
5809 // x.CameraAtAxis, x.CameraCenter);
5810 //m_log.DebugFormat("[LLCLIENTVIEW]: Cam2 {0} {1}",
5811 // x.CameraLeftAxis, x.CameraUpAxis);
5812 //}
5813
5814 return cameraSignificant;
5815 }
5816
5817 private bool HandleAgentUpdate(IClientAPI sender, Packet packet)
5818 {
5819 // We got here, which means that something in agent update was significant
5820
5821 AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
5822 AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData;
5823
5824 if (x.AgentID != AgentId || x.SessionID != SessionId)
5602 { 5825 {
5603 AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet; 5826 PacketPool.Instance.ReturnPacket(packet);
5827 return false;
5828 }
5604 5829
5605 #region Packet Session and User Check 5830 TotalAgentUpdates++;
5606 if (agentUpdate.AgentData.SessionID != SessionId || agentUpdate.AgentData.AgentID != AgentId)
5607 {
5608 PacketPool.Instance.ReturnPacket(packet);
5609 return false;
5610 }
5611 #endregion
5612 5831
5613 bool update = false; 5832 bool movement = CheckAgentMovementUpdateSignificance(x);
5614 AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData; 5833 bool camera = CheckAgentCameraUpdateSignificance(x);
5615
5616 if (m_lastAgentUpdateArgs != null)
5617 {
5618 // These should be ordered from most-likely to
5619 // least likely to change. I've made an initial
5620 // guess at that.
5621 update =
5622 (
5623 (x.BodyRotation != m_lastAgentUpdateArgs.BodyRotation) ||
5624 (x.CameraAtAxis != m_lastAgentUpdateArgs.CameraAtAxis) ||
5625 (x.CameraCenter != m_lastAgentUpdateArgs.CameraCenter) ||
5626 (x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) ||
5627 (x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) ||
5628 (x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) ||
5629 (x.ControlFlags != 0) ||
5630 (x.Far != m_lastAgentUpdateArgs.Far) ||
5631 (x.Flags != m_lastAgentUpdateArgs.Flags) ||
5632 (x.State != m_lastAgentUpdateArgs.State) ||
5633 (x.HeadRotation != m_lastAgentUpdateArgs.HeadRotation) ||
5634 (x.SessionID != m_lastAgentUpdateArgs.SessionID) ||
5635 (x.AgentID != m_lastAgentUpdateArgs.AgentID)
5636 );
5637 }
5638 else
5639 {
5640 m_lastAgentUpdateArgs = new AgentUpdateArgs();
5641 update = true;
5642 }
5643 5834
5644 if (update) 5835 // Was there a significant movement/state change?
5645 { 5836 if (movement)
5646// m_log.DebugFormat("[LLCLIENTVIEW]: Triggered AgentUpdate for {0}", sener.Name); 5837 {
5838 m_thisAgentUpdateArgs.BodyRotation = x.BodyRotation;
5839 m_thisAgentUpdateArgs.ControlFlags = x.ControlFlags;
5840 m_thisAgentUpdateArgs.Far = x.Far;
5841 m_thisAgentUpdateArgs.Flags = x.Flags;
5842 m_thisAgentUpdateArgs.HeadRotation = x.HeadRotation;
5843// m_thisAgentUpdateArgs.SessionID = x.SessionID;
5844 m_thisAgentUpdateArgs.State = x.State;
5845
5846 UpdateAgent handlerAgentUpdate = OnAgentUpdate;
5847 UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate;
5647 5848
5648 m_lastAgentUpdateArgs.AgentID = x.AgentID; 5849 if (handlerPreAgentUpdate != null)
5649 m_lastAgentUpdateArgs.BodyRotation = x.BodyRotation; 5850 OnPreAgentUpdate(this, m_thisAgentUpdateArgs);
5650 m_lastAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis;
5651 m_lastAgentUpdateArgs.CameraCenter = x.CameraCenter;
5652 m_lastAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis;
5653 m_lastAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis;
5654 m_lastAgentUpdateArgs.ControlFlags = x.ControlFlags;
5655 m_lastAgentUpdateArgs.Far = x.Far;
5656 m_lastAgentUpdateArgs.Flags = x.Flags;
5657 m_lastAgentUpdateArgs.HeadRotation = x.HeadRotation;
5658 m_lastAgentUpdateArgs.SessionID = x.SessionID;
5659 m_lastAgentUpdateArgs.State = x.State;
5660 5851
5661 UpdateAgent handlerAgentUpdate = OnAgentUpdate; 5852 if (handlerAgentUpdate != null)
5662 UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate; 5853 OnAgentUpdate(this, m_thisAgentUpdateArgs);
5663 5854
5664 if (handlerPreAgentUpdate != null) 5855 handlerAgentUpdate = null;
5665 OnPreAgentUpdate(this, m_lastAgentUpdateArgs); 5856 handlerPreAgentUpdate = null;
5857 }
5666 5858
5667 if (handlerAgentUpdate != null) 5859 // Was there a significant camera(s) change?
5668 OnAgentUpdate(this, m_lastAgentUpdateArgs); 5860 if (camera)
5861 {
5862 m_thisAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis;
5863 m_thisAgentUpdateArgs.CameraCenter = x.CameraCenter;
5864 m_thisAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis;
5865 m_thisAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis;
5669 5866
5670 handlerAgentUpdate = null; 5867 UpdateAgent handlerAgentCameraUpdate = OnAgentCameraUpdate;
5671 handlerPreAgentUpdate = null; 5868
5672 } 5869 if (handlerAgentCameraUpdate != null)
5870 handlerAgentCameraUpdate(this, m_thisAgentUpdateArgs);
5871
5872 handlerAgentCameraUpdate = null;
5673 } 5873 }
5674 5874
5675 PacketPool.Instance.ReturnPacket(packet); 5875 PacketPool.Instance.ReturnPacket(packet);
@@ -6260,6 +6460,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6260 //m_log.Info("[LAND]: LAND:" + modify.ToString()); 6460 //m_log.Info("[LAND]: LAND:" + modify.ToString());
6261 if (modify.ParcelData.Length > 0) 6461 if (modify.ParcelData.Length > 0)
6262 { 6462 {
6463 // Note: the ModifyTerrain event handler sends out updated packets before the end of this event. Therefore,
6464 // a simple boolean value should work and perhaps queue up just a few terrain patch packets at the end of the edit.
6465 m_justEditedTerrain = true; // Prevent terrain packet (Land layer) from being queued, make it unreliable
6263 if (OnModifyTerrain != null) 6466 if (OnModifyTerrain != null)
6264 { 6467 {
6265 for (int i = 0; i < modify.ParcelData.Length; i++) 6468 for (int i = 0; i < modify.ParcelData.Length; i++)
@@ -6275,6 +6478,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6275 } 6478 }
6276 } 6479 }
6277 } 6480 }
6481 m_justEditedTerrain = false; // Queue terrain packet (Land layer) if necessary, make it reliable again
6278 } 6482 }
6279 6483
6280 return true; 6484 return true;
@@ -6343,7 +6547,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6343 6547
6344 WearableCacheItem[] cacheitems = new WearableCacheItem[appear.WearableData.Length]; 6548 WearableCacheItem[] cacheitems = new WearableCacheItem[appear.WearableData.Length];
6345 for (int i=0; i<appear.WearableData.Length;i++) 6549 for (int i=0; i<appear.WearableData.Length;i++)
6346 cacheitems[i] = new WearableCacheItem(){CacheId = appear.WearableData[i].CacheID,TextureIndex=Convert.ToUInt32(appear.WearableData[i].TextureIndex)}; 6550 cacheitems[i] = new WearableCacheItem(){
6551 CacheId = appear.WearableData[i].CacheID,
6552 TextureIndex=Convert.ToUInt32(appear.WearableData[i].TextureIndex)
6553 };
6347 6554
6348 6555
6349 6556
@@ -6549,8 +6756,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6549 return true; 6756 return true;
6550 } 6757 }
6551 6758
6552 private bool HandleCompleteAgentMovement(IClientAPI sender, Packet Pack) 6759 private bool HandleCompleteAgentMovement(IClientAPI sender, Packet Pack)
6553 { 6760 {
6761 m_log.DebugFormat("[LLClientView] HandleCompleteAgentMovement");
6762
6554 Action<IClientAPI, bool> handlerCompleteMovementToRegion = OnCompleteMovementToRegion; 6763 Action<IClientAPI, bool> handlerCompleteMovementToRegion = OnCompleteMovementToRegion;
6555 if (handlerCompleteMovementToRegion != null) 6764 if (handlerCompleteMovementToRegion != null)
6556 { 6765 {
@@ -6636,6 +6845,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6636 } 6845 }
6637 #endregion 6846 #endregion
6638 6847
6848 if (SceneAgent.IsChildAgent)
6849 {
6850 SendCantSitBecauseChildAgentResponse();
6851 return true;
6852 }
6853
6639 AgentRequestSit handlerAgentRequestSit = OnAgentRequestSit; 6854 AgentRequestSit handlerAgentRequestSit = OnAgentRequestSit;
6640 6855
6641 if (handlerAgentRequestSit != null) 6856 if (handlerAgentRequestSit != null)
@@ -6660,6 +6875,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6660 } 6875 }
6661 #endregion 6876 #endregion
6662 6877
6878 if (SceneAgent.IsChildAgent)
6879 {
6880 SendCantSitBecauseChildAgentResponse();
6881 return true;
6882 }
6883
6663 AgentSit handlerAgentSit = OnAgentSit; 6884 AgentSit handlerAgentSit = OnAgentSit;
6664 if (handlerAgentSit != null) 6885 if (handlerAgentSit != null)
6665 { 6886 {
@@ -6669,6 +6890,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6669 return true; 6890 return true;
6670 } 6891 }
6671 6892
6893 /// <summary>
6894 /// Used when a child agent gets a sit response which should not be fulfilled.
6895 /// </summary>
6896 private void SendCantSitBecauseChildAgentResponse()
6897 {
6898 SendAlertMessage("Try moving closer. Can't sit on object because it is not in the same region as you.");
6899 }
6900
6672 private bool HandleSoundTrigger(IClientAPI sender, Packet Pack) 6901 private bool HandleSoundTrigger(IClientAPI sender, Packet Pack)
6673 { 6902 {
6674 SoundTriggerPacket soundTriggerPacket = (SoundTriggerPacket)Pack; 6903 SoundTriggerPacket soundTriggerPacket = (SoundTriggerPacket)Pack;
@@ -7879,129 +8108,145 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7879 //m_log.Debug("ClientView.ProcessPackets.cs:ProcessInPacket() - Got transfer request"); 8108 //m_log.Debug("ClientView.ProcessPackets.cs:ProcessInPacket() - Got transfer request");
7880 8109
7881 TransferRequestPacket transfer = (TransferRequestPacket)Pack; 8110 TransferRequestPacket transfer = (TransferRequestPacket)Pack;
7882 //m_log.Debug("Transfer Request: " + transfer.ToString());
7883 // Validate inventory transfers
7884 // Has to be done here, because AssetCache can't do it
7885 //
7886 UUID taskID = UUID.Zero; 8111 UUID taskID = UUID.Zero;
7887 if (transfer.TransferInfo.SourceType == (int)SourceType.SimInventoryItem) 8112 if (transfer.TransferInfo.SourceType == (int)SourceType.SimInventoryItem)
7888 { 8113 {
7889 taskID = new UUID(transfer.TransferInfo.Params, 48);
7890 UUID itemID = new UUID(transfer.TransferInfo.Params, 64);
7891 UUID requestID = new UUID(transfer.TransferInfo.Params, 80);
7892
7893// m_log.DebugFormat(
7894// "[CLIENT]: Got request for asset {0} from item {1} in prim {2} by {3}",
7895// requestID, itemID, taskID, Name);
7896
7897 if (!(((Scene)m_scene).Permissions.BypassPermissions())) 8114 if (!(((Scene)m_scene).Permissions.BypassPermissions()))
7898 { 8115 {
7899 if (taskID != UUID.Zero) // Prim 8116 // We're spawning a thread because the permissions check can block this thread
8117 Util.FireAndForget(delegate
7900 { 8118 {
7901 SceneObjectPart part = ((Scene)m_scene).GetSceneObjectPart(taskID); 8119 // This requests the asset if needed
8120 HandleSimInventoryTransferRequestWithPermsCheck(sender, transfer);
8121 });
8122 return true;
8123 }
8124 }
8125 else if (transfer.TransferInfo.SourceType == (int)SourceType.SimEstate)
8126 {
8127 //TransferRequestPacket does not include covenant uuid?
8128 //get scene covenant uuid
8129 taskID = m_scene.RegionInfo.RegionSettings.Covenant;
8130 }
7902 8131
7903 if (part == null) 8132 // This is non-blocking
7904 { 8133 MakeAssetRequest(transfer, taskID);
7905 m_log.WarnFormat(
7906 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but prim does not exist",
7907 Name, requestID, itemID, taskID);
7908 return true;
7909 }
7910 8134
7911 TaskInventoryItem tii = part.Inventory.GetInventoryItem(itemID); 8135 return true;
7912 if (tii == null) 8136 }
7913 {
7914 m_log.WarnFormat(
7915 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item does not exist",
7916 Name, requestID, itemID, taskID);
7917 return true;
7918 }
7919 8137
7920 if (tii.Type == (int)AssetType.LSLText) 8138 private void HandleSimInventoryTransferRequestWithPermsCheck(IClientAPI sender, TransferRequestPacket transfer)
7921 { 8139 {
7922 if (!((Scene)m_scene).Permissions.CanEditScript(itemID, taskID, AgentId)) 8140 UUID taskID = new UUID(transfer.TransferInfo.Params, 48);
7923 return true; 8141 UUID itemID = new UUID(transfer.TransferInfo.Params, 64);
7924 } 8142 UUID requestID = new UUID(transfer.TransferInfo.Params, 80);
7925 else if (tii.Type == (int)AssetType.Notecard)
7926 {
7927 if (!((Scene)m_scene).Permissions.CanEditNotecard(itemID, taskID, AgentId))
7928 return true;
7929 }
7930 else
7931 {
7932 // TODO: Change this code to allow items other than notecards and scripts to be successfully
7933 // shared with group. In fact, this whole block of permissions checking should move to an IPermissionsModule
7934 if (part.OwnerID != AgentId)
7935 {
7936 m_log.WarnFormat(
7937 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the prim is owned by {4}",
7938 Name, requestID, itemID, taskID, part.OwnerID);
7939 return true;
7940 }
7941 8143
7942 if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0) 8144 //m_log.DebugFormat(
7943 { 8145 // "[CLIENT]: Got request for asset {0} from item {1} in prim {2} by {3}",
7944 m_log.WarnFormat( 8146 // requestID, itemID, taskID, Name);
7945 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but modify permissions are not set",
7946 Name, requestID, itemID, taskID);
7947 return true;
7948 }
7949 8147
7950 if (tii.OwnerID != AgentId) 8148 //m_log.Debug("Transfer Request: " + transfer.ToString());
7951 { 8149 // Validate inventory transfers
7952 m_log.WarnFormat( 8150 // Has to be done here, because AssetCache can't do it
7953 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the item is owned by {4}", 8151 //
7954 Name, requestID, itemID, taskID, tii.OwnerID); 8152 if (taskID != UUID.Zero) // Prim
7955 return true; 8153 {
7956 } 8154 SceneObjectPart part = ((Scene)m_scene).GetSceneObjectPart(taskID);
7957 8155
7958 if (( 8156 if (part == null)
7959 tii.CurrentPermissions & ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) 8157 {
7960 != ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) 8158 m_log.WarnFormat(
7961 { 8159 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but prim does not exist",
7962 m_log.WarnFormat( 8160 Name, requestID, itemID, taskID);
7963 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item permissions are not modify/copy/transfer", 8161 return;
7964 Name, requestID, itemID, taskID); 8162 }
7965 return true;
7966 }
7967 8163
7968 if (tii.AssetID != requestID) 8164 TaskInventoryItem tii = part.Inventory.GetInventoryItem(itemID);
7969 { 8165 if (tii == null)
7970 m_log.WarnFormat( 8166 {
7971 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but this does not match item's asset {4}", 8167 m_log.WarnFormat(
7972 Name, requestID, itemID, taskID, tii.AssetID); 8168 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item does not exist",
7973 return true; 8169 Name, requestID, itemID, taskID);
7974 } 8170 return;
7975 } 8171 }
8172
8173 if (tii.Type == (int)AssetType.LSLText)
8174 {
8175 if (!((Scene)m_scene).Permissions.CanEditScript(itemID, taskID, AgentId))
8176 return;
8177 }
8178 else if (tii.Type == (int)AssetType.Notecard)
8179 {
8180 if (!((Scene)m_scene).Permissions.CanEditNotecard(itemID, taskID, AgentId))
8181 return;
8182 }
8183 else
8184 {
8185 // TODO: Change this code to allow items other than notecards and scripts to be successfully
8186 // shared with group. In fact, this whole block of permissions checking should move to an IPermissionsModule
8187 if (part.OwnerID != AgentId)
8188 {
8189 m_log.WarnFormat(
8190 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the prim is owned by {4}",
8191 Name, requestID, itemID, taskID, part.OwnerID);
8192 return;
7976 } 8193 }
7977 else // Agent 8194
8195 if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0)
7978 { 8196 {
7979 IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>(); 8197 m_log.WarnFormat(
7980 if (invAccess != null) 8198 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but modify permissions are not set",
7981 { 8199 Name, requestID, itemID, taskID);
7982 if (!invAccess.CanGetAgentInventoryItem(this, itemID, requestID)) 8200 return;
7983 return false; 8201 }
7984 } 8202
7985 else 8203 if (tii.OwnerID != AgentId)
7986 { 8204 {
7987 return false; 8205 m_log.WarnFormat(
7988 } 8206 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the item is owned by {4}",
8207 Name, requestID, itemID, taskID, tii.OwnerID);
8208 return;
8209 }
8210
8211 if ((
8212 tii.CurrentPermissions & ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer))
8213 != ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer))
8214 {
8215 m_log.WarnFormat(
8216 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item permissions are not modify/copy/transfer",
8217 Name, requestID, itemID, taskID);
8218 return;
8219 }
8220
8221 if (tii.AssetID != requestID)
8222 {
8223 m_log.WarnFormat(
8224 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but this does not match item's asset {4}",
8225 Name, requestID, itemID, taskID, tii.AssetID);
8226 return;
7989 } 8227 }
7990 } 8228 }
7991 } 8229 }
7992 else 8230 else // Agent
7993 if (transfer.TransferInfo.SourceType == (int)SourceType.SimEstate) 8231 {
8232 IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>();
8233 if (invAccess != null)
8234 {
8235 if (!invAccess.CanGetAgentInventoryItem(this, itemID, requestID))
8236 return;
8237 }
8238 else
7994 { 8239 {
7995 //TransferRequestPacket does not include covenant uuid? 8240 return;
7996 //get scene covenant uuid
7997 taskID = m_scene.RegionInfo.RegionSettings.Covenant;
7998 } 8241 }
8242 }
7999 8243
8244 // Permissions out of the way, let's request the asset
8000 MakeAssetRequest(transfer, taskID); 8245 MakeAssetRequest(transfer, taskID);
8001 8246
8002 return true;
8003 } 8247 }
8004 8248
8249
8005 private bool HandleAssetUploadRequest(IClientAPI sender, Packet Pack) 8250 private bool HandleAssetUploadRequest(IClientAPI sender, Packet Pack)
8006 { 8251 {
8007 AssetUploadRequestPacket request = (AssetUploadRequestPacket)Pack; 8252 AssetUploadRequestPacket request = (AssetUploadRequestPacket)Pack;
@@ -11732,8 +11977,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11732 } 11977 }
11733 11978
11734 /// <summary> 11979 /// <summary>
11735 /// Send a response back to a client when it asks the asset server (via the region server) if it has
11736 /// its appearance texture cached.
11737 /// </summary> 11980 /// </summary>
11738 /// <remarks> 11981 /// <remarks>
11739 /// At the moment, we always reply that there is no cached texture. 11982 /// At the moment, we always reply that there is no cached texture.
@@ -11741,6 +11984,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11741 /// <param name="simclient"></param> 11984 /// <param name="simclient"></param>
11742 /// <param name="packet"></param> 11985 /// <param name="packet"></param>
11743 /// <returns></returns> 11986 /// <returns></returns>
11987 // TODO: Convert old handler to use new method
11988 /*protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet)
11989 {
11990 AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet;
11991
11992 if (cachedtex.AgentData.SessionID != SessionId)
11993 return false;
11994
11995
11996 List<CachedTextureRequestArg> requestArgs = new List<CachedTextureRequestArg>();
11997
11998 for (int i = 0; i < cachedtex.WearableData.Length; i++)
11999 {
12000 CachedTextureRequestArg arg = new CachedTextureRequestArg();
12001 arg.BakedTextureIndex = cachedtex.WearableData[i].TextureIndex;
12002 arg.WearableHashID = cachedtex.WearableData[i].ID;
12003
12004 requestArgs.Add(arg);
12005 }
12006
12007 CachedTextureRequest handlerCachedTextureRequest = OnCachedTextureRequest;
12008 if (handlerCachedTextureRequest != null)
12009 {
12010 handlerCachedTextureRequest(simclient,cachedtex.AgentData.SerialNum,requestArgs);
12011 }
12012
12013 return true;
12014 }*/
12015
11744 protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet) 12016 protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet)
11745 { 12017 {
11746 //m_log.Debug("texture cached: " + packet.ToString()); 12018 //m_log.Debug("texture cached: " + packet.ToString());
@@ -11749,156 +12021,105 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11749 12021
11750 if (cachedtex.AgentData.SessionID != SessionId) 12022 if (cachedtex.AgentData.SessionID != SessionId)
11751 return false; 12023 return false;
11752
11753 12024
11754 // TODO: don't create new blocks if recycling an old packet 12025 // TODO: don't create new blocks if recycling an old packet
11755 cachedresp.AgentData.AgentID = AgentId; 12026 cachedresp.AgentData.AgentID = AgentId;
11756 cachedresp.AgentData.SessionID = m_sessionId; 12027 cachedresp.AgentData.SessionID = m_sessionId;
11757 cachedresp.AgentData.SerialNum = m_cachedTextureSerial; 12028 cachedresp.AgentData.SerialNum = cachedtex.AgentData.SerialNum;
11758 m_cachedTextureSerial++;
11759 cachedresp.WearableData = 12029 cachedresp.WearableData =
11760 new AgentCachedTextureResponsePacket.WearableDataBlock[cachedtex.WearableData.Length]; 12030 new AgentCachedTextureResponsePacket.WearableDataBlock[cachedtex.WearableData.Length];
11761 12031
11762 //IAvatarFactoryModule fac = m_scene.RequestModuleInterface<IAvatarFactoryModule>();
11763 // var item = fac.GetBakedTextureFaces(AgentId);
11764 //WearableCacheItem[] items = fac.GetCachedItems(AgentId);
11765
11766 IAssetService cache = m_scene.AssetService;
11767 IBakedTextureModule bakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
11768 //bakedTextureModule = null;
11769 int maxWearablesLoop = cachedtex.WearableData.Length; 12032 int maxWearablesLoop = cachedtex.WearableData.Length;
11770 if (maxWearablesLoop > AvatarWearable.MAX_WEARABLES) 12033 if (maxWearablesLoop > AvatarWearable.MAX_WEARABLES)
11771 maxWearablesLoop = AvatarWearable.MAX_WEARABLES; 12034 maxWearablesLoop = AvatarWearable.MAX_WEARABLES;
11772 12035
11773 if (bakedTextureModule != null && cache != null) 12036 int cacheHits = 0;
11774 {
11775 // We need to make sure the asset stored in the bake is available on this server also by it's assetid before we map it to a Cacheid
11776 12037
11777 WearableCacheItem[] cacheItems = null; 12038 // We need to make sure the asset stored in the bake is available on this server also by it's assetid before we map it to a Cacheid
11778 ScenePresence p = m_scene.GetScenePresence(AgentId);
11779 if (p.Appearance != null)
11780 if (p.Appearance.WearableCacheItems == null || p.Appearance.WearableCacheItemsDirty)
11781 {
11782 try
11783 {
11784 cacheItems = bakedTextureModule.Get(AgentId);
11785 p.Appearance.WearableCacheItems = cacheItems;
11786 p.Appearance.WearableCacheItemsDirty = false;
11787 }
11788 12039
11789 /* 12040 WearableCacheItem[] cacheItems = null;
11790 * The following Catch types DO NOT WORK, it jumps to the General Packet Exception Handler if you don't catch Exception!
11791 *
11792 catch (System.Net.Sockets.SocketException)
11793 {
11794 cacheItems = null;
11795 }
11796 catch (WebException)
11797 {
11798 cacheItems = null;
11799 }
11800 catch (InvalidOperationException)
11801 {
11802 cacheItems = null;
11803 } */
11804 catch (Exception)
11805 {
11806 cacheItems = null;
11807 }
11808
11809 }
11810 else if (p.Appearance.WearableCacheItems != null)
11811 {
11812 cacheItems = p.Appearance.WearableCacheItems;
11813 }
11814 12041
11815 if (cache != null && cacheItems != null) 12042 ScenePresence p = m_scene.GetScenePresence(AgentId);
11816 {
11817 foreach (WearableCacheItem item in cacheItems)
11818 {
11819
11820 if (cache.GetCached(item.TextureID.ToString()) == null)
11821 {
11822 item.TextureAsset.Temporary = true;
11823 cache.Store(item.TextureAsset);
11824 }
11825 12043
12044 if (p != null && p.Appearance != null)
12045 {
12046 cacheItems = p.Appearance.WearableCacheItems;
12047 }
11826 12048
11827 } 12049 if (cacheItems != null)
11828 } 12050 {
11829 12051 for (int i = 0; i < maxWearablesLoop; i++)
11830 if (cacheItems != null)
11831 { 12052 {
11832 12053 int idx = cachedtex.WearableData[i].TextureIndex;
11833 for (int i = 0; i < maxWearablesLoop; i++)
11834 {
11835 WearableCacheItem item =
11836 WearableCacheItem.SearchTextureIndex(cachedtex.WearableData[i].TextureIndex,cacheItems);
11837 12054
11838 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); 12055 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11839 cachedresp.WearableData[i].TextureIndex= cachedtex.WearableData[i].TextureIndex; 12056 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
11840 cachedresp.WearableData[i].HostName = new byte[0]; 12057 cachedresp.WearableData[i].HostName = new byte[0];
11841 if (item != null && cachedtex.WearableData[i].ID == item.CacheId) 12058 if (cachedtex.WearableData[i].ID == cacheItems[idx].CacheId)
11842 { 12059 {
11843 12060 cachedresp.WearableData[i].TextureID = cacheItems[idx].TextureID;
11844 cachedresp.WearableData[i].TextureID = item.TextureID; 12061 cacheHits++;
11845 }
11846 else
11847 {
11848 cachedresp.WearableData[i].TextureID = UUID.Zero;
11849 }
11850 } 12062 }
11851 } 12063 else
11852 else
11853 {
11854 for (int i = 0; i < maxWearablesLoop; i++)
11855 { 12064 {
11856 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11857 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
11858 cachedresp.WearableData[i].TextureID = UUID.Zero; 12065 cachedresp.WearableData[i].TextureID = UUID.Zero;
11859 //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
11860 cachedresp.WearableData[i].HostName = new byte[0];
11861 } 12066 }
11862 } 12067 }
11863 } 12068 }
11864 else 12069 else
11865 { 12070 {
11866 if (cache == null) 12071 for (int i = 0; i < maxWearablesLoop; i++)
11867 { 12072 {
11868 for (int i = 0; i < maxWearablesLoop; i++) 12073 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11869 { 12074 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
11870 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); 12075 cachedresp.WearableData[i].TextureID = UUID.Zero;
11871 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex; 12076 //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
11872 cachedresp.WearableData[i].TextureID = UUID.Zero; 12077 cachedresp.WearableData[i].HostName = new byte[0];
11873 //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
11874 cachedresp.WearableData[i].HostName = new byte[0];
11875 }
11876 } 12078 }
11877 else 12079 }
11878 {
11879 for (int i = 0; i < maxWearablesLoop; i++)
11880 {
11881 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11882 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
11883
11884 12080
12081 m_log.DebugFormat("texture cached: hits {0}", cacheHits);
11885 12082
11886 if (cache.GetCached(cachedresp.WearableData[i].TextureID.ToString()) == null)
11887 cachedresp.WearableData[i].TextureID = UUID.Zero;
11888 //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
11889 else
11890 cachedresp.WearableData[i].TextureID = UUID.Zero;
11891 // UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
11892 cachedresp.WearableData[i].HostName = new byte[0];
11893 }
11894 }
11895 }
11896 cachedresp.Header.Zerocoded = true; 12083 cachedresp.Header.Zerocoded = true;
11897 OutPacket(cachedresp, ThrottleOutPacketType.Task); 12084 OutPacket(cachedresp, ThrottleOutPacketType.Task);
11898 12085
11899 return true; 12086 return true;
11900 } 12087 }
11901 12088
12089 /// <summary>
12090 /// Send a response back to a client when it asks the asset server (via the region server) if it has
12091 /// its appearance texture cached.
12092 /// </summary>
12093 /// <param name="avatar"></param>
12094 /// <param name="serial"></param>
12095 /// <param name="cachedTextures"></param>
12096 /// <returns></returns>
12097 public void SendCachedTextureResponse(ISceneEntity avatar, int serial, List<CachedTextureResponseArg> cachedTextures)
12098 {
12099 ScenePresence presence = avatar as ScenePresence;
12100 if (presence == null)
12101 return;
12102
12103 AgentCachedTextureResponsePacket cachedresp = (AgentCachedTextureResponsePacket)PacketPool.Instance.GetPacket(PacketType.AgentCachedTextureResponse);
12104
12105 // TODO: don't create new blocks if recycling an old packet
12106 cachedresp.AgentData.AgentID = m_agentId;
12107 cachedresp.AgentData.SessionID = m_sessionId;
12108 cachedresp.AgentData.SerialNum = serial;
12109 cachedresp.WearableData = new AgentCachedTextureResponsePacket.WearableDataBlock[cachedTextures.Count];
12110
12111 for (int i = 0; i < cachedTextures.Count; i++)
12112 {
12113 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
12114 cachedresp.WearableData[i].TextureIndex = (byte)cachedTextures[i].BakedTextureIndex;
12115 cachedresp.WearableData[i].TextureID = cachedTextures[i].BakedTextureID;
12116 cachedresp.WearableData[i].HostName = new byte[0];
12117 }
12118
12119 cachedresp.Header.Zerocoded = true;
12120 OutPacket(cachedresp, ThrottleOutPacketType.Task);
12121 }
12122
11902 protected bool HandleMultipleObjUpdate(IClientAPI simClient, Packet packet) 12123 protected bool HandleMultipleObjUpdate(IClientAPI simClient, Packet packet)
11903 { 12124 {
11904 MultipleObjectUpdatePacket multipleupdate = (MultipleObjectUpdatePacket)packet; 12125 MultipleObjectUpdatePacket multipleupdate = (MultipleObjectUpdatePacket)packet;
@@ -11924,8 +12145,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11924 if (part == null) 12145 if (part == null)
11925 { 12146 {
11926 // It's a ghost! tell the client to delete it from view. 12147 // It's a ghost! tell the client to delete it from view.
11927 simClient.SendKillObject(Scene.RegionInfo.RegionHandle, 12148 simClient.SendKillObject(new List<uint> { localId });
11928 new List<uint> { localId });
11929 } 12149 }
11930 else 12150 else
11931 { 12151 {
@@ -12129,7 +12349,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12129 /// <param name="throttles"></param> 12349 /// <param name="throttles"></param>
12130 public void SetChildAgentThrottle(byte[] throttles) 12350 public void SetChildAgentThrottle(byte[] throttles)
12131 { 12351 {
12132 m_udpClient.SetThrottles(throttles); 12352 SetChildAgentThrottle(throttles, 1.0f);
12353 }
12354
12355 public void SetChildAgentThrottle(byte[] throttles,float factor)
12356 {
12357 m_udpClient.SetThrottles(throttles, factor);
12133 GenericCall2 handler = OnUpdateThrottles; 12358 GenericCall2 handler = OnUpdateThrottles;
12134 if (handler != null) 12359 if (handler != null)
12135 { 12360 {
@@ -12138,16 +12363,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12138 } 12363 }
12139 12364
12140 /// <summary> 12365 /// <summary>
12141 /// Sets the throttles from values supplied by the client 12366 /// Sets the throttles from values supplied caller
12142 /// </summary> 12367 /// </summary>
12143 /// <param name="throttles"></param> 12368 /// <param name="throttles"></param>
12144 public void SetAgentThrottleSilent(int throttle, int setting) 12369 public void SetAgentThrottleSilent(int throttle, int setting)
12145 { 12370 {
12146 m_udpClient.ForceThrottleSetting(throttle,setting); 12371 m_udpClient.ForceThrottleSetting(throttle,setting);
12147 //m_udpClient.SetThrottles(throttles);
12148
12149 } 12372 }
12150 12373
12374 public int GetAgentThrottleSilent(int throttle)
12375 {
12376 return m_udpClient.GetThrottleSetting(throttle);
12377 }
12151 12378
12152 /// <summary> 12379 /// <summary>
12153 /// Get the current throttles for this client as a packed byte array 12380 /// Get the current throttles for this client as a packed byte array
@@ -12250,8 +12477,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12250 uint regionY = 0; 12477 uint regionY = 0;
12251 12478
12252 Utils.LongToUInts(m_scene.RegionInfo.RegionHandle, out regionX, out regionY); 12479 Utils.LongToUInts(m_scene.RegionInfo.RegionHandle, out regionX, out regionY);
12253 locx = Convert.ToSingle(args[0]) - (float)regionX; 12480 locx = (float)(Convert.ToDouble(args[0]) - (double)regionX);
12254 locy = Convert.ToSingle(args[1]) - (float)regionY; 12481 locy = (float)(Convert.ToDouble(args[1]) - (double)regionY);
12255 locz = Convert.ToSingle(args[2]); 12482 locz = Convert.ToSingle(args[2]);
12256 12483
12257 Action<Vector3, bool, bool> handlerAutoPilotGo = OnAutoPilotGo; 12484 Action<Vector3, bool, bool> handlerAutoPilotGo = OnAutoPilotGo;
@@ -12299,6 +12526,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12299 12526
12300 shape.PCode = addPacket.ObjectData.PCode; 12527 shape.PCode = addPacket.ObjectData.PCode;
12301 shape.State = addPacket.ObjectData.State; 12528 shape.State = addPacket.ObjectData.State;
12529 shape.LastAttachPoint = addPacket.ObjectData.State;
12302 shape.PathBegin = addPacket.ObjectData.PathBegin; 12530 shape.PathBegin = addPacket.ObjectData.PathBegin;
12303 shape.PathEnd = addPacket.ObjectData.PathEnd; 12531 shape.PathEnd = addPacket.ObjectData.PathEnd;
12304 shape.PathScaleX = addPacket.ObjectData.PathScaleX; 12532 shape.PathScaleX = addPacket.ObjectData.PathScaleX;
@@ -12329,7 +12557,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12329 ClientInfo info = m_udpClient.GetClientInfo(); 12557 ClientInfo info = m_udpClient.GetClientInfo();
12330 12558
12331 info.proxyEP = null; 12559 info.proxyEP = null;
12332 info.agentcircuit = RequestClientInfo(); 12560 if (info.agentcircuit == null)
12561 info.agentcircuit = RequestClientInfo();
12333 12562
12334 return info; 12563 return info;
12335 } 12564 }
@@ -12712,11 +12941,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12712 OutPacket(dialog, ThrottleOutPacketType.Task); 12941 OutPacket(dialog, ThrottleOutPacketType.Task);
12713 } 12942 }
12714 12943
12715 public void StopFlying(ISceneEntity p) 12944 public void SendAgentTerseUpdate(ISceneEntity p)
12716 { 12945 {
12717 if (p is ScenePresence) 12946 if (p is ScenePresence)
12718 { 12947 {
12719 ScenePresence presence = p as ScenePresence; 12948// m_log.DebugFormat(
12949// "[LLCLIENTVIEW]: Immediately sending terse agent update for {0} to {1} in {2}",
12950// p.Name, Name, Scene.Name);
12951
12720 // It turns out to get the agent to stop flying, you have to feed it stop flying velocities 12952 // It turns out to get the agent to stop flying, you have to feed it stop flying velocities
12721 // There's no explicit message to send the client to tell it to stop flying.. it relies on the 12953 // There's no explicit message to send the client to tell it to stop flying.. it relies on the
12722 // velocity, collision plane and avatar height 12954 // velocity, collision plane and avatar height
@@ -12724,34 +12956,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12724 // Add 1/6 the avatar's height to it's position so it doesn't shoot into the air 12956 // Add 1/6 the avatar's height to it's position so it doesn't shoot into the air
12725 // when the avatar stands up 12957 // when the avatar stands up
12726 12958
12727 Vector3 pos = presence.AbsolutePosition;
12728
12729 if (presence.Appearance.AvatarHeight != 127.0f)
12730 pos += new Vector3(0f, 0f, (presence.Appearance.AvatarHeight/6f));
12731 else
12732 pos += new Vector3(0f, 0f, (1.56f/6f));
12733
12734 presence.AbsolutePosition = pos;
12735
12736 // attach a suitable collision plane regardless of the actual situation to force the LLClient to land.
12737 // Collision plane below the avatar's position a 6th of the avatar's height is suitable.
12738 // Mind you, that this method doesn't get called if the avatar's velocity magnitude is greater then a
12739 // certain amount.. because the LLClient wouldn't land in that situation anyway.
12740
12741 // why are we still testing for this really old height value default???
12742 if (presence.Appearance.AvatarHeight != 127.0f)
12743 presence.CollisionPlane = new Vector4(0, 0, 0, pos.Z - presence.Appearance.AvatarHeight/6f);
12744 else
12745 presence.CollisionPlane = new Vector4(0, 0, 0, pos.Z - (1.56f/6f));
12746
12747
12748 ImprovedTerseObjectUpdatePacket.ObjectDataBlock block = 12959 ImprovedTerseObjectUpdatePacket.ObjectDataBlock block =
12749 CreateImprovedTerseBlock(p, false); 12960 CreateImprovedTerseBlock(p, false);
12750 12961
12751 const float TIME_DILATION = 1.0f; 12962 const float TIME_DILATION = 1.0f;
12752 ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f); 12963 ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f);
12753 12964
12754
12755 ImprovedTerseObjectUpdatePacket packet 12965 ImprovedTerseObjectUpdatePacket packet
12756 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket( 12966 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
12757 PacketType.ImprovedTerseObjectUpdate); 12967 PacketType.ImprovedTerseObjectUpdate);
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs
index 073c357..41dd4d1 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs
@@ -206,6 +206,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
206 } 206 }
207 } 207 }
208 208
209 public bool HasUpdates()
210 {
211 J2KImage image = GetHighestPriorityImage();
212
213 return image != null && image.IsDecoded;
214 }
215
209 public bool ProcessImageQueue(int packetsToSend) 216 public bool ProcessImageQueue(int packetsToSend)
210 { 217 {
211 int packetsSent = 0; 218 int packetsSent = 0;
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
index e52ac37..0ae7617 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
@@ -31,6 +31,7 @@ using System.Net;
31using System.Threading; 31using System.Threading;
32using log4net; 32using log4net;
33using OpenSim.Framework; 33using OpenSim.Framework;
34using OpenSim.Framework.Monitoring;
34using OpenMetaverse; 35using OpenMetaverse;
35using OpenMetaverse.Packets; 36using OpenMetaverse.Packets;
36 37
@@ -81,6 +82,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
81 /// hooked to put more data on the empty queue</summary> 82 /// hooked to put more data on the empty queue</summary>
82 public event QueueEmpty OnQueueEmpty; 83 public event QueueEmpty OnQueueEmpty;
83 84
85 public event Func<ThrottleOutPacketTypeFlags, bool> HasUpdates;
86
84 /// <summary>AgentID for this client</summary> 87 /// <summary>AgentID for this client</summary>
85 public readonly UUID AgentID; 88 public readonly UUID AgentID;
86 /// <summary>The remote address of the connected client</summary> 89 /// <summary>The remote address of the connected client</summary>
@@ -141,8 +144,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
141 get { return m_throttleClient; } 144 get { return m_throttleClient; }
142 } 145 }
143 146
144 /// <summary>Throttle bucket for this agent's connection</summary>
145 private readonly TokenBucket m_throttleCategory;
146 /// <summary>Throttle buckets for each packet category</summary> 147 /// <summary>Throttle buckets for each packet category</summary>
147 private readonly TokenBucket[] m_throttleCategories; 148 private readonly TokenBucket[] m_throttleCategories;
148 /// <summary>Outgoing queues for throttled packets</summary> 149 /// <summary>Outgoing queues for throttled packets</summary>
@@ -160,6 +161,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP
160 private int m_maxRTO = 60000; 161 private int m_maxRTO = 60000;
161 public bool m_deliverPackets = true; 162 public bool m_deliverPackets = true;
162 163
164 private float m_burstTime;
165
166 public int m_lastStartpingTimeMS;
167 public int m_pingMS;
168
169 public int PingTimeMS
170 {
171 get
172 {
173 if (m_pingMS < 10)
174 return 10;
175 if(m_pingMS > 2000)
176 return 2000;
177 return m_pingMS;
178 }
179 }
180
181 /// <summary>
182 /// This is the percentage of the udp texture queue to add to the task queue since
183 /// textures are now generally handled through http.
184 /// </summary>
185 private double m_cannibalrate = 0.0;
186
187 private ClientInfo m_info = new ClientInfo();
188
163 /// <summary> 189 /// <summary>
164 /// Default constructor 190 /// Default constructor
165 /// </summary> 191 /// </summary>
@@ -190,13 +216,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
190 if (maxRTO != 0) 216 if (maxRTO != 0)
191 m_maxRTO = maxRTO; 217 m_maxRTO = maxRTO;
192 218
219 m_burstTime = rates.BrustTime;
220 float m_burst = rates.ClientMaxRate * m_burstTime;
221
193 // Create a token bucket throttle for this client that has the scene token bucket as a parent 222 // Create a token bucket throttle for this client that has the scene token bucket as a parent
194 m_throttleClient = new AdaptiveTokenBucket(parentThrottle, rates.Total, rates.AdaptiveThrottlesEnabled); 223 m_throttleClient = new AdaptiveTokenBucket(parentThrottle, rates.ClientMaxRate, m_burst, 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);
197 // Create an array of token buckets for this clients different throttle categories 224 // Create an array of token buckets for this clients different throttle categories
198 m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; 225 m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT];
199 226
227 m_cannibalrate = rates.CannibalizeTextureRate;
228
229 m_burst = rates.Total * rates.BrustTime;
230
200 for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) 231 for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
201 { 232 {
202 ThrottleOutPacketType type = (ThrottleOutPacketType)i; 233 ThrottleOutPacketType type = (ThrottleOutPacketType)i;
@@ -204,7 +235,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
204 // Initialize the packet outboxes, where packets sit while they are waiting for tokens 235 // Initialize the packet outboxes, where packets sit while they are waiting for tokens
205 m_packetOutboxes[i] = new DoubleLocklessQueue<OutgoingPacket>(); 236 m_packetOutboxes[i] = new DoubleLocklessQueue<OutgoingPacket>();
206 // Initialize the token buckets that control the throttling for each category 237 // Initialize the token buckets that control the throttling for each category
207 m_throttleCategories[i] = new TokenBucket(m_throttleCategory, rates.GetRate(type)); 238 m_throttleCategories[i] = new TokenBucket(m_throttleClient, rates.GetRate(type), m_burst);
208 } 239 }
209 240
210 // Default the retransmission timeout to one second 241 // Default the retransmission timeout to one second
@@ -212,6 +243,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
212 243
213 // Initialize this to a sane value to prevent early disconnects 244 // Initialize this to a sane value to prevent early disconnects
214 TickLastPacketReceived = Environment.TickCount & Int32.MaxValue; 245 TickLastPacketReceived = Environment.TickCount & Int32.MaxValue;
246 m_pingMS = (int)(3.0 * server.TickCountResolution); // so filter doesnt start at 0;
215 } 247 }
216 248
217 /// <summary> 249 /// <summary>
@@ -241,20 +273,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
241 // TODO: This data structure is wrong in so many ways. Locking and copying the entire lists 273 // TODO: This data structure is wrong in so many ways. Locking and copying the entire lists
242 // of pending and needed ACKs for every client every time some method wants information about 274 // of pending and needed ACKs for every client every time some method wants information about
243 // this connection is a recipe for poor performance 275 // this connection is a recipe for poor performance
244 ClientInfo info = new ClientInfo(); 276
245 info.pendingAcks = new Dictionary<uint, uint>(); 277 m_info.resendThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate;
246 info.needAck = new Dictionary<uint, byte[]>(); 278 m_info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate;
247 279 m_info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate;
248 info.resendThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate; 280 m_info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate;
249 info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; 281 m_info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate;
250 info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; 282 m_info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate;
251 info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; 283 m_info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate;
252 info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; 284 m_info.totalThrottle = (int)m_throttleClient.DripRate;
253 info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; 285
254 info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; 286 return m_info;
255 info.totalThrottle = (int)m_throttleCategory.DripRate;
256
257 return info;
258 } 287 }
259 288
260 /// <summary> 289 /// <summary>
@@ -311,6 +340,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
311 340
312 public void SetThrottles(byte[] throttleData) 341 public void SetThrottles(byte[] throttleData)
313 { 342 {
343 SetThrottles(throttleData, 1.0f);
344 }
345
346 public void SetThrottles(byte[] throttleData, float factor)
347 {
314 byte[] adjData; 348 byte[] adjData;
315 int pos = 0; 349 int pos = 0;
316 350
@@ -330,16 +364,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
330 } 364 }
331 365
332 // 0.125f converts from bits to bytes 366 // 0.125f converts from bits to bytes
333 int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; 367 float scale = 0.125f * factor;
334 int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; 368 int resend = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4;
335 int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; 369 int land = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4;
336 int cloud = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; 370 int wind = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4;
337 int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; 371 int cloud = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4;
338 int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; 372 int task = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4;
339 int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); 373 int texture = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4;
374 int asset = (int)(BitConverter.ToSingle(adjData, pos) * scale);
340 375
341 // Make sure none of the throttles are set below our packet MTU, 376 // Make sure none of the throttles are set below our packet MTU,
342 // otherwise a throttle could become permanently clogged 377 // otherwise a throttle could become permanently clogged
378
379/* not using floats
343 resend = Math.Max(resend, LLUDPServer.MTU); 380 resend = Math.Max(resend, LLUDPServer.MTU);
344 land = Math.Max(land, LLUDPServer.MTU); 381 land = Math.Max(land, LLUDPServer.MTU);
345 wind = Math.Max(wind, LLUDPServer.MTU); 382 wind = Math.Max(wind, LLUDPServer.MTU);
@@ -347,8 +384,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
347 task = Math.Max(task, LLUDPServer.MTU); 384 task = Math.Max(task, LLUDPServer.MTU);
348 texture = Math.Max(texture, LLUDPServer.MTU); 385 texture = Math.Max(texture, LLUDPServer.MTU);
349 asset = Math.Max(asset, LLUDPServer.MTU); 386 asset = Math.Max(asset, LLUDPServer.MTU);
387*/
388
389 // Since most textures are now delivered through http, make it possible
390 // to cannibalize some of the bw from the texture throttle to use for
391 // the task queue (e.g. object updates)
392 task = task + (int)(m_cannibalrate * texture);
393 texture = (int)((1 - m_cannibalrate) * texture);
394
395 int total = resend + land + wind + cloud + task + texture + asset;
396
397 float m_burst = total * m_burstTime;
350 398
351 //int total = resend + land + wind + cloud + task + texture + asset;
352 //m_log.DebugFormat("[LLUDPCLIENT]: {0} is setting throttles. Resend={1}, Land={2}, Wind={3}, Cloud={4}, Task={5}, Texture={6}, Asset={7}, Total={8}", 399 //m_log.DebugFormat("[LLUDPCLIENT]: {0} is setting throttles. Resend={1}, Land={2}, Wind={3}, Cloud={4}, Task={5}, Texture={6}, Asset={7}, Total={8}",
353 // AgentID, resend, land, wind, cloud, task, texture, asset, total); 400 // AgentID, resend, land, wind, cloud, task, texture, asset, total);
354 401
@@ -357,24 +404,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP
357 404
358 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend]; 405 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend];
359 bucket.RequestedDripRate = resend; 406 bucket.RequestedDripRate = resend;
407 bucket.RequestedBurst = m_burst;
360 408
361 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land]; 409 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land];
362 bucket.RequestedDripRate = land; 410 bucket.RequestedDripRate = land;
411 bucket.RequestedBurst = m_burst;
363 412
364 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind]; 413 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind];
365 bucket.RequestedDripRate = wind; 414 bucket.RequestedDripRate = wind;
415 bucket.RequestedBurst = m_burst;
366 416
367 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud]; 417 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud];
368 bucket.RequestedDripRate = cloud; 418 bucket.RequestedDripRate = cloud;
419 bucket.RequestedBurst = m_burst;
369 420
370 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset]; 421 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset];
371 bucket.RequestedDripRate = asset; 422 bucket.RequestedDripRate = asset;
423 bucket.RequestedBurst = m_burst;
372 424
373 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task]; 425 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task];
374 bucket.RequestedDripRate = task; 426 bucket.RequestedDripRate = task;
427 bucket.RequestedBurst = m_burst;
375 428
376 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture]; 429 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture];
377 bucket.RequestedDripRate = texture; 430 bucket.RequestedDripRate = texture;
431 bucket.RequestedBurst = m_burst;
378 432
379 // Reset the packed throttles cached data 433 // Reset the packed throttles cached data
380 m_packedThrottles = null; 434 m_packedThrottles = null;
@@ -392,25 +446,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
392 int i = 0; 446 int i = 0;
393 447
394 // multiply by 8 to convert bytes back to bits 448 // multiply by 8 to convert bytes back to bits
395 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].RequestedDripRate * 8 * multiplier; 449 multiplier *= 8;
450
451 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].RequestedDripRate * multiplier;
396 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; 452 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
397 453
398 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Land].RequestedDripRate * 8 * multiplier; 454 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Land].RequestedDripRate * multiplier;
399 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; 455 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
400 456
401 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].RequestedDripRate * 8 * multiplier; 457 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].RequestedDripRate * multiplier;
402 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; 458 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
403 459
404 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].RequestedDripRate * 8 * multiplier; 460 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].RequestedDripRate * multiplier;
405 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; 461 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
406 462
407 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Task].RequestedDripRate * 8 * multiplier; 463 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Task].RequestedDripRate * multiplier;
408 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; 464 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
409 465
410 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].RequestedDripRate * 8 * multiplier; 466 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].RequestedDripRate * multiplier;
411 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; 467 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
412 468
413 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].RequestedDripRate * 8 * multiplier; 469 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].RequestedDripRate * multiplier;
414 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; 470 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
415 471
416 m_packedThrottles = data; 472 m_packedThrottles = data;
@@ -418,6 +474,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
418 474
419 return data; 475 return data;
420 } 476 }
477
478 public int GetCatBytesCanSend(ThrottleOutPacketType cat, int timeMS)
479 {
480 int icat = (int)cat;
481 if (icat > 0 && icat < THROTTLE_CATEGORY_COUNT)
482 {
483 TokenBucket bucket = m_throttleCategories[icat];
484 return bucket.GetCatBytesCanSend(timeMS);
485 }
486 else
487 return 0;
488 }
421 489
422 /// <summary> 490 /// <summary>
423 /// Queue an outgoing packet if appropriate. 491 /// Queue an outgoing packet if appropriate.
@@ -449,19 +517,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
449 517
450 TokenBucket bucket = m_throttleCategories[category]; 518 TokenBucket bucket = m_throttleCategories[category];
451 519
452 // Don't send this packet if there is already a packet waiting in the queue 520 // Don't send this packet if queue is not empty
453 // even if we have the tokens to send it, tokens should go to the already 521 if (queue.Count > 0 || m_nextPackets[category] != null)
454 // queued packets
455 if (queue.Count > 0)
456 { 522 {
457 queue.Enqueue(packet, highPriority); 523 queue.Enqueue(packet, highPriority);
458 return true; 524 return true;
459 } 525 }
460 526
461
462 if (!forceQueue && bucket.RemoveTokens(packet.Buffer.DataLength)) 527 if (!forceQueue && bucket.RemoveTokens(packet.Buffer.DataLength))
463 { 528 {
464 // Enough tokens were removed from the bucket, the packet will not be queued 529 // enough tokens so it can be sent imediatly by caller
465 return false; 530 return false;
466 } 531 }
467 else 532 else
@@ -496,7 +561,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
496 /// <returns>True if any packets were sent, otherwise false</returns> 561 /// <returns>True if any packets were sent, otherwise false</returns>
497 public bool DequeueOutgoing() 562 public bool DequeueOutgoing()
498 { 563 {
499 if (m_deliverPackets == false) return false; 564// if (m_deliverPackets == false) return false;
500 565
501 OutgoingPacket packet = null; 566 OutgoingPacket packet = null;
502 DoubleLocklessQueue<OutgoingPacket> queue; 567 DoubleLocklessQueue<OutgoingPacket> queue;
@@ -523,6 +588,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
523 m_udpServer.SendPacketFinal(nextPacket); 588 m_udpServer.SendPacketFinal(nextPacket);
524 m_nextPackets[i] = null; 589 m_nextPackets[i] = null;
525 packetSent = true; 590 packetSent = true;
591
592 if (m_packetOutboxes[i].Count < 5)
593 emptyCategories |= CategoryToFlag(i);
526 } 594 }
527 } 595 }
528 else 596 else
@@ -550,6 +618,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
550 // Send the packet 618 // Send the packet
551 m_udpServer.SendPacketFinal(packet); 619 m_udpServer.SendPacketFinal(packet);
552 packetSent = true; 620 packetSent = true;
621
622 if (queue.Count < 5)
623 emptyCategories |= CategoryToFlag(i);
553 } 624 }
554 else 625 else
555 { 626 {
@@ -557,11 +628,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
557 m_nextPackets[i] = packet; 628 m_nextPackets[i] = packet;
558 } 629 }
559 630
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 } 631 }
566 else 632 else
567 { 633 {
@@ -639,6 +705,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
639 RTO = Math.Min(RTO * 2, m_maxRTO); 705 RTO = Math.Min(RTO * 2, m_maxRTO);
640 } 706 }
641 707
708
709 const int MIN_CALLBACK_MS = 10;
710
642 /// <summary> 711 /// <summary>
643 /// Does an early check to see if this queue empty callback is already 712 /// Does an early check to see if this queue empty callback is already
644 /// running, then asynchronously firing the event 713 /// running, then asynchronously firing the event
@@ -646,15 +715,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP
646 /// <param name="categories">Throttle categories to fire the callback for</param> 715 /// <param name="categories">Throttle categories to fire the callback for</param>
647 private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories) 716 private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories)
648 { 717 {
649 if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty) 718 if (!m_isQueueEmptyRunning)
650 { 719 {
651 // Use a value of 0 to signal that FireQueueEmpty is running 720 int start = Environment.TickCount & Int32.MaxValue;
652 m_nextOnQueueEmpty = 0; 721
653 // Asynchronously run the callback 722 if (start < m_nextOnQueueEmpty)
654 Util.FireAndForget(FireQueueEmpty, categories); 723 return;
724
725 m_isQueueEmptyRunning = true;
726
727 m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
728 if (m_nextOnQueueEmpty == 0)
729 m_nextOnQueueEmpty = 1;
730
731 if (HasUpdates(categories))
732 {
733 // Asynchronously run the callback
734 Util.FireAndForget(FireQueueEmpty, categories);
735 }
736 else
737 {
738 m_isQueueEmptyRunning = false;
739 }
655 } 740 }
656 } 741 }
657 742
743 private bool m_isQueueEmptyRunning;
744
745
658 /// <summary> 746 /// <summary>
659 /// Fires the OnQueueEmpty callback and sets the minimum time that it 747 /// Fires the OnQueueEmpty callback and sets the minimum time that it
660 /// can be called again 748 /// can be called again
@@ -664,26 +752,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP
664 /// signature</param> 752 /// signature</param>
665 private void FireQueueEmpty(object o) 753 private void FireQueueEmpty(object o)
666 { 754 {
667 const int MIN_CALLBACK_MS = 30;
668
669 ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o; 755 ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o;
670 QueueEmpty callback = OnQueueEmpty; 756 QueueEmpty callback = OnQueueEmpty;
671
672 int start = Environment.TickCount & Int32.MaxValue;
673 757
674 if (callback != null) 758 if (callback != null)
675 { 759 {
760 // if (m_udpServer.IsRunningOutbound)
761 // {
676 try { callback(categories); } 762 try { callback(categories); }
677 catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); } 763 catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); }
764 // }
678 } 765 }
679 766
680 m_nextOnQueueEmpty = start + MIN_CALLBACK_MS; 767 m_isQueueEmptyRunning = false;
681 if (m_nextOnQueueEmpty == 0)
682 m_nextOnQueueEmpty = 1;
683 } 768 }
769
684 internal void ForceThrottleSetting(int throttle, int setting) 770 internal void ForceThrottleSetting(int throttle, int setting)
685 { 771 {
686 m_throttleCategories[throttle].RequestedDripRate = Math.Max(setting, LLUDPServer.MTU); ; 772 if (throttle > 0 && throttle < THROTTLE_CATEGORY_COUNT)
773 m_throttleCategories[throttle].RequestedDripRate = Math.Max(setting, LLUDPServer.MTU);
774 }
775
776 internal int GetThrottleSetting(int throttle)
777 {
778 if (throttle > 0 && throttle < THROTTLE_CATEGORY_COUNT)
779 return (int)m_throttleCategories[throttle].RequestedDripRate;
780 else
781 return 0;
687 } 782 }
688 783
689 /// <summary> 784 /// <summary>
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
index 4154ef2..f66534d 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -34,6 +34,7 @@ using System.Net.Sockets;
34using System.Reflection; 34using System.Reflection;
35using System.Threading; 35using System.Threading;
36using log4net; 36using log4net;
37using NDesk.Options;
37using Nini.Config; 38using Nini.Config;
38using OpenMetaverse.Packets; 39using OpenMetaverse.Packets;
39using OpenSim.Framework; 40using OpenSim.Framework;
@@ -62,20 +63,41 @@ namespace OpenSim.Region.ClientStack.LindenUDP
62 m_udpServer = new LLUDPServer(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager); 63 m_udpServer = new LLUDPServer(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager);
63 } 64 }
64 65
65 public void NetworkStop()
66 {
67 m_udpServer.Stop();
68 }
69
70 public void AddScene(IScene scene) 66 public void AddScene(IScene scene)
71 { 67 {
72 m_udpServer.AddScene(scene); 68 m_udpServer.AddScene(scene);
73 69
74 StatsManager.RegisterStat( 70 StatsManager.RegisterStat(
75 new Stat( 71 new Stat(
72 "ClientLogoutsDueToNoReceives",
73 "Number of times a client has been logged out because no packets were received before the timeout.",
74 "",
75 "",
76 "clientstack",
77 scene.Name,
78 StatType.Pull,
79 MeasuresOfInterest.None,
80 stat => stat.Value = m_udpServer.ClientLogoutsDueToNoReceives,
81 StatVerbosity.Debug));
82
83 StatsManager.RegisterStat(
84 new Stat(
85 "IncomingUDPReceivesCount",
86 "Number of UDP receives performed",
87 "",
88 "",
89 "clientstack",
90 scene.Name,
91 StatType.Pull,
92 MeasuresOfInterest.AverageChangeOverTime,
93 stat => stat.Value = m_udpServer.UdpReceives,
94 StatVerbosity.Debug));
95
96 StatsManager.RegisterStat(
97 new Stat(
76 "IncomingPacketsProcessedCount", 98 "IncomingPacketsProcessedCount",
77 "Number of inbound UDP packets processed", 99 "Number of inbound LL protocol packets processed",
78 "Number of inbound UDP packets processed", 100 "",
79 "", 101 "",
80 "clientstack", 102 "clientstack",
81 scene.Name, 103 scene.Name,
@@ -83,6 +105,86 @@ namespace OpenSim.Region.ClientStack.LindenUDP
83 MeasuresOfInterest.AverageChangeOverTime, 105 MeasuresOfInterest.AverageChangeOverTime,
84 stat => stat.Value = m_udpServer.IncomingPacketsProcessed, 106 stat => stat.Value = m_udpServer.IncomingPacketsProcessed,
85 StatVerbosity.Debug)); 107 StatVerbosity.Debug));
108
109 StatsManager.RegisterStat(
110 new Stat(
111 "IncomingPacketsMalformedCount",
112 "Number of inbound UDP packets that could not be recognized as LL protocol packets.",
113 "",
114 "",
115 "clientstack",
116 scene.Name,
117 StatType.Pull,
118 MeasuresOfInterest.AverageChangeOverTime,
119 stat => stat.Value = m_udpServer.IncomingMalformedPacketCount,
120 StatVerbosity.Info));
121
122 StatsManager.RegisterStat(
123 new Stat(
124 "IncomingPacketsOrphanedCount",
125 "Number of inbound packets that were not initial connections packets and could not be associated with a viewer.",
126 "",
127 "",
128 "clientstack",
129 scene.Name,
130 StatType.Pull,
131 MeasuresOfInterest.AverageChangeOverTime,
132 stat => stat.Value = m_udpServer.IncomingOrphanedPacketCount,
133 StatVerbosity.Info));
134
135 StatsManager.RegisterStat(
136 new Stat(
137 "IncomingPacketsResentCount",
138 "Number of inbound packets that clients indicate are resends.",
139 "",
140 "",
141 "clientstack",
142 scene.Name,
143 StatType.Pull,
144 MeasuresOfInterest.AverageChangeOverTime,
145 stat => stat.Value = m_udpServer.IncomingPacketsResentCount,
146 StatVerbosity.Debug));
147
148 StatsManager.RegisterStat(
149 new Stat(
150 "OutgoingUDPSendsCount",
151 "Number of UDP sends performed",
152 "",
153 "",
154 "clientstack",
155 scene.Name,
156 StatType.Pull,
157 MeasuresOfInterest.AverageChangeOverTime,
158 stat => stat.Value = m_udpServer.UdpSends,
159 StatVerbosity.Debug));
160
161 StatsManager.RegisterStat(
162 new Stat(
163 "OutgoingPacketsResentCount",
164 "Number of packets resent because a client did not acknowledge receipt",
165 "",
166 "",
167 "clientstack",
168 scene.Name,
169 StatType.Pull,
170 MeasuresOfInterest.AverageChangeOverTime,
171 stat => stat.Value = m_udpServer.PacketsResentCount,
172 StatVerbosity.Debug));
173
174 StatsManager.RegisterStat(
175 new Stat(
176 "AverageUDPProcessTime",
177 "Average number of milliseconds taken to process each incoming UDP packet in a sample.",
178 "This is for initial receive processing which is separate from the later client LL packet processing stage.",
179 "ms",
180 "clientstack",
181 scene.Name,
182 StatType.Pull,
183 MeasuresOfInterest.None,
184 stat => stat.Value = m_udpServer.AverageReceiveTicksForLastSamplePeriod / TimeSpan.TicksPerMillisecond,
185// stat =>
186// stat.Value = Math.Round(m_udpServer.AverageReceiveTicksForLastSamplePeriod / TimeSpan.TicksPerMillisecond, 7),
187 StatVerbosity.Debug));
86 } 188 }
87 189
88 public bool HandlesRegion(Location x) 190 public bool HandlesRegion(Location x)
@@ -107,10 +209,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
107 /// </summary> 209 /// </summary>
108 public class LLUDPServer : OpenSimUDPBase 210 public class LLUDPServer : OpenSimUDPBase
109 { 211 {
212 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
213
110 /// <summary>Maximum transmission unit, or UDP packet size, for the LLUDP protocol</summary> 214 /// <summary>Maximum transmission unit, or UDP packet size, for the LLUDP protocol</summary>
111 public const int MTU = 1400; 215 public const int MTU = 1400;
112 216
113 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 217 /// <summary>Number of forced client logouts due to no receipt of packets before timeout.</summary>
218 public int ClientLogoutsDueToNoReceives { get; private set; }
219
220 /// <summary>
221 /// Default packet debug level given to new clients
222 /// </summary>
223 public int DefaultClientPacketDebugLevel { get; set; }
114 224
115 /// <summary>The measured resolution of Environment.TickCount</summary> 225 /// <summary>The measured resolution of Environment.TickCount</summary>
116 public readonly float TickCountResolution; 226 public readonly float TickCountResolution;
@@ -183,7 +293,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP
183 /// <summary>Flag to signal when clients should send pings</summary> 293 /// <summary>Flag to signal when clients should send pings</summary>
184 protected bool m_sendPing; 294 protected bool m_sendPing;
185 295
296 private int m_animationSequenceNumber;
297
298 public int NextAnimationSequenceNumber
299 {
300 get
301 {
302 m_animationSequenceNumber++;
303 if (m_animationSequenceNumber > 2147482624)
304 m_animationSequenceNumber = 1;
305 return m_animationSequenceNumber;
306 }
307 }
308
309
310
186 private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>(); 311 private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>();
312
313 /// <summary>
314 /// Event used to signal when queued packets are available for sending.
315 /// </summary>
316 /// <remarks>
317 /// This allows the outbound loop to only operate when there is data to send rather than continuously polling.
318 /// Some data is sent immediately and not queued. That data would not trigger this event.
319 /// WRONG use. May be usefull in future revision
320 /// </remarks>
321// private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false);
322
187 private Pool<IncomingPacket> m_incomingPacketPool; 323 private Pool<IncomingPacket> m_incomingPacketPool;
188 324
189 /// <summary> 325 /// <summary>
@@ -204,7 +340,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP
204 340
205 public Socket Server { get { return null; } } 341 public Socket Server { get { return null; } }
206 342
207 private int m_malformedCount = 0; // Guard against a spamming attack 343 /// <summary>
344 /// Record how many packets have been resent
345 /// </summary>
346 internal int PacketsResentCount { get; set; }
347
348 /// <summary>
349 /// Record how many packets have been sent
350 /// </summary>
351 internal int PacketsSentCount { get; set; }
352
353 /// <summary>
354 /// Record how many incoming packets are indicated as resends by clients.
355 /// </summary>
356 internal int IncomingPacketsResentCount { get; set; }
357
358 /// <summary>
359 /// Record how many inbound packets could not be recognized as LLUDP packets.
360 /// </summary>
361 public int IncomingMalformedPacketCount { get; private set; }
362
363 /// <summary>
364 /// Record how many inbound packets could not be associated with a simulator circuit.
365 /// </summary>
366 public int IncomingOrphanedPacketCount { get; private set; }
208 367
209 /// <summary> 368 /// <summary>
210 /// Record current outgoing client for monitoring purposes. 369 /// Record current outgoing client for monitoring purposes.
@@ -225,16 +384,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
225 384
226 // Measure the resolution of Environment.TickCount 385 // Measure the resolution of Environment.TickCount
227 TickCountResolution = 0f; 386 TickCountResolution = 0f;
228 for (int i = 0; i < 5; i++) 387 for (int i = 0; i < 10; i++)
229 { 388 {
230 int start = Environment.TickCount; 389 int start = Environment.TickCount;
231 int now = start; 390 int now = start;
232 while (now == start) 391 while (now == start)
233 now = Environment.TickCount; 392 now = Environment.TickCount;
234 TickCountResolution += (float)(now - start) * 0.2f; 393 TickCountResolution += (float)(now - start) * 0.1f;
235 } 394 }
236 m_log.Info("[LLUDPSERVER]: Average Environment.TickCount resolution: " + TickCountResolution + "ms");
237 TickCountResolution = (float)Math.Ceiling(TickCountResolution); 395 TickCountResolution = (float)Math.Ceiling(TickCountResolution);
396 m_log.Info("[LLUDPSERVER]: Average Environment.TickCount resolution: " + TickCountResolution + "ms");
238 397
239 #endregion Environment.TickCount Measurement 398 #endregion Environment.TickCount Measurement
240 399
@@ -242,6 +401,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
242 int sceneThrottleBps = 0; 401 int sceneThrottleBps = 0;
243 bool usePools = false; 402 bool usePools = false;
244 403
404
405
245 IConfig config = configSource.Configs["ClientStack.LindenUDP"]; 406 IConfig config = configSource.Configs["ClientStack.LindenUDP"];
246 if (config != null) 407 if (config != null)
247 { 408 {
@@ -288,9 +449,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
288 } 449 }
289 #endregion BinaryStats 450 #endregion BinaryStats
290 451
291 m_throttle = new TokenBucket(null, sceneThrottleBps); 452 m_throttle = new TokenBucket(null, sceneThrottleBps, sceneThrottleBps * 10e-3f);
292 ThrottleRates = new ThrottleRates(configSource); 453 ThrottleRates = new ThrottleRates(configSource);
293 454
455 Random rnd = new Random(Util.EnvironmentTickCount());
456 m_animationSequenceNumber = rnd.Next(11474826);
457
294 if (usePools) 458 if (usePools)
295 EnablePools(); 459 EnablePools();
296 } 460 }
@@ -461,6 +625,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
461 m_scene = (Scene)scene; 625 m_scene = (Scene)scene;
462 m_location = new Location(m_scene.RegionInfo.RegionHandle); 626 m_location = new Location(m_scene.RegionInfo.RegionHandle);
463 627
628 StatsManager.RegisterStat(
629 new Stat(
630 "InboxPacketsCount",
631 "Number of LL protocol packets waiting for the second stage of processing after initial receive.",
632 "Number of LL protocol packets waiting for the second stage of processing after initial receive.",
633 "",
634 "clientstack",
635 scene.Name,
636 StatType.Pull,
637 MeasuresOfInterest.AverageChangeOverTime,
638 stat => stat.Value = packetInbox.Count,
639 StatVerbosity.Debug));
640
464 // XXX: These stats are also pool stats but we register them separately since they are currently not 641 // XXX: These stats are also pool stats but we register them separately since they are currently not
465 // turned on and off by EnablePools()/DisablePools() 642 // turned on and off by EnablePools()/DisablePools()
466 StatsManager.RegisterStat( 643 StatsManager.RegisterStat(
@@ -521,6 +698,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
521 EnablePoolStats(); 698 EnablePoolStats();
522 699
523 MainConsole.Instance.Commands.AddCommand( 700 MainConsole.Instance.Commands.AddCommand(
701 "Debug", false, "debug lludp packet",
702 "debug lludp packet [--default] <level> [<avatar-first-name> <avatar-last-name>]",
703 "Turn on packet debugging",
704 "If level > 255 then all incoming and outgoing packets are logged.\n"
705 + "If level <= 255 then incoming AgentUpdate and outgoing SimStats and SimulatorViewerTimeMessage packets are not logged.\n"
706 + "If level <= 200 then incoming RequestImage and outgoing ImagePacket, ImageData, LayerData and CoarseLocationUpdate packets are not logged.\n"
707 + "If level <= 100 then incoming ViewerEffect and AgentAnimation and outgoing ViewerEffect and AvatarAnimation packets are not logged.\n"
708 + "If level <= 50 then outgoing ImprovedTerseObjectUpdate packets are not logged.\n"
709 + "If level <= 0 then no packets are logged.\n"
710 + "If --default is specified then the level becomes the default logging level for all subsequent agents.\n"
711 + "In this case, you cannot also specify an avatar name.\n"
712 + "If an avatar name is given then only packets from that avatar are logged.",
713 HandlePacketCommand);
714
715 MainConsole.Instance.Commands.AddCommand(
524 "Debug", 716 "Debug",
525 false, 717 false,
526 "debug lludp start", 718 "debug lludp start",
@@ -559,10 +751,79 @@ namespace OpenSim.Region.ClientStack.LindenUDP
559 "debug lludp status", 751 "debug lludp status",
560 "Return status of LLUDP packet processing.", 752 "Return status of LLUDP packet processing.",
561 HandleStatusCommand); 753 HandleStatusCommand);
754/* disabled
755 MainConsole.Instance.Commands.AddCommand(
756 "Debug",
757 false,
758 "debug lludp toggle agentupdate",
759 "debug lludp toggle agentupdate",
760 "Toggle whether agentupdate packets are processed or simply discarded.",
761 HandleAgentUpdateCommand);
762 */
763 }
764
765 private void HandlePacketCommand(string module, string[] args)
766 {
767 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
768 return;
769
770 bool setAsDefaultLevel = false;
771 OptionSet optionSet = new OptionSet().Add("default", o => setAsDefaultLevel = o != null);
772 List<string> filteredArgs = optionSet.Parse(args);
773
774 string name = null;
775
776 if (filteredArgs.Count == 6)
777 {
778 if (!setAsDefaultLevel)
779 {
780 name = string.Format("{0} {1}", filteredArgs[4], filteredArgs[5]);
781 }
782 else
783 {
784 MainConsole.Instance.OutputFormat("ERROR: Cannot specify a user name when setting default logging level");
785 return;
786 }
787 }
788
789 if (filteredArgs.Count > 3)
790 {
791 int newDebug;
792 if (int.TryParse(filteredArgs[3], out newDebug))
793 {
794 if (setAsDefaultLevel)
795 {
796 DefaultClientPacketDebugLevel = newDebug;
797 MainConsole.Instance.OutputFormat(
798 "Debug packet debug for new clients set to {0} in {1}", DefaultClientPacketDebugLevel, m_scene.Name);
799 }
800 else
801 {
802 m_scene.ForEachScenePresence(sp =>
803 {
804 if (name == null || sp.Name == name)
805 {
806 MainConsole.Instance.OutputFormat(
807 "Packet debug for {0} ({1}) set to {2} in {3}",
808 sp.Name, sp.IsChildAgent ? "child" : "root", newDebug, m_scene.Name);
809
810 sp.ControllingClient.DebugPacketLevel = newDebug;
811 }
812 });
813 }
814 }
815 else
816 {
817 MainConsole.Instance.Output("Usage: debug lludp packet [--default] 0..255 [<first-name> <last-name>]");
818 }
819 }
562 } 820 }
563 821
564 private void HandleStartCommand(string module, string[] args) 822 private void HandleStartCommand(string module, string[] args)
565 { 823 {
824 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
825 return;
826
566 if (args.Length != 4) 827 if (args.Length != 4)
567 { 828 {
568 MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>"); 829 MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>");
@@ -580,6 +841,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
580 841
581 private void HandleStopCommand(string module, string[] args) 842 private void HandleStopCommand(string module, string[] args)
582 { 843 {
844 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
845 return;
846
583 if (args.Length != 4) 847 if (args.Length != 4)
584 { 848 {
585 MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>"); 849 MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>");
@@ -597,6 +861,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
597 861
598 private void HandlePoolCommand(string module, string[] args) 862 private void HandlePoolCommand(string module, string[] args)
599 { 863 {
864 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
865 return;
866
600 if (args.Length != 4) 867 if (args.Length != 4)
601 { 868 {
602 MainConsole.Instance.Output("Usage: debug lludp pool <on|off>"); 869 MainConsole.Instance.Output("Usage: debug lludp pool <on|off>");
@@ -627,8 +894,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP
627 } 894 }
628 } 895 }
629 896
897 bool m_discardAgentUpdates;
898
899 private void HandleAgentUpdateCommand(string module, string[] args)
900 {
901 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
902 return;
903
904 m_discardAgentUpdates = !m_discardAgentUpdates;
905
906 MainConsole.Instance.OutputFormat(
907 "Discard AgentUpdates now {0} for {1}", m_discardAgentUpdates, m_scene.Name);
908 }
909
630 private void HandleStatusCommand(string module, string[] args) 910 private void HandleStatusCommand(string module, string[] args)
631 { 911 {
912 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
913 return;
914
632 MainConsole.Instance.OutputFormat( 915 MainConsole.Instance.OutputFormat(
633 "IN LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningInbound ? "enabled" : "disabled"); 916 "IN LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningInbound ? "enabled" : "disabled");
634 917
@@ -636,6 +919,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
636 "OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled"); 919 "OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled");
637 920
638 MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_scene.Name, UsePools ? "on" : "off"); 921 MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_scene.Name, UsePools ? "on" : "off");
922
923 MainConsole.Instance.OutputFormat(
924 "Packet debug level for new clients is {0}", DefaultClientPacketDebugLevel);
639 } 925 }
640 926
641 public bool HandlesRegion(Location x) 927 public bool HandlesRegion(Location x)
@@ -643,44 +929,44 @@ namespace OpenSim.Region.ClientStack.LindenUDP
643 return x == m_location; 929 return x == m_location;
644 } 930 }
645 931
646 public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting) 932// public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting)
647 { 933// {
648 // CoarseLocationUpdate and AvatarGroupsReply packets cannot be split in an automated way 934// // CoarseLocationUpdate and AvatarGroupsReply packets cannot be split in an automated way
649 if ((packet.Type == PacketType.CoarseLocationUpdate || packet.Type == PacketType.AvatarGroupsReply) && allowSplitting) 935// if ((packet.Type == PacketType.CoarseLocationUpdate || packet.Type == PacketType.AvatarGroupsReply) && allowSplitting)
650 allowSplitting = false; 936// allowSplitting = false;
651 937//
652 if (allowSplitting && packet.HasVariableBlocks) 938// if (allowSplitting && packet.HasVariableBlocks)
653 { 939// {
654 byte[][] datas = packet.ToBytesMultiple(); 940// byte[][] datas = packet.ToBytesMultiple();
655 int packetCount = datas.Length; 941// int packetCount = datas.Length;
656 942//
657 if (packetCount < 1) 943// if (packetCount < 1)
658 m_log.Error("[LLUDPSERVER]: Failed to split " + packet.Type + " with estimated length " + packet.Length); 944// m_log.Error("[LLUDPSERVER]: Failed to split " + packet.Type + " with estimated length " + packet.Length);
659 945//
660 for (int i = 0; i < packetCount; i++) 946// for (int i = 0; i < packetCount; i++)
661 { 947// {
662 byte[] data = datas[i]; 948// byte[] data = datas[i];
663 m_scene.ForEachClient( 949// m_scene.ForEachClient(
664 delegate(IClientAPI client) 950// delegate(IClientAPI client)
665 { 951// {
666 if (client is LLClientView) 952// if (client is LLClientView)
667 SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null); 953// SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null);
668 } 954// }
669 ); 955// );
670 } 956// }
671 } 957// }
672 else 958// else
673 { 959// {
674 byte[] data = packet.ToBytes(); 960// byte[] data = packet.ToBytes();
675 m_scene.ForEachClient( 961// m_scene.ForEachClient(
676 delegate(IClientAPI client) 962// delegate(IClientAPI client)
677 { 963// {
678 if (client is LLClientView) 964// if (client is LLClientView)
679 SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null); 965// SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null);
680 } 966// }
681 ); 967// );
682 } 968// }
683 } 969// }
684 970
685 /// <summary> 971 /// <summary>
686 /// Start the process of sending a packet to the client. 972 /// Start the process of sending a packet to the client.
@@ -700,6 +986,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
700 if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting) 986 if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting)
701 allowSplitting = false; 987 allowSplitting = false;
702 988
989 bool packetQueued = false;
990
703 if (allowSplitting && packet.HasVariableBlocks) 991 if (allowSplitting && packet.HasVariableBlocks)
704 { 992 {
705 byte[][] datas = packet.ToBytesMultiple(); 993 byte[][] datas = packet.ToBytesMultiple();
@@ -711,16 +999,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
711 for (int i = 0; i < packetCount; i++) 999 for (int i = 0; i < packetCount; i++)
712 { 1000 {
713 byte[] data = datas[i]; 1001 byte[] data = datas[i];
714 SendPacketData(udpClient, data, packet.Type, category, method); 1002
1003 if (!SendPacketData(udpClient, data, packet.Type, category, method))
1004 packetQueued = true;
715 } 1005 }
716 } 1006 }
717 else 1007 else
718 { 1008 {
719 byte[] data = packet.ToBytes(); 1009 byte[] data = packet.ToBytes();
720 SendPacketData(udpClient, data, packet.Type, category, method); 1010 packetQueued = SendPacketData(udpClient, data, packet.Type, category, method);
721 } 1011 }
722 1012
723 PacketPool.Instance.ReturnPacket(packet); 1013 PacketPool.Instance.ReturnPacket(packet);
1014
1015 /// WRONG use. May be usefull in future revision
1016// if (packetQueued)
1017// m_dataPresentEvent.Set();
724 } 1018 }
725 1019
726 /// <summary> 1020 /// <summary>
@@ -734,7 +1028,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
734 /// The method to call if the packet is not acked by the client. If null, then a standard 1028 /// The method to call if the packet is not acked by the client. If null, then a standard
735 /// resend of the packet is done. 1029 /// resend of the packet is done.
736 /// </param> 1030 /// </param>
737 public void SendPacketData( 1031 /// <returns>true if the data was sent immediately, false if it was queued for sending</returns>
1032 public bool SendPacketData(
738 LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category, UnackedPacketMethod method) 1033 LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category, UnackedPacketMethod method)
739 { 1034 {
740 int dataLength = data.Length; 1035 int dataLength = data.Length;
@@ -807,7 +1102,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
807 // packet so that it isn't sent before a queued update packet. 1102 // packet so that it isn't sent before a queued update packet.
808 bool requestQueue = type == PacketType.KillObject; 1103 bool requestQueue = type == PacketType.KillObject;
809 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue, highPriority)) 1104 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue, highPriority))
1105 {
810 SendPacketFinal(outgoingPacket); 1106 SendPacketFinal(outgoingPacket);
1107 return true;
1108 }
1109
1110 return false;
811 1111
812 #endregion Queue or Send 1112 #endregion Queue or Send
813 } 1113 }
@@ -848,6 +1148,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
848 pc.PingID.OldestUnacked = 0; 1148 pc.PingID.OldestUnacked = 0;
849 1149
850 SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false, null); 1150 SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false, null);
1151 udpClient.m_lastStartpingTimeMS = Util.EnvironmentTickCount();
851 } 1152 }
852 1153
853 public void CompletePing(LLUDPClient udpClient, byte pingID) 1154 public void CompletePing(LLUDPClient udpClient, byte pingID)
@@ -883,7 +1184,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
883 // Fire this out on a different thread so that we don't hold up outgoing packet processing for 1184 // Fire this out on a different thread so that we don't hold up outgoing packet processing for
884 // everybody else if this is being called due to an ack timeout. 1185 // everybody else if this is being called due to an ack timeout.
885 // This is the same as processing as the async process of a logout request. 1186 // This is the same as processing as the async process of a logout request.
886 Util.FireAndForget(o => DeactivateClientDueToTimeout(client)); 1187 Util.FireAndForget(o => DeactivateClientDueToTimeout(client, timeoutTicks));
887 1188
888 return; 1189 return;
889 } 1190 }
@@ -944,7 +1245,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
944 int dataLength = buffer.DataLength; 1245 int dataLength = buffer.DataLength;
945 1246
946 // NOTE: I'm seeing problems with some viewers when ACKs are appended to zerocoded packets so I've disabled that here 1247 // NOTE: I'm seeing problems with some viewers when ACKs are appended to zerocoded packets so I've disabled that here
947 if (!isZerocoded) 1248 if (!isZerocoded && !isResend && outgoingPacket.UnackedMethod == null)
948 { 1249 {
949 // Keep appending ACKs until there is no room left in the buffer or there are 1250 // Keep appending ACKs until there is no room left in the buffer or there are
950 // no more ACKs to append 1251 // no more ACKs to append
@@ -988,6 +1289,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
988 else 1289 else
989 { 1290 {
990 Interlocked.Increment(ref udpClient.PacketsResent); 1291 Interlocked.Increment(ref udpClient.PacketsResent);
1292
1293 // We're not going to worry about interlock yet since its not currently critical that this total count
1294 // is 100% correct
1295 PacketsResentCount++;
991 } 1296 }
992 1297
993 #endregion Sequence Number Assignment 1298 #endregion Sequence Number Assignment
@@ -995,6 +1300,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
995 // Stats tracking 1300 // Stats tracking
996 Interlocked.Increment(ref udpClient.PacketsSent); 1301 Interlocked.Increment(ref udpClient.PacketsSent);
997 1302
1303 // We're not going to worry about interlock yet since its not currently critical that this total count
1304 // is 100% correct
1305 PacketsSentCount++;
1306
998 // Put the UDP payload on the wire 1307 // Put the UDP payload on the wire
999 AsyncBeginSend(buffer); 1308 AsyncBeginSend(buffer);
1000 1309
@@ -1002,6 +1311,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1002 outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue; 1311 outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue;
1003 } 1312 }
1004 1313
1314 private void RecordMalformedInboundPacket(IPEndPoint endPoint)
1315 {
1316// if (m_malformedCount < 100)
1317// m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString());
1318
1319 IncomingMalformedPacketCount++;
1320
1321 if ((IncomingMalformedPacketCount % 10000) == 0)
1322 m_log.WarnFormat(
1323 "[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack. Last was from {1}",
1324 IncomingMalformedPacketCount, endPoint);
1325 }
1326
1005 public override void PacketReceived(UDPPacketBuffer buffer) 1327 public override void PacketReceived(UDPPacketBuffer buffer)
1006 { 1328 {
1007 // Debugging/Profiling 1329 // Debugging/Profiling
@@ -1023,6 +1345,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1023// "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}", 1345// "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}",
1024// buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); 1346// buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
1025 1347
1348 RecordMalformedInboundPacket(endPoint);
1349
1026 return; // Drop undersized packet 1350 return; // Drop undersized packet
1027 } 1351 }
1028 1352
@@ -1041,6 +1365,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1041// "[LLUDPSERVER]: Dropping packet with malformed header received from {0} in {1}", 1365// "[LLUDPSERVER]: Dropping packet with malformed header received from {0} in {1}",
1042// buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); 1366// buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
1043 1367
1368 RecordMalformedInboundPacket(endPoint);
1369
1044 return; // Malformed header 1370 return; // Malformed header
1045 } 1371 }
1046 1372
@@ -1056,34 +1382,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1056 // Only allocate a buffer for zerodecoding if the packet is zerocoded 1382 // Only allocate a buffer for zerodecoding if the packet is zerocoded
1057 ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null); 1383 ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
1058 } 1384 }
1059 catch (MalformedDataException)
1060 {
1061 }
1062 catch (IndexOutOfRangeException)
1063 {
1064// m_log.WarnFormat(
1065// "[LLUDPSERVER]: Dropping short packet received from {0} in {1}",
1066// buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
1067
1068 return; // Drop short packet
1069 }
1070 catch (Exception e) 1385 catch (Exception e)
1071 { 1386 {
1072 if (m_malformedCount < 100) 1387 if (IncomingMalformedPacketCount < 100)
1073 m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString()); 1388 m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString());
1074
1075 m_malformedCount++;
1076
1077 if ((m_malformedCount % 100000) == 0)
1078 m_log.DebugFormat("[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack.", m_malformedCount);
1079 } 1389 }
1080 1390
1081 // Fail-safe check 1391 // Fail-safe check
1082 if (packet == null) 1392 if (packet == null)
1083 { 1393 {
1084 m_log.ErrorFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}:", 1394 if (IncomingMalformedPacketCount < 100)
1085 buffer.DataLength, buffer.RemoteEndPoint); 1395 {
1086 m_log.Error(Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)); 1396 m_log.WarnFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}, data {2}:",
1397 buffer.DataLength, buffer.RemoteEndPoint, Utils.BytesToHexString(buffer.Data, buffer.DataLength, null));
1398 }
1399
1400 RecordMalformedInboundPacket(endPoint);
1401
1087 return; 1402 return;
1088 } 1403 }
1089 1404
@@ -1127,12 +1442,36 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1127 queue.Enqueue(buffer); 1442 queue.Enqueue(buffer);
1128 return; 1443 return;
1129 } 1444 }
1445
1446/*
1447 else if (packet.Type == PacketType.CompleteAgentMovement)
1448 {
1449 // Send ack straight away to let the viewer know that we got it.
1450 SendAckImmediate(endPoint, packet.Header.Sequence);
1451
1452 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the
1453 // buffer.
1454 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
1455
1456 Util.FireAndForget(HandleCompleteMovementIntoRegion, array);
1457
1458 return;
1459 }
1460 */
1130 } 1461 }
1131 1462
1132 // Determine which agent this packet came from 1463 // Determine which agent this packet came from
1133 if (client == null || !(client is LLClientView)) 1464 if (client == null || !(client is LLClientView))
1134 { 1465 {
1135 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); 1466 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName);
1467
1468 IncomingOrphanedPacketCount++;
1469
1470 if ((IncomingOrphanedPacketCount % 10000) == 0)
1471 m_log.WarnFormat(
1472 "[LLUDPSERVER]: Received {0} orphaned packets so far. Last was from {1}",
1473 IncomingOrphanedPacketCount, endPoint);
1474
1136 return; 1475 return;
1137 } 1476 }
1138 1477
@@ -1211,6 +1550,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1211 1550
1212 #region Incoming Packet Accounting 1551 #region Incoming Packet Accounting
1213 1552
1553 // We're not going to worry about interlock yet since its not currently critical that this total count
1554 // is 100% correct
1555 if (packet.Header.Resent)
1556 IncomingPacketsResentCount++;
1557
1214 // Check the archive of received reliable packet IDs to see whether we already received this packet 1558 // Check the archive of received reliable packet IDs to see whether we already received this packet
1215 if (packet.Header.Reliable && !udpClient.PacketArchive.TryEnqueue(packet.Header.Sequence)) 1559 if (packet.Header.Reliable && !udpClient.PacketArchive.TryEnqueue(packet.Header.Sequence))
1216 { 1560 {
@@ -1233,6 +1577,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1233 LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length); 1577 LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length);
1234 #endregion BinaryStats 1578 #endregion BinaryStats
1235 1579
1580// AgentUpdate mess removed from here
1581
1236 #region Ping Check Handling 1582 #region Ping Check Handling
1237 1583
1238 if (packet.Type == PacketType.StartPingCheck) 1584 if (packet.Type == PacketType.StartPingCheck)
@@ -1242,7 +1588,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1242 // We don't need to do anything else with ping checks 1588 // We don't need to do anything else with ping checks
1243 StartPingCheckPacket startPing = (StartPingCheckPacket)packet; 1589 StartPingCheckPacket startPing = (StartPingCheckPacket)packet;
1244 CompletePing(udpClient, startPing.PingID.PingID); 1590 CompletePing(udpClient, startPing.PingID.PingID);
1245 1591
1246 if ((Environment.TickCount - m_elapsedMSSinceLastStatReport) >= 3000) 1592 if ((Environment.TickCount - m_elapsedMSSinceLastStatReport) >= 3000)
1247 { 1593 {
1248 udpClient.SendPacketStats(); 1594 udpClient.SendPacketStats();
@@ -1252,7 +1598,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1252 } 1598 }
1253 else if (packet.Type == PacketType.CompletePingCheck) 1599 else if (packet.Type == PacketType.CompletePingCheck)
1254 { 1600 {
1255 // We don't currently track client ping times 1601 int t = Util.EnvironmentTickCountSubtract(udpClient.m_lastStartpingTimeMS);
1602 int c = udpClient.m_pingMS;
1603 c = 800 * c + 200 * t;
1604 c /= 1000;
1605 udpClient.m_pingMS = c;
1256 return; 1606 return;
1257 } 1607 }
1258 1608
@@ -1272,11 +1622,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1272 incomingPacket = new IncomingPacket((LLClientView)client, packet); 1622 incomingPacket = new IncomingPacket((LLClientView)client, packet);
1273 } 1623 }
1274 1624
1275 if (incomingPacket.Packet.Type == PacketType.AgentUpdate || 1625// if (incomingPacket.Packet.Type == PacketType.AgentUpdate ||
1276 incomingPacket.Packet.Type == PacketType.ChatFromViewer) 1626// incomingPacket.Packet.Type == PacketType.ChatFromViewer)
1627 if (incomingPacket.Packet.Type == PacketType.ChatFromViewer)
1277 packetInbox.EnqueueHigh(incomingPacket); 1628 packetInbox.EnqueueHigh(incomingPacket);
1278 else 1629 else
1279 packetInbox.EnqueueLow(incomingPacket); 1630 packetInbox.EnqueueLow(incomingPacket);
1631
1280 } 1632 }
1281 1633
1282 #region BinaryStats 1634 #region BinaryStats
@@ -1393,7 +1745,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1393 1745
1394 try 1746 try
1395 { 1747 {
1396 // DateTime startTime = DateTime.Now; 1748// DateTime startTime = DateTime.Now;
1397 object[] array = (object[])o; 1749 object[] array = (object[])o;
1398 endPoint = (IPEndPoint)array[0]; 1750 endPoint = (IPEndPoint)array[0];
1399 UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1]; 1751 UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1];
@@ -1413,20 +1765,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1413 uccp.CircuitCode.SessionID, 1765 uccp.CircuitCode.SessionID,
1414 endPoint, 1766 endPoint,
1415 sessionInfo); 1767 sessionInfo);
1416
1417 // Send ack straight away to let the viewer know that the connection is active.
1418 // The client will be null if it already exists (e.g. if on a region crossing the client sends a use
1419 // circuit code to the existing child agent. This is not particularly obvious.
1420 SendAckImmediate(endPoint, uccp.Header.Sequence);
1421
1422 // We only want to send initial data to new clients, not ones which are being converted from child to root.
1423 if (client != null)
1424 client.SceneAgent.SendInitialDataToMe();
1425 1768
1426 // Now we know we can handle more data 1769 // Now we know we can handle more data
1427 Thread.Sleep(200); 1770 Thread.Sleep(200);
1428 1771
1429 // Obtain the queue and remove it from the cache 1772 // Obtain the pending queue and remove it from the cache
1430 Queue<UDPPacketBuffer> queue = null; 1773 Queue<UDPPacketBuffer> queue = null;
1431 1774
1432 lock (m_pendingCache) 1775 lock (m_pendingCache)
@@ -1435,6 +1778,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1435 { 1778 {
1436 m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present"); 1779 m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present");
1437 return; 1780 return;
1781
1438 } 1782 }
1439 m_pendingCache.Remove(endPoint); 1783 m_pendingCache.Remove(endPoint);
1440 } 1784 }
@@ -1442,12 +1786,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1442 m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count); 1786 m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count);
1443 1787
1444 // Reinject queued packets 1788 // Reinject queued packets
1445 while(queue.Count > 0) 1789 while (queue.Count > 0)
1446 { 1790 {
1447 UDPPacketBuffer buf = queue.Dequeue(); 1791 UDPPacketBuffer buf = queue.Dequeue();
1448 PacketReceived(buf); 1792 PacketReceived(buf);
1449 } 1793 }
1794
1450 queue = null; 1795 queue = null;
1796
1797 // Send ack straight away to let the viewer know that the connection is active.
1798 // The client will be null if it already exists (e.g. if on a region crossing the client sends a use
1799 // circuit code to the existing child agent. This is not particularly obvious.
1800 SendAckImmediate(endPoint, uccp.Header.Sequence);
1801
1802 // We only want to send initial data to new clients, not ones which are being converted from child to root.
1803 if (client != null)
1804 {
1805 AgentCircuitData aCircuit = m_scene.AuthenticateHandler.GetAgentCircuitData(uccp.CircuitCode.Code);
1806 bool tp = (aCircuit.teleportFlags > 0);
1807 // Let's delay this for TP agents, otherwise the viewer doesn't know where to get resources from
1808 if (!tp)
1809 client.SceneAgent.SendInitialDataToMe();
1810 }
1451 } 1811 }
1452 else 1812 else
1453 { 1813 {
@@ -1455,10 +1815,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1455 m_log.WarnFormat( 1815 m_log.WarnFormat(
1456 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", 1816 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}",
1457 uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint); 1817 uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint);
1818
1458 lock (m_pendingCache) 1819 lock (m_pendingCache)
1459 m_pendingCache.Remove(endPoint); 1820 m_pendingCache.Remove(endPoint);
1460 } 1821 }
1461
1462 // m_log.DebugFormat( 1822 // m_log.DebugFormat(
1463 // "[LLUDPSERVER]: Handling UseCircuitCode request from {0} took {1}ms", 1823 // "[LLUDPSERVER]: Handling UseCircuitCode request from {0} took {1}ms",
1464 // buffer.RemoteEndPoint, (DateTime.Now - startTime).Milliseconds); 1824 // buffer.RemoteEndPoint, (DateTime.Now - startTime).Milliseconds);
@@ -1475,6 +1835,117 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1475 e.StackTrace); 1835 e.StackTrace);
1476 } 1836 }
1477 } 1837 }
1838/*
1839 private void HandleCompleteMovementIntoRegion(object o)
1840 {
1841 IPEndPoint endPoint = null;
1842 IClientAPI client = null;
1843
1844 try
1845 {
1846 object[] array = (object[])o;
1847 endPoint = (IPEndPoint)array[0];
1848 CompleteAgentMovementPacket packet = (CompleteAgentMovementPacket)array[1];
1849
1850 m_log.DebugFormat(
1851 "[LLUDPSERVER]: Handling CompleteAgentMovement request from {0} in {1}", endPoint, m_scene.Name);
1852
1853 // Determine which agent this packet came from
1854 // We need to wait here because in when using the OpenSimulator V2 teleport protocol to travel to a destination
1855 // simulator with no existing child presence, the viewer (at least LL 3.3.4) will send UseCircuitCode
1856 // and then CompleteAgentMovement immediately without waiting for an ack. As we are now handling these
1857 // packets asynchronously, we need to account for this thread proceeding more quickly than the
1858 // UseCircuitCode thread.
1859 int count = 40;
1860 while (count-- > 0)
1861 {
1862 if (m_scene.TryGetClient(endPoint, out client))
1863 {
1864 if (!client.IsActive)
1865 {
1866 // This check exists to catch a condition where the client has been closed by another thread
1867 // but has not yet been removed from the client manager (and possibly a new connection has
1868 // not yet been established).
1869 m_log.DebugFormat(
1870 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client is not active yet. Waiting.",
1871 endPoint, client.Name, m_scene.Name);
1872 }
1873 else if (client.SceneAgent == null)
1874 {
1875 // This check exists to catch a condition where the new client has been added to the client
1876 // manager but the SceneAgent has not yet been set in Scene.AddNewAgent(). If we are too
1877 // eager, then the new ScenePresence may not have registered a listener for this messsage
1878 // before we try to process it.
1879 // XXX: A better long term fix may be to add the SceneAgent before the client is added to
1880 // the client manager
1881 m_log.DebugFormat(
1882 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client SceneAgent not set yet. Waiting.",
1883 endPoint, client.Name, m_scene.Name);
1884 }
1885 else
1886 {
1887 break;
1888 }
1889 }
1890 else
1891 {
1892 m_log.DebugFormat(
1893 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} in {1} but no client exists yet. Waiting.",
1894 endPoint, m_scene.Name);
1895 }
1896
1897 Thread.Sleep(200);
1898 }
1899
1900 if (client == null)
1901 {
1902 m_log.DebugFormat(
1903 "[LLUDPSERVER]: No client found for CompleteAgentMovement from {0} in {1} after wait. Dropping.",
1904 endPoint, m_scene.Name);
1905
1906 return;
1907 }
1908 else if (!client.IsActive || client.SceneAgent == null)
1909 {
1910 // This check exists to catch a condition where the client has been closed by another thread
1911 // but has not yet been removed from the client manager.
1912 // The packet could be simply ignored but it is useful to know if this condition occurred for other debugging
1913 // purposes.
1914 m_log.DebugFormat(
1915 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client is not active after wait. Dropping.",
1916 endPoint, client.Name, m_scene.Name);
1917
1918 return;
1919 }
1920
1921 IncomingPacket incomingPacket1;
1922
1923 // Inbox insertion
1924 if (UsePools)
1925 {
1926 incomingPacket1 = m_incomingPacketPool.GetObject();
1927 incomingPacket1.Client = (LLClientView)client;
1928 incomingPacket1.Packet = packet;
1929 }
1930 else
1931 {
1932 incomingPacket1 = new IncomingPacket((LLClientView)client, packet);
1933 }
1934
1935 packetInbox.Enqueue(incomingPacket1);
1936 }
1937 catch (Exception e)
1938 {
1939 m_log.ErrorFormat(
1940 "[LLUDPSERVER]: CompleteAgentMovement handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}",
1941 endPoint != null ? endPoint.ToString() : "n/a",
1942 client != null ? client.Name : "unknown",
1943 client != null ? client.AgentId.ToString() : "unknown",
1944 e.Message,
1945 e.StackTrace);
1946 }
1947 }
1948*/
1478 1949
1479 /// <summary> 1950 /// <summary>
1480 /// Send an ack immediately to the given endpoint. 1951 /// Send an ack immediately to the given endpoint.
@@ -1532,6 +2003,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1532 uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo) 2003 uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo)
1533 { 2004 {
1534 IClientAPI client = null; 2005 IClientAPI client = null;
2006 bool createNew = false;
1535 2007
1536 // We currently synchronize this code across the whole scene to avoid issues such as 2008 // We currently synchronize this code across the whole scene to avoid issues such as
1537 // http://opensimulator.org/mantis/view.php?id=5365 However, once locking per agent circuit can be done 2009 // http://opensimulator.org/mantis/view.php?id=5365 However, once locking per agent circuit can be done
@@ -1540,10 +2012,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1540 { 2012 {
1541 if (!m_scene.TryGetClient(agentID, out client)) 2013 if (!m_scene.TryGetClient(agentID, out client))
1542 { 2014 {
2015 createNew = true;
2016 }
2017 else
2018 {
2019 if (client.SceneAgent == null)
2020 {
2021 m_scene.CloseAgent(agentID, true);
2022 createNew = true;
2023 }
2024 }
2025
2026 if (createNew)
2027 {
1543 LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, m_throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO); 2028 LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, m_throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO);
1544 2029
1545 client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); 2030 client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
1546 client.OnLogout += LogoutHandler; 2031 client.OnLogout += LogoutHandler;
2032 client.DebugPacketLevel = DefaultClientPacketDebugLevel;
1547 2033
1548 ((LLClientView)client).DisableFacelights = m_disableFacelights; 2034 ((LLClientView)client).DisableFacelights = m_disableFacelights;
1549 2035
@@ -1562,21 +2048,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1562 /// regular client pings. 2048 /// regular client pings.
1563 /// </remarks> 2049 /// </remarks>
1564 /// <param name='client'></param> 2050 /// <param name='client'></param>
1565 private void DeactivateClientDueToTimeout(LLClientView client) 2051 /// <param name='timeoutTicks'></param>
2052 private void DeactivateClientDueToTimeout(LLClientView client, int timeoutTicks)
1566 { 2053 {
1567 lock (client.CloseSyncLock) 2054 lock (client.CloseSyncLock)
1568 { 2055 {
1569 m_log.WarnFormat( 2056 ClientLogoutsDueToNoReceives++;
1570 "[LLUDPSERVER]: Ack timeout, disconnecting {0} agent for {1} in {2}", 2057
1571 client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, m_scene.RegionInfo.RegionName); 2058 if (client.SceneAgent != null)
1572 2059 {
1573 StatsManager.SimExtraStats.AddAbnormalClientThreadTermination(); 2060 m_log.WarnFormat(
1574 2061 "[LLUDPSERVER]: No packets received from {0} agent of {1} for {2}ms in {3}. Disconnecting.",
1575 if (!client.SceneAgent.IsChildAgent) 2062 client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, timeoutTicks, m_scene.Name);
1576 client.Kick("Simulator logged you out due to connection timeout");
1577 2063
1578 client.CloseWithoutChecks(true); 2064 if (!client.SceneAgent.IsChildAgent)
2065 client.Kick("Simulator logged you out due to connection timeout.");
2066 }
1579 } 2067 }
2068
2069 if (!m_scene.CloseAgent(client.AgentId, true))
2070 client.Close(true,true);
1580 } 2071 }
1581 2072
1582 private void IncomingPacketHandler() 2073 private void IncomingPacketHandler()
@@ -1592,6 +2083,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1592 { 2083 {
1593 IncomingPacket incomingPacket = null; 2084 IncomingPacket incomingPacket = null;
1594 2085
2086 /*
1595 // HACK: This is a test to try and rate limit packet handling on Mono. 2087 // HACK: This is a test to try and rate limit packet handling on Mono.
1596 // If it works, a more elegant solution can be devised 2088 // If it works, a more elegant solution can be devised
1597 if (Util.FireAndForgetCount() < 2) 2089 if (Util.FireAndForgetCount() < 2)
@@ -1599,6 +2091,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1599 //m_log.Debug("[LLUDPSERVER]: Incoming packet handler is sleeping"); 2091 //m_log.Debug("[LLUDPSERVER]: Incoming packet handler is sleeping");
1600 Thread.Sleep(30); 2092 Thread.Sleep(30);
1601 } 2093 }
2094 */
1602 2095
1603 if (packetInbox.Dequeue(100, ref incomingPacket)) 2096 if (packetInbox.Dequeue(100, ref incomingPacket))
1604 { 2097 {
@@ -1608,7 +2101,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1608 m_incomingPacketPool.ReturnObject(incomingPacket); 2101 m_incomingPacketPool.ReturnObject(incomingPacket);
1609 } 2102 }
1610 } 2103 }
1611 catch (Exception ex) 2104 catch(Exception ex)
1612 { 2105 {
1613 m_log.Error("[LLUDPSERVER]: Error in the incoming packet handler loop: " + ex.Message, ex); 2106 m_log.Error("[LLUDPSERVER]: Error in the incoming packet handler loop: " + ex.Message, ex);
1614 } 2107 }
@@ -1694,9 +2187,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1694 2187
1695 // If nothing was sent, sleep for the minimum amount of time before a 2188 // If nothing was sent, sleep for the minimum amount of time before a
1696 // token bucket could get more tokens 2189 // token bucket could get more tokens
2190
1697 if (!m_packetSent) 2191 if (!m_packetSent)
1698 Thread.Sleep((int)TickCountResolution); 2192 Thread.Sleep((int)TickCountResolution);
1699 2193
2194 // .... wrong core code removed
2195
2196
1700 Watchdog.UpdateThread(); 2197 Watchdog.UpdateThread();
1701 } 2198 }
1702 catch (Exception ex) 2199 catch (Exception ex)
@@ -1912,7 +2409,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1912 if (!client.IsLoggingOut) 2409 if (!client.IsLoggingOut)
1913 { 2410 {
1914 client.IsLoggingOut = true; 2411 client.IsLoggingOut = true;
1915 client.Close(false, false); 2412 m_scene.CloseAgent(client.AgentId, false);
1916 } 2413 }
1917 } 2414 }
1918 } 2415 }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
index 7035e38..0030dee 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
@@ -78,6 +78,36 @@ namespace OpenMetaverse
78 public bool IsRunningOutbound { get; private set; } 78 public bool IsRunningOutbound { get; private set; }
79 79
80 /// <summary> 80 /// <summary>
81 /// Number of UDP receives.
82 /// </summary>
83 public int UdpReceives { get; private set; }
84
85 /// <summary>
86 /// Number of UDP sends
87 /// </summary>
88 public int UdpSends { get; private set; }
89
90 /// <summary>
91 /// Number of receives over which to establish a receive time average.
92 /// </summary>
93 private readonly static int s_receiveTimeSamples = 500;
94
95 /// <summary>
96 /// Current number of samples taken to establish a receive time average.
97 /// </summary>
98 private int m_currentReceiveTimeSamples;
99
100 /// <summary>
101 /// Cumulative receive time for the sample so far.
102 /// </summary>
103 private int m_receiveTicksInCurrentSamplePeriod;
104
105 /// <summary>
106 /// The average time taken for each require receive in the last sample.
107 /// </summary>
108 public float AverageReceiveTicksForLastSamplePeriod { get; private set; }
109
110 /// <summary>
81 /// Default constructor 111 /// Default constructor
82 /// </summary> 112 /// </summary>
83 /// <param name="bindAddress">Local IP address to bind the server to</param> 113 /// <param name="bindAddress">Local IP address to bind the server to</param>
@@ -111,6 +141,8 @@ namespace OpenMetaverse
111 141
112 if (!IsRunningInbound) 142 if (!IsRunningInbound)
113 { 143 {
144 m_log.DebugFormat("[UDPBASE]: Starting inbound UDP loop");
145
114 const int SIO_UDP_CONNRESET = -1744830452; 146 const int SIO_UDP_CONNRESET = -1744830452;
115 147
116 IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort); 148 IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort);
@@ -120,6 +152,10 @@ namespace OpenMetaverse
120 SocketType.Dgram, 152 SocketType.Dgram,
121 ProtocolType.Udp); 153 ProtocolType.Udp);
122 154
155 // OpenSim may need this but in AVN, this messes up automated
156 // sim restarts badly
157 //m_udpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false);
158
123 try 159 try
124 { 160 {
125 // This udp socket flag is not supported under mono, 161 // This udp socket flag is not supported under mono,
@@ -151,6 +187,8 @@ namespace OpenMetaverse
151 /// </summary> 187 /// </summary>
152 public void StartOutbound() 188 public void StartOutbound()
153 { 189 {
190 m_log.DebugFormat("[UDPBASE]: Starting outbound UDP loop");
191
154 IsRunningOutbound = true; 192 IsRunningOutbound = true;
155 } 193 }
156 194
@@ -158,10 +196,8 @@ namespace OpenMetaverse
158 { 196 {
159 if (IsRunningInbound) 197 if (IsRunningInbound)
160 { 198 {
161 // wait indefinitely for a writer lock. Once this is called, the .NET runtime 199 m_log.DebugFormat("[UDPBASE]: Stopping inbound UDP loop");
162 // will deny any more reader locks, in effect blocking all other send/receive 200
163 // threads. Once we have the lock, we set IsRunningInbound = false to inform the other
164 // threads that the socket is closed.
165 IsRunningInbound = false; 201 IsRunningInbound = false;
166 m_udpSocket.Close(); 202 m_udpSocket.Close();
167 } 203 }
@@ -169,6 +205,8 @@ namespace OpenMetaverse
169 205
170 public void StopOutbound() 206 public void StopOutbound()
171 { 207 {
208 m_log.DebugFormat("[UDPBASE]: Stopping outbound UDP loop");
209
172 IsRunningOutbound = false; 210 IsRunningOutbound = false;
173 } 211 }
174 212
@@ -257,7 +295,16 @@ namespace OpenMetaverse
257 m_log.Warn("[UDPBASE]: Salvaged the UDP listener on port " + m_udpPort); 295 m_log.Warn("[UDPBASE]: Salvaged the UDP listener on port " + m_udpPort);
258 } 296 }
259 } 297 }
260 catch (ObjectDisposedException) { } 298 catch (ObjectDisposedException e)
299 {
300 m_log.Error(
301 string.Format("[UDPBASE]: Error processing UDP begin receive {0}. Exception ", UdpReceives), e);
302 }
303 catch (Exception e)
304 {
305 m_log.Error(
306 string.Format("[UDPBASE]: Error processing UDP begin receive {0}. Exception ", UdpReceives), e);
307 }
261 } 308 }
262 } 309 }
263 310
@@ -267,17 +314,21 @@ namespace OpenMetaverse
267 // to AsyncBeginReceive 314 // to AsyncBeginReceive
268 if (IsRunningInbound) 315 if (IsRunningInbound)
269 { 316 {
317 UdpReceives++;
318
270 // Asynchronous mode will start another receive before the 319 // Asynchronous mode will start another receive before the
271 // callback for this packet is even fired. Very parallel :-) 320 // callback for this packet is even fired. Very parallel :-)
272 if (m_asyncPacketHandling) 321 if (m_asyncPacketHandling)
273 AsyncBeginReceive(); 322 AsyncBeginReceive();
274 323
275 // get the buffer that was created in AsyncBeginReceive
276 // this is the received data
277 UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState;
278
279 try 324 try
280 { 325 {
326 // get the buffer that was created in AsyncBeginReceive
327 // this is the received data
328 UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState;
329
330 int startTick = Util.EnvironmentTickCount();
331
281 // get the length of data actually read from the socket, store it with the 332 // get the length of data actually read from the socket, store it with the
282 // buffer 333 // buffer
283 buffer.DataLength = m_udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint); 334 buffer.DataLength = m_udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint);
@@ -285,9 +336,42 @@ namespace OpenMetaverse
285 // call the abstract method PacketReceived(), passing the buffer that 336 // call the abstract method PacketReceived(), passing the buffer that
286 // has just been filled from the socket read. 337 // has just been filled from the socket read.
287 PacketReceived(buffer); 338 PacketReceived(buffer);
339
340 // If more than one thread can be calling AsyncEndReceive() at once (e.g. if m_asyncPacketHandler)
341 // then a particular stat may be inaccurate due to a race condition. We won't worry about this
342 // since this should be rare and won't cause a runtime problem.
343 if (m_currentReceiveTimeSamples >= s_receiveTimeSamples)
344 {
345 AverageReceiveTicksForLastSamplePeriod
346 = (float)m_receiveTicksInCurrentSamplePeriod / s_receiveTimeSamples;
347
348 m_receiveTicksInCurrentSamplePeriod = 0;
349 m_currentReceiveTimeSamples = 0;
350 }
351 else
352 {
353 m_receiveTicksInCurrentSamplePeriod += Util.EnvironmentTickCountSubtract(startTick);
354 m_currentReceiveTimeSamples++;
355 }
356 }
357 catch (SocketException se)
358 {
359 m_log.Error(
360 string.Format(
361 "[UDPBASE]: Error processing UDP end receive {0}, socket error code {1}. Exception ",
362 UdpReceives, se.ErrorCode),
363 se);
364 }
365 catch (ObjectDisposedException e)
366 {
367 m_log.Error(
368 string.Format("[UDPBASE]: Error processing UDP end receive {0}. Exception ", UdpReceives), e);
369 }
370 catch (Exception e)
371 {
372 m_log.Error(
373 string.Format("[UDPBASE]: Error processing UDP end receive {0}. Exception ", UdpReceives), e);
288 } 374 }
289 catch (SocketException) { }
290 catch (ObjectDisposedException) { }
291 finally 375 finally
292 { 376 {
293// if (UsePools) 377// if (UsePools)
@@ -298,14 +382,13 @@ namespace OpenMetaverse
298 if (!m_asyncPacketHandling) 382 if (!m_asyncPacketHandling)
299 AsyncBeginReceive(); 383 AsyncBeginReceive();
300 } 384 }
301
302 } 385 }
303 } 386 }
304 387
305 public void AsyncBeginSend(UDPPacketBuffer buf) 388 public void AsyncBeginSend(UDPPacketBuffer buf)
306 { 389 {
307 if (IsRunningOutbound) 390// if (IsRunningOutbound)
308 { 391// {
309 try 392 try
310 { 393 {
311 m_udpSocket.BeginSendTo( 394 m_udpSocket.BeginSendTo(
@@ -319,7 +402,7 @@ namespace OpenMetaverse
319 } 402 }
320 catch (SocketException) { } 403 catch (SocketException) { }
321 catch (ObjectDisposedException) { } 404 catch (ObjectDisposedException) { }
322 } 405// }
323 } 406 }
324 407
325 void AsyncEndSend(IAsyncResult result) 408 void AsyncEndSend(IAsyncResult result)
@@ -328,9 +411,11 @@ namespace OpenMetaverse
328 { 411 {
329// UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState; 412// UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState;
330 m_udpSocket.EndSendTo(result); 413 m_udpSocket.EndSendTo(result);
414
415 UdpSends++;
331 } 416 }
332 catch (SocketException) { } 417 catch (SocketException) { }
333 catch (ObjectDisposedException) { } 418 catch (ObjectDisposedException) { }
334 } 419 }
335 } 420 }
336} \ No newline at end of file 421}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
index 1fdc410..5a2bcee 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
@@ -145,39 +145,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
145 return packet; 145 return packet;
146 } 146 }
147 147
148 // private byte[] decoded_header = new byte[10];
149 private static PacketType GetType(byte[] bytes) 148 private static PacketType GetType(byte[] bytes)
150 { 149 {
151 byte[] decoded_header = new byte[10 + 8];
152 ushort id; 150 ushort id;
153 PacketFrequency freq; 151 PacketFrequency freq;
152 bool isZeroCoded = (bytes[0] & Helpers.MSG_ZEROCODED) != 0;
154 153
155 if ((bytes[0] & Helpers.MSG_ZEROCODED) != 0) 154 if (bytes[6] == 0xFF)
156 { 155 {
157 Helpers.ZeroDecode(bytes, 16, decoded_header); 156 if (bytes[7] == 0xFF)
158 }
159 else
160 {
161 Buffer.BlockCopy(bytes, 0, decoded_header, 0, 10);
162 }
163
164 if (decoded_header[6] == 0xFF)
165 {
166 if (decoded_header[7] == 0xFF)
167 { 157 {
168 id = (ushort) ((decoded_header[8] << 8) + decoded_header[9]);
169 freq = PacketFrequency.Low; 158 freq = PacketFrequency.Low;
159 if (isZeroCoded && bytes[8] == 0)
160 id = bytes[10];
161 else
162 id = (ushort)((bytes[8] << 8) + bytes[9]);
170 } 163 }
171 else 164 else
172 { 165 {
173 id = decoded_header[7];
174 freq = PacketFrequency.Medium; 166 freq = PacketFrequency.Medium;
167 id = bytes[7];
175 } 168 }
176 } 169 }
177 else 170 else
178 { 171 {
179 id = decoded_header[6];
180 freq = PacketFrequency.High; 172 freq = PacketFrequency.High;
173 id = bytes[6];
181 } 174 }
182 175
183 return Packet.GetType(id, freq); 176 return Packet.GetType(id, freq);
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs b/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs
index 98ef72f..f8d0c02 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.6.*")] 32[assembly: AssemblyVersion("0.8.0.*")]
33 33
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs
index 556df30..9700224 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs
@@ -33,6 +33,7 @@ using NUnit.Framework;
33using OpenMetaverse; 33using OpenMetaverse;
34using OpenMetaverse.Packets; 34using OpenMetaverse.Packets;
35using OpenSim.Framework; 35using OpenSim.Framework;
36using OpenSim.Framework.Monitoring;
36using OpenSim.Region.Framework.Scenes; 37using OpenSim.Region.Framework.Scenes;
37using OpenSim.Tests.Common; 38using OpenSim.Tests.Common;
38using OpenSim.Tests.Common.Mock; 39using OpenSim.Tests.Common.Mock;
@@ -69,6 +70,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
69 { 70 {
70 base.SetUp(); 71 base.SetUp();
71 m_scene = new SceneHelpers().SetupScene(); 72 m_scene = new SceneHelpers().SetupScene();
73 StatsManager.SimExtraStats = new SimExtraStatsCollector();
72 } 74 }
73 75
74 /// <summary> 76 /// <summary>
@@ -198,7 +200,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
198 public void TestLogoutClientDueToAck() 200 public void TestLogoutClientDueToAck()
199 { 201 {
200 TestHelpers.InMethod(); 202 TestHelpers.InMethod();
201// TestHelpers.EnableLogging(); 203 TestHelpers.EnableLogging();
202 204
203 IniConfigSource ics = new IniConfigSource(); 205 IniConfigSource ics = new IniConfigSource();
204 IConfig config = ics.AddConfig("ClientStack.LindenUDP"); 206 IConfig config = ics.AddConfig("ClientStack.LindenUDP");
@@ -210,8 +212,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
210 212
211 ScenePresence spAfterAckTimeout = m_scene.GetScenePresence(sp.UUID); 213 ScenePresence spAfterAckTimeout = m_scene.GetScenePresence(sp.UUID);
212 Assert.That(spAfterAckTimeout, Is.Null); 214 Assert.That(spAfterAckTimeout, Is.Null);
213
214// TestHelpers.DisableLogging();
215 } 215 }
216 216
217// /// <summary> 217// /// <summary>
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs
index 7d9f581..575e54c 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs
@@ -29,6 +29,7 @@ using System;
29using System.IO; 29using System.IO;
30using System.Net; 30using System.Net;
31using System.Reflection; 31using System.Reflection;
32using System.Threading;
32using log4net.Config; 33using log4net.Config;
33using Nini.Config; 34using Nini.Config;
34using NUnit.Framework; 35using NUnit.Framework;
@@ -53,6 +54,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
53 [TestFixtureSetUp] 54 [TestFixtureSetUp]
54 public void FixtureInit() 55 public void FixtureInit()
55 { 56 {
57 // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
58 Util.FireAndForgetMethod = FireAndForgetMethod.None;
59
56 using ( 60 using (
57 Stream resource 61 Stream resource
58 = GetType().Assembly.GetManifestResourceStream( 62 = GetType().Assembly.GetManifestResourceStream(
@@ -72,9 +76,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
72 } 76 }
73 } 77 }
74 78
79 [TestFixtureTearDown]
80 public void TearDown()
81 {
82 // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
83 // threads. Possibly, later tests should be rewritten not to worry about such things.
84 Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
85 }
86
75 [SetUp] 87 [SetUp]
76 public void SetUp() 88 public override void SetUp()
77 { 89 {
90 base.SetUp();
91
78 UUID userId = TestHelpers.ParseTail(0x3); 92 UUID userId = TestHelpers.ParseTail(0x3);
79 93
80 J2KDecoderModule j2kdm = new J2KDecoderModule(); 94 J2KDecoderModule j2kdm = new J2KDecoderModule();
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs
index 119a677..e2178e5 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs
@@ -52,17 +52,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
52 public override void Update(int frames) {} 52 public override void Update(int frames) {}
53 public override void LoadWorldMap() {} 53 public override void LoadWorldMap() {}
54 54
55 public override ISceneAgent AddNewClient(IClientAPI client, PresenceType type) 55 public override ISceneAgent AddNewAgent(IClientAPI client, PresenceType type)
56 { 56 {
57 client.OnObjectName += RecordObjectNameCall; 57 client.OnObjectName += RecordObjectNameCall;
58 58
59 // FIXME 59 // FIXME
60 return null; 60 return null;
61 } 61 }
62 62
63 public override void RemoveClient(UUID agentID, bool someReason) {} 63 public override bool CloseAgent(UUID agentID, bool force) { return true; }
64// public override void CloseAllAgents(uint circuitcode) {} 64
65 public override bool CheckClient(UUID clientId, IPEndPoint endPoint) { return true; } 65 public override bool CheckClient(UUID clientId, IPEndPoint endPoint) { return true; }
66
66 public override void OtherRegionUp(GridRegion otherRegion) { } 67 public override void OtherRegionUp(GridRegion otherRegion) { }
67 68
68 public override bool TryGetScenePresence(UUID uuid, out ScenePresence sp) { sp = null; return false; } 69 public override bool TryGetScenePresence(UUID uuid, out ScenePresence sp) { sp = null; return false; }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs
index c9aac0b..451dee5 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs
@@ -59,6 +59,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
59 /// <summary>Flag used to enable adaptive throttles</summary> 59 /// <summary>Flag used to enable adaptive throttles</summary>
60 public bool AdaptiveThrottlesEnabled; 60 public bool AdaptiveThrottlesEnabled;
61 61
62 /// <summary>Amount of the texture throttle to steal for the task throttle</summary>
63 public double CannibalizeTextureRate;
64
65 public int ClientMaxRate;
66 public float BrustTime;
67
62 /// <summary> 68 /// <summary>
63 /// Default constructor 69 /// Default constructor
64 /// </summary> 70 /// </summary>
@@ -77,9 +83,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
77 Texture = throttleConfig.GetInt("texture_default", 18500); 83 Texture = throttleConfig.GetInt("texture_default", 18500);
78 Asset = throttleConfig.GetInt("asset_default", 10500); 84 Asset = throttleConfig.GetInt("asset_default", 10500);
79 85
80 Total = throttleConfig.GetInt("client_throttle_max_bps", 0); 86 Total = Resend + Land + Wind + Cloud + Task + Texture + Asset;
87 // 3000000 bps default max
88 ClientMaxRate = throttleConfig.GetInt("client_throttle_max_bps", 375000);
89 if (ClientMaxRate > 1000000)
90 ClientMaxRate = 1000000; // no more than 8Mbps
91
92 BrustTime = (float)throttleConfig.GetInt("client_throttle_burtsTimeMS", 10);
93 BrustTime *= 1e-3f;
81 94
82 AdaptiveThrottlesEnabled = throttleConfig.GetBoolean("enable_adaptive_throttles", false); 95 AdaptiveThrottlesEnabled = throttleConfig.GetBoolean("enable_adaptive_throttles", false);
96
97 CannibalizeTextureRate = (double)throttleConfig.GetFloat("CannibalizeTextureRate", 0.0f);
98 CannibalizeTextureRate = Util.Clamp<double>(CannibalizeTextureRate,0.0, 0.9);
83 } 99 }
84 catch (Exception) { } 100 catch (Exception) { }
85 } 101 }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs
index 4c33db5..1877cf0 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs
@@ -44,23 +44,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
44 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 44 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
45 private static Int32 m_counter = 0; 45 private static Int32 m_counter = 0;
46 46
47// private Int32 m_identifier; 47// private Int32 m_identifier;
48 48
49 /// <summary> 49 protected const float m_timeScale = 1e-3f;
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 50
55 /// <summary> 51 /// <summary>
56 /// This is the number of quantums worth of packets that can 52 /// This is the number of m_minimumDripRate bytes
57 /// be accommodated during a burst 53 /// allowed in a burst
54 /// roughtly, with this settings, the maximum time system will take
55 /// to recheck a bucket in ms
56 ///
58 /// </summary> 57 /// </summary>
59 protected const Double m_quantumsPerBurst = 1.5; 58 protected const float m_quantumsPerBurst = 5;
60 59
61 /// <summary> 60 /// <summary>
62 /// </summary> 61 /// </summary>
63 protected const Int32 m_minimumDripRate = 1400; 62 protected const float m_minimumDripRate = 1400;
64 63
65 /// <summary>Time of the last drip, in system ticks</summary> 64 /// <summary>Time of the last drip, in system ticks</summary>
66 protected Int32 m_lastDrip; 65 protected Int32 m_lastDrip;
@@ -69,12 +68,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
69 /// The number of bytes that can be sent at this moment. This is the 68 /// The number of bytes that can be sent at this moment. This is the
70 /// current number of tokens in the bucket 69 /// current number of tokens in the bucket
71 /// </summary> 70 /// </summary>
72 protected Int64 m_tokenCount; 71 protected float m_tokenCount;
73 72
74 /// <summary> 73 /// <summary>
75 /// Map of children buckets and their requested maximum burst rate 74 /// Map of children buckets and their requested maximum burst rate
76 /// </summary> 75 /// </summary>
77 protected Dictionary<TokenBucket,Int64> m_children = new Dictionary<TokenBucket,Int64>(); 76 protected Dictionary<TokenBucket, float> m_children = new Dictionary<TokenBucket, float>();
78 77
79#region Properties 78#region Properties
80 79
@@ -91,25 +90,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
91 } 90 }
92 91
93 /// <summary> 92 /// <summary>
94 /// Maximum burst rate in bytes per second. This is the maximum number 93 /// This is the maximum number
95 /// of tokens that can accumulate in the bucket at any one time. This 94 /// of tokens that can accumulate in the bucket at any one time. This
96 /// also sets the total request for leaf nodes 95 /// also sets the total request for leaf nodes
97 /// </summary> 96 /// </summary>
98 protected Int64 m_burstRate; 97 protected float m_burst;
99 public Int64 RequestedBurstRate 98 public float RequestedBurst
100 { 99 {
101 get { return m_burstRate; } 100 get { return m_burst; }
102 set { m_burstRate = (value < 0 ? 0 : value); } 101 set {
102 float rate = (value < 0 ? 0 : value);
103 if (rate < m_minimumDripRate)
104 rate = m_minimumDripRate;
105 else if (rate > m_minimumDripRate * m_quantumsPerBurst)
106 rate = m_minimumDripRate * m_quantumsPerBurst;
107
108 m_burst = rate;
109 }
103 } 110 }
104 111
105 public Int64 BurstRate 112 public float Burst
106 { 113 {
107 get { 114 get {
108 double rate = RequestedBurstRate * BurstRateModifier(); 115 float rate = RequestedBurst * BurstModifier();
109 if (rate < m_minimumDripRate * m_quantumsPerBurst) 116 if (rate < m_minimumDripRate)
110 rate = m_minimumDripRate * m_quantumsPerBurst; 117 rate = m_minimumDripRate;
111 118 return (float)rate;
112 return (Int64) rate;
113 } 119 }
114 } 120 }
115 121
@@ -120,30 +126,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP
120 /// <remarks>Tokens are added to the bucket any time 126 /// <remarks>Tokens are added to the bucket any time
121 /// <seealso cref="RemoveTokens"/> is called, at the granularity of 127 /// <seealso cref="RemoveTokens"/> is called, at the granularity of
122 /// the system tick interval (typically around 15-22ms)</remarks> 128 /// the system tick interval (typically around 15-22ms)</remarks>
123 protected Int64 m_dripRate; 129 protected float m_dripRate;
124 public virtual Int64 RequestedDripRate 130 public virtual float RequestedDripRate
125 { 131 {
126 get { return (m_dripRate == 0 ? m_totalDripRequest : m_dripRate); } 132 get { return (m_dripRate == 0 ? m_totalDripRequest : m_dripRate); }
127 set { 133 set {
128 m_dripRate = (value < 0 ? 0 : value); 134 m_dripRate = (value < 0 ? 0 : value);
129 m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst);
130 m_totalDripRequest = m_dripRate; 135 m_totalDripRequest = m_dripRate;
136
131 if (m_parent != null) 137 if (m_parent != null)
132 m_parent.RegisterRequest(this,m_dripRate); 138 m_parent.RegisterRequest(this,m_dripRate);
133 } 139 }
134 } 140 }
135 141
136 public virtual Int64 DripRate 142 public virtual float DripRate
137 { 143 {
138 get { 144 get {
145 float rate = Math.Min(RequestedDripRate,TotalDripRequest);
139 if (m_parent == null) 146 if (m_parent == null)
140 return Math.Min(RequestedDripRate,TotalDripRequest); 147 return rate;
141 148
142 double rate = (double)RequestedDripRate * m_parent.DripRateModifier(); 149 rate *= m_parent.DripRateModifier();
143 if (rate < m_minimumDripRate) 150 if (rate < m_minimumDripRate)
144 rate = m_minimumDripRate; 151 rate = m_minimumDripRate;
145 152
146 return (Int64)rate; 153 return (float)rate;
147 } 154 }
148 } 155 }
149 156
@@ -151,8 +158,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
151 /// The current total of the requested maximum burst rates of 158 /// The current total of the requested maximum burst rates of
152 /// this bucket's children buckets. 159 /// this bucket's children buckets.
153 /// </summary> 160 /// </summary>
154 protected Int64 m_totalDripRequest; 161 protected float m_totalDripRequest;
155 public Int64 TotalDripRequest 162 public float TotalDripRequest
156 { 163 {
157 get { return m_totalDripRequest; } 164 get { return m_totalDripRequest; }
158 set { m_totalDripRequest = value; } 165 set { m_totalDripRequest = value; }
@@ -171,16 +178,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
171 /// zero if this bucket has no maximum capacity</param> 178 /// zero if this bucket has no maximum capacity</param>
172 /// <param name="dripRate">Rate that the bucket fills, in bytes per 179 /// <param name="dripRate">Rate that the bucket fills, in bytes per
173 /// second. If zero, the bucket always remains full</param> 180 /// second. If zero, the bucket always remains full</param>
174 public TokenBucket(TokenBucket parent, Int64 dripRate) 181 public TokenBucket(TokenBucket parent, float dripRate, float MaxBurst)
175 { 182 {
176// m_identifier = m_counter++; 183// m_identifier = m_counter++;
177 m_counter++; 184 m_counter++;
178 185
179 Parent = parent; 186 Parent = parent;
180 RequestedDripRate = dripRate; 187 RequestedDripRate = dripRate;
188 RequestedBurst = MaxBurst;
181 // TotalDripRequest = dripRate; // this will be overwritten when a child node registers 189 // TotalDripRequest = dripRate; // this will be overwritten when a child node registers
182 // MaxBurst = (Int64)((double)dripRate * m_quantumsPerBurst); 190 // MaxBurst = (Int64)((double)dripRate * m_quantumsPerBurst);
183 m_lastDrip = Util.EnvironmentTickCount(); 191 m_lastDrip = Util.EnvironmentTickCount() + 100000;
184 } 192 }
185 193
186#endregion Constructor 194#endregion Constructor
@@ -192,15 +200,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
192 /// hierarchy. However, if any of the parents is over-booked, then 200 /// hierarchy. However, if any of the parents is over-booked, then
193 /// the modifier will be less than 1. 201 /// the modifier will be less than 1.
194 /// </summary> 202 /// </summary>
195 protected double DripRateModifier() 203 protected float DripRateModifier()
196 { 204 {
197 Int64 driprate = DripRate; 205 float driprate = DripRate;
198 return driprate >= TotalDripRequest ? 1.0 : (double)driprate / (double)TotalDripRequest; 206 return driprate >= TotalDripRequest ? 1.0f : driprate / TotalDripRequest;
199 } 207 }
200 208
201 /// <summary> 209 /// <summary>
202 /// </summary> 210 /// </summary>
203 protected double BurstRateModifier() 211 protected float BurstModifier()
204 { 212 {
205 // for now... burst rate is always m_quantumsPerBurst (constant) 213 // for now... burst rate is always m_quantumsPerBurst (constant)
206 // larger than drip rate so the ratio of burst requests is the 214 // larger than drip rate so the ratio of burst requests is the
@@ -212,7 +220,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
212 /// Register drip rate requested by a child of this throttle. Pass the 220 /// Register drip rate requested by a child of this throttle. Pass the
213 /// changes up the hierarchy. 221 /// changes up the hierarchy.
214 /// </summary> 222 /// </summary>
215 public void RegisterRequest(TokenBucket child, Int64 request) 223 public void RegisterRequest(TokenBucket child, float request)
216 { 224 {
217 lock (m_children) 225 lock (m_children)
218 { 226 {
@@ -220,7 +228,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
220 // m_totalDripRequest = m_children.Values.Sum(); 228 // m_totalDripRequest = m_children.Values.Sum();
221 229
222 m_totalDripRequest = 0; 230 m_totalDripRequest = 0;
223 foreach (KeyValuePair<TokenBucket, Int64> cref in m_children) 231 foreach (KeyValuePair<TokenBucket, float> cref in m_children)
224 m_totalDripRequest += cref.Value; 232 m_totalDripRequest += cref.Value;
225 } 233 }
226 234
@@ -241,7 +249,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
241 // m_totalDripRequest = m_children.Values.Sum(); 249 // m_totalDripRequest = m_children.Values.Sum();
242 250
243 m_totalDripRequest = 0; 251 m_totalDripRequest = 0;
244 foreach (KeyValuePair<TokenBucket, Int64> cref in m_children) 252 foreach (KeyValuePair<TokenBucket, float> cref in m_children)
245 m_totalDripRequest += cref.Value; 253 m_totalDripRequest += cref.Value;
246 } 254 }
247 255
@@ -257,7 +265,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
257 /// <param name="amount">Number of tokens to remove from the bucket</param> 265 /// <param name="amount">Number of tokens to remove from the bucket</param>
258 /// <returns>True if the requested number of tokens were removed from 266 /// <returns>True if the requested number of tokens were removed from
259 /// the bucket, otherwise false</returns> 267 /// the bucket, otherwise false</returns>
260 public bool RemoveTokens(Int64 amount) 268 public bool RemoveTokens(int amount)
261 { 269 {
262 // Deposit tokens for this interval 270 // Deposit tokens for this interval
263 Drip(); 271 Drip();
@@ -274,19 +282,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
274 return false; 282 return false;
275 } 283 }
276 284
277 /// <summary> 285 public int GetCatBytesCanSend(int timeMS)
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 { 286 {
283 m_tokenCount += count; 287// return (int)(m_tokenCount + timeMS * m_dripRate * 1e-3);
284 288 return (int)(timeMS * m_dripRate * 1e-3);
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 } 289 }
291 290
292 /// <summary> 291 /// <summary>
@@ -305,17 +304,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
305 return; 304 return;
306 } 305 }
307 306
308 // Determine the interval over which we are adding tokens, never add 307 Int32 now = Util.EnvironmentTickCount();
309 // more than a single quantum of tokens 308 Int32 deltaMS = now - m_lastDrip;
310 Int32 deltaMS = Math.Min(Util.EnvironmentTickCountSubtract(m_lastDrip), m_ticksPerQuantum); 309 m_lastDrip = now;
311 m_lastDrip = Util.EnvironmentTickCount();
312 310
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) 311 if (deltaMS <= 0)
316 return; 312 return;
317 313
318 Deposit(deltaMS * DripRate / m_ticksPerQuantum); 314 m_tokenCount += deltaMS * DripRate * m_timeScale;
315
316 float burst = Burst;
317 if (m_tokenCount > burst)
318 m_tokenCount = burst;
319 } 319 }
320 } 320 }
321 321
@@ -325,20 +325,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP
325 325
326 /// <summary> 326 /// <summary>
327 /// The minimum rate for flow control. Minimum drip rate is one 327 /// The minimum rate for flow control. Minimum drip rate is one
328 /// packet per second. Open the throttle to 15 packets per second 328 /// packet per second.
329 /// or about 160kbps.
330 /// </summary> 329 /// </summary>
331 protected const Int64 m_minimumFlow = m_minimumDripRate * 15; 330
331 protected const float m_minimumFlow = 50000;
332 332
333 // <summary> 333 // <summary>
334 // The maximum rate for flow control. Drip rate can never be 334 // The maximum rate for flow control. Drip rate can never be
335 // greater than this. 335 // greater than this.
336 // </summary> 336 // </summary>
337 protected Int64 m_maxDripRate = 0; 337
338 protected Int64 MaxDripRate 338 protected float m_maxDripRate = 0;
339 public float MaxDripRate
339 { 340 {
340 get { return (m_maxDripRate == 0 ? m_totalDripRequest : m_maxDripRate); } 341 get { return (m_maxDripRate == 0 ? m_totalDripRequest : m_maxDripRate); }
341 set { m_maxDripRate = (value == 0 ? 0 : Math.Max(value,m_minimumFlow)); } 342 set
343 {
344 m_maxDripRate = (value == 0 ? m_totalDripRequest : Math.Max(value, m_minimumFlow));
345 }
342 } 346 }
343 347
344 private bool m_enabled = false; 348 private bool m_enabled = false;
@@ -346,12 +350,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
346 // <summary> 350 // <summary>
347 // 351 //
348 // </summary> 352 // </summary>
349 public virtual Int64 AdjustedDripRate 353 public virtual float AdjustedDripRate
350 { 354 {
351 get { return m_dripRate; } 355 get { return m_dripRate; }
352 set { 356 set {
353 m_dripRate = OpenSim.Framework.Util.Clamp<Int64>(value,m_minimumFlow,MaxDripRate); 357 m_dripRate = OpenSim.Framework.Util.Clamp<float>(value,m_minimumFlow,MaxDripRate);
354 m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst); 358
355 if (m_parent != null) 359 if (m_parent != null)
356 m_parent.RegisterRequest(this,m_dripRate); 360 m_parent.RegisterRequest(this,m_dripRate);
357 } 361 }
@@ -360,16 +364,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
360 // <summary> 364 // <summary>
361 // 365 //
362 // </summary> 366 // </summary>
363 public AdaptiveTokenBucket(TokenBucket parent, Int64 maxDripRate, bool enabled) : base(parent,maxDripRate) 367 public AdaptiveTokenBucket(TokenBucket parent, float maxDripRate,float maxBurst, bool enabled)
368 : base(parent, maxDripRate,maxBurst)
364 { 369 {
365 m_enabled = enabled; 370 m_enabled = enabled;
371
372 MaxDripRate = maxDripRate;
366 373
367 if (m_enabled) 374 if (enabled)
368 { 375 AdjustedDripRate = m_maxDripRate * .5f;
369 // m_log.DebugFormat("[TOKENBUCKET] Adaptive throttle enabled"); 376 else
370 MaxDripRate = maxDripRate; 377 AdjustedDripRate = m_maxDripRate;
371 AdjustedDripRate = m_minimumFlow;
372 }
373 } 378 }
374 379
375 // <summary> 380 // <summary>