aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ClientStack')
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/AgentPreferencesModule.cs182
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs136
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs2251
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCapsModule.cs91
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs746
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs623
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs465
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs198
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/FetchInventory2Module.cs144
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs456
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs488
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs151
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs389
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs380
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs33
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs242
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs304
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/Tests/WebFetchInvDescModuleTests.cs161
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs145
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs465
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/IncomingPacket.cs63
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/IncomingPacketHistoryCollection.cs73
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs441
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs13979
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs360
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs918
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs2246
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs880
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs535
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/OutgoingPacket.cs75
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs299
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs36
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs273
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs174
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs104
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/Resources/4-tile2.jp2bin0 -> 24410 bytes
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs432
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs141
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs417
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs252
-rw-r--r--OpenSim/Region/ClientStack/Properties/AssemblyInfo.cs33
41 files changed, 29781 insertions, 0 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/AgentPreferencesModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/AgentPreferencesModule.cs
new file mode 100644
index 0000000..8f65a69
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/AgentPreferencesModule.cs
@@ -0,0 +1,182 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.IO;
32using log4net;
33using Mono.Addins;
34using Nini.Config;
35using OpenMetaverse;
36using OpenMetaverse.StructuredData;
37using OpenSim.Framework.Console;
38using OpenSim.Framework.Servers;
39using OpenSim.Framework.Servers.HttpServer;
40using OpenSim.Region.Framework.Interfaces;
41using OpenSim.Region.Framework.Scenes;
42using OpenSim.Services.Interfaces;
43using Caps = OpenSim.Framework.Capabilities.Caps;
44using OpenSim.Capabilities.Handlers;
45
46namespace OpenSim.Region.ClientStack.LindenCaps
47{
48 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AgentPreferencesModule")]
49 public class AgentPreferencesModule : ISharedRegionModule
50 {
51 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
52
53 private List<Scene> m_scenes = new List<Scene>();
54
55 public void Initialise(IConfigSource source)
56 {
57
58 }
59
60 #region Region module
61
62 public void AddRegion(Scene scene)
63 {
64 lock (m_scenes) m_scenes.Add(scene);
65 }
66
67 public void RemoveRegion(Scene scene)
68 {
69 lock (m_scenes) m_scenes.Remove(scene);
70 scene.EventManager.OnRegisterCaps -= RegisterCaps;
71 scene = null;
72 }
73
74 public void RegionLoaded(Scene scene)
75 {
76 scene.EventManager.OnRegisterCaps += delegate(UUID agentID, OpenSim.Framework.Capabilities.Caps caps)
77 {
78 RegisterCaps(agentID, caps);
79 };
80 }
81
82 public void PostInitialise() {}
83
84 public void Close() {}
85
86 public string Name { get { return "AgentPreferencesModule"; } }
87
88 public Type ReplaceableInterface
89 {
90 get { return null; }
91 }
92
93 public void RegisterCaps(UUID agent, Caps caps)
94 {
95 UUID capId = UUID.Random();
96 caps.RegisterHandler("AgentPreferences",
97 new RestStreamHandler("POST", "/CAPS/" + capId,
98 delegate(string request, string path, string param,
99 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
100 {
101 return UpdateAgentPreferences(request, path, param, agent);
102 }));
103 caps.RegisterHandler("UpdateAgentLanguage",
104 new RestStreamHandler("POST", "/CAPS/" + capId,
105 delegate(string request, string path, string param,
106 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
107 {
108 return UpdateAgentPreferences(request, path, param, agent);
109 }));
110 caps.RegisterHandler("UpdateAgentInformation",
111 new RestStreamHandler("POST", "/CAPS/" + capId,
112 delegate(string request, string path, string param,
113 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
114 {
115 return UpdateAgentPreferences(request, path, param, agent);
116 }));
117 }
118
119 public string UpdateAgentPreferences(string request, string path, string param, UUID agent)
120 {
121 OSDMap resp = new OSDMap();
122 // The viewer doesn't do much with the return value, so for now, if there is no preference service,
123 // we'll return a null llsd block for debugging purposes. This may change if someone knows what the
124 // correct server response would be here.
125 if (m_scenes[0].AgentPreferencesService == null)
126 {
127 return OSDParser.SerializeLLSDXmlString(resp);
128 }
129 m_log.DebugFormat("[AgentPrefs]: UpdateAgentPreferences for {0}", agent.ToString());
130 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
131 AgentPrefs data = m_scenes[0].AgentPreferencesService.GetAgentPreferences(agent);
132 if (data == null)
133 {
134 data = new AgentPrefs(agent);
135 }
136
137 if (req.ContainsKey("access_prefs"))
138 {
139 OSDMap accessPrefs = (OSDMap)req["access_prefs"]; // We could check with ContainsKey...
140 data.AccessPrefs = accessPrefs["max"].AsString();
141 }
142 if (req.ContainsKey("default_object_perm_masks"))
143 {
144 OSDMap permsMap = (OSDMap)req["default_object_perm_masks"];
145 data.PermEveryone = permsMap["Everyone"].AsInteger();
146 data.PermGroup = permsMap["Group"].AsInteger();
147 data.PermNextOwner = permsMap["NextOwner"].AsInteger();
148 }
149 if (req.ContainsKey("hover_height"))
150 {
151 data.HoverHeight = req["hover_height"].AsReal();
152 }
153 if (req.ContainsKey("language"))
154 {
155 data.Language = req["language"].AsString();
156 }
157 if (req.ContainsKey("language_is_public"))
158 {
159 data.LanguageIsPublic = req["language_is_public"].AsBoolean();
160 }
161 m_scenes[0].AgentPreferencesService.StoreAgentPreferences(data);
162 OSDMap respAccessPrefs = new OSDMap();
163 respAccessPrefs["max"] = data.AccessPrefs;
164 resp["access_prefs"] = respAccessPrefs;
165 OSDMap respDefaultPerms = new OSDMap();
166 respDefaultPerms["Everyone"] = data.PermEveryone;
167 respDefaultPerms["Group"] = data.PermGroup;
168 respDefaultPerms["NextOwner"] = data.PermNextOwner;
169 resp["default_object_perm_masks"] = respDefaultPerms;
170 resp["god_level"] = 0; // *TODO: Add this
171 resp["hover_height"] = data.HoverHeight;
172 resp["language"] = data.Language;
173 resp["language_is_public"] = data.LanguageIsPublic;
174
175 string response = OSDParser.SerializeLLSDXmlString(resp);
176 return response;
177 }
178
179 #endregion Region module
180 }
181}
182
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs
new file mode 100644
index 0000000..e3c430c
--- /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
new file mode 100644
index 0000000..50b83f6
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
@@ -0,0 +1,2251 @@
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.Timers;
30using System.Collections;
31using System.Collections.Generic;
32using System.Collections.Specialized;
33using System.IO;
34using System.Reflection;
35using System.Text;
36using System.Web;
37
38using OpenMetaverse;
39using OpenMetaverse.StructuredData;
40using Nini.Config;
41using log4net;
42
43using OpenSim.Framework;
44using OpenSim.Framework.Capabilities;
45using OpenSim.Region.Framework;
46using OpenSim.Region.Framework.Interfaces;
47using OpenSim.Region.Framework.Scenes;
48using OpenSim.Region.Framework.Scenes.Serialization;
49using OpenSim.Framework.Servers;
50using OpenSim.Framework.Servers.HttpServer;
51using OpenSim.Services.Interfaces;
52
53using Caps = OpenSim.Framework.Capabilities.Caps;
54using OSDArray = OpenMetaverse.StructuredData.OSDArray;
55using OSDMap = OpenMetaverse.StructuredData.OSDMap;
56using PermissionMask = OpenSim.Framework.PermissionMask;
57
58namespace OpenSim.Region.ClientStack.Linden
59{
60 public delegate void UpLoadedAsset(
61 string assetName, string description, UUID assetID, UUID inventoryItem, UUID parentFolder,
62 byte[] data, string inventoryType, string assetType,
63 int cost, UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances,
64 bool IsAtestUpload, ref string error, ref int nextOwnerMask, ref int groupMask, ref int everyoneMask);
65
66 public delegate UUID UpdateItem(UUID itemID, byte[] data);
67
68 public delegate void UpdateTaskScript(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors);
69
70 public delegate void NewInventoryItem(UUID userID, InventoryItemBase item, uint cost);
71
72 public delegate void NewAsset(AssetBase asset);
73
74 public delegate UUID ItemUpdatedCallback(UUID userID, UUID itemID, byte[] data);
75
76 public delegate ArrayList TaskScriptUpdatedCallback(UUID userID, UUID itemID, UUID primID,
77 bool isScriptRunning, byte[] data);
78
79 public delegate InventoryCollection FetchInventoryDescendentsCAPS(UUID agentID, UUID folderID, UUID ownerID,
80 bool fetchFolders, bool fetchItems, int sortOrder, out int version);
81
82 /// <summary>
83 /// XXX Probably not a particularly nice way of allow us to get the scene presence from the scene (chiefly so that
84 /// we can popup a message on the user's client if the inventory service has permanently failed). But I didn't want
85 /// to just pass the whole Scene into CAPS.
86 /// </summary>
87 public delegate IClientAPI GetClientDelegate(UUID agentID);
88
89 public class BunchOfCaps
90 {
91 private static readonly ILog m_log =
92 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
93
94 private Scene m_Scene;
95 private UUID m_AgentID;
96 private Caps m_HostCapsObj;
97 private ModelCost m_ModelCost;
98
99 // private static readonly string m_remoteParcelRequestPath = "0009/";// This is in the LandManagementModule.
100
101 // These are callbacks which will be setup by the scene so that we can update scene data when we
102 // receive capability calls
103 public NewInventoryItem AddNewInventoryItem = null;
104 public NewAsset AddNewAsset = null;
105 public ItemUpdatedCallback ItemUpdatedCall = null;
106 public TaskScriptUpdatedCallback TaskScriptUpdatedCall = null;
107 public FetchInventoryDescendentsCAPS CAPSFetchInventoryDescendents = null;
108 public GetClientDelegate GetClient = null;
109
110 private bool m_persistBakedTextures = false;
111 private IAssetService m_assetService;
112 private bool m_dumpAssetsToFile = false;
113 private string m_regionName;
114
115 private int m_levelUpload = 0;
116
117 private bool m_enableFreeTestUpload = false; // allows "TEST-" prefix hack
118 private bool m_ForceFreeTestUpload = false; // forces all uploads to be test
119
120 private bool m_enableModelUploadTextureToInventory = false; // place uploaded textures also in inventory
121 // may not be visible till relog
122
123 private bool m_RestrictFreeTestUploadPerms = false; // reduces also the permitions. Needs a creator defined!!
124 private UUID m_testAssetsCreatorID = UUID.Zero;
125
126 private float m_PrimScaleMin = 0.001f;
127
128 private bool m_AllowCapHomeLocation = true;
129 private bool m_AllowCapGroupMemberData = true;
130 private IUserManagement m_UserManager;
131
132
133 private enum FileAgentInventoryState : int
134 {
135 idle = 0,
136 processRequest = 1,
137 waitUpload = 2,
138 processUpload = 3
139 }
140 private FileAgentInventoryState m_FileAgentInventoryState = FileAgentInventoryState.idle;
141
142 public BunchOfCaps(Scene scene, UUID agentID, Caps caps)
143 {
144 m_Scene = scene;
145 m_AgentID = agentID;
146 m_HostCapsObj = caps;
147
148 // create a model upload cost provider
149 m_ModelCost = new ModelCost(scene);
150
151 m_PrimScaleMin = m_ModelCost.PrimScaleMin;
152
153 IConfigSource config = m_Scene.Config;
154 if (config != null)
155 {
156 IConfig sconfig = config.Configs["Startup"];
157 if (sconfig != null)
158 {
159 m_levelUpload = sconfig.GetInt("LevelUpload", 0);
160 }
161
162 IConfig appearanceConfig = config.Configs["Appearance"];
163 if (appearanceConfig != null)
164 {
165 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures);
166 }
167 // economy for model upload
168 IConfig EconomyConfig = config.Configs["Economy"];
169 if (EconomyConfig != null)
170 {
171 m_ModelCost.Econfig(EconomyConfig);
172
173 m_enableModelUploadTextureToInventory = EconomyConfig.GetBoolean("MeshModelAllowTextureToInventory", m_enableModelUploadTextureToInventory);
174
175 m_RestrictFreeTestUploadPerms = EconomyConfig.GetBoolean("m_RestrictFreeTestUploadPerms", m_RestrictFreeTestUploadPerms);
176 m_enableFreeTestUpload = EconomyConfig.GetBoolean("AllowFreeTestUpload", m_enableFreeTestUpload);
177 m_ForceFreeTestUpload = EconomyConfig.GetBoolean("ForceFreeTestUpload", m_ForceFreeTestUpload);
178 string testcreator = EconomyConfig.GetString("TestAssetsCreatorID", "");
179 if (testcreator != "")
180 {
181 UUID id;
182 UUID.TryParse(testcreator, out id);
183 if (id != null)
184 m_testAssetsCreatorID = id;
185 }
186 }
187
188 IConfig CapsConfig = config.Configs["ClientStack.LindenCaps"];
189 if (CapsConfig != null)
190 {
191 string homeLocationUrl = CapsConfig.GetString("Cap_HomeLocation", "localhost");
192 if(homeLocationUrl == String.Empty)
193 m_AllowCapHomeLocation = false;
194
195 string GroupMemberDataUrl = CapsConfig.GetString("Cap_GroupMemberData", "localhost");
196 if(GroupMemberDataUrl == String.Empty)
197 m_AllowCapGroupMemberData = false;
198 }
199 }
200
201 m_assetService = m_Scene.AssetService;
202 m_regionName = m_Scene.RegionInfo.RegionName;
203 m_UserManager = m_Scene.RequestModuleInterface<IUserManagement>();
204 if (m_UserManager == null)
205 m_log.Error("[CAPS]: GetDisplayNames disabled because user management component not found");
206
207 RegisterHandlers();
208
209 AddNewInventoryItem = m_Scene.AddUploadedInventoryItem;
210 ItemUpdatedCall = m_Scene.CapsUpdateInventoryItemAsset;
211 TaskScriptUpdatedCall = m_Scene.CapsUpdateTaskInventoryScriptAsset;
212 GetClient = m_Scene.SceneGraph.GetControllingClient;
213
214 m_FileAgentInventoryState = FileAgentInventoryState.idle;
215 }
216
217 public string GetNewCapPath()
218 {
219 return "/CAPS/" + UUID.Random();
220 }
221
222 /// <summary>
223 /// Register a bunch of CAPS http service handlers
224 /// </summary>
225 public void RegisterHandlers()
226 {
227 // this path is also defined elsewhere so keeping it
228 string seedcapsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath +"0000/";
229
230 // the root of all evil path needs to be capsBase + m_requestPath
231 m_HostCapsObj.RegisterHandler(
232 "SEED", new RestStreamHandler("POST", seedcapsBase, SeedCapRequest, "SEED", null));
233
234// m_log.DebugFormat(
235// "[CAPS]: Registered seed capability {0} for {1}", seedcapsBase, m_HostCapsObj.AgentID);
236
237 RegisterRegionServiceHandlers();
238 RegisterInventoryServiceHandlers();
239 RegisterOtherHandlers();
240 }
241
242 public void RegisterRegionServiceHandlers()
243 {
244 try
245 {
246 //m_capsHandlers["MapLayer"] =
247 // new LLSDStreamhandler<OSDMapRequest, OSDMapLayerResponse>("POST",
248 // GetNewCapPath(),
249 // GetMapLayer);
250
251 IRequestHandler getObjectPhysicsDataHandler = new RestStreamHandler(
252 "POST", GetNewCapPath(), GetObjectPhysicsData, "GetObjectPhysicsData", null);
253 m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler);
254
255 IRequestHandler getObjectCostHandler = new RestStreamHandler(
256 "POST", GetNewCapPath(), GetObjectCost, "GetObjectCost", null );
257 m_HostCapsObj.RegisterHandler("GetObjectCost", getObjectCostHandler);
258
259 IRequestHandler ResourceCostSelectedHandler = new RestStreamHandler(
260 "POST", GetNewCapPath(), ResourceCostSelected, "ResourceCostSelected", null);
261 m_HostCapsObj.RegisterHandler("ResourceCostSelected", ResourceCostSelectedHandler);
262
263 IRequestHandler req = new RestStreamHandler(
264 "POST", GetNewCapPath(), ScriptTaskInventory, "UpdateScript", null);
265 m_HostCapsObj.RegisterHandler("UpdateScriptTaskInventory", req);
266 m_HostCapsObj.RegisterHandler("UpdateScriptTask", req);
267
268 if(m_AllowCapHomeLocation)
269 {
270 IRequestHandler HomeLocationHandler = new RestStreamHandler(
271 "POST", GetNewCapPath(), HomeLocation, "HomeLocation", null);
272 m_HostCapsObj.RegisterHandler("HomeLocation", HomeLocationHandler);
273 }
274
275 if(m_AllowCapGroupMemberData)
276 {
277 IRequestHandler GroupMemberDataHandler = new RestStreamHandler(
278 "POST", GetNewCapPath(), GroupMemberData, "GroupMemberData", null);
279 m_HostCapsObj.RegisterHandler("GroupMemberData", GroupMemberDataHandler);
280 }
281
282
283// IRequestHandler animSetRequestHandler
284// = new RestStreamHandler(
285// "POST", capsBase + m_animSetTaskUpdatePath, AnimSetTaskInventory, "UpdateScript", null);
286
287// m_HostCapsObj.RegisterHandler("UpdateAnimSetTaskInventory", animSetRequestHandler);
288 }
289 catch (Exception e)
290 {
291 m_log.Error("[CAPS]: " + e.ToString());
292 }
293 }
294
295 public void RegisterInventoryServiceHandlers()
296 {
297 try
298 {
299 m_HostCapsObj.RegisterHandler("NewFileAgentInventory",
300 new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDAssetUploadResponse>(
301 "POST", GetNewCapPath(), NewAgentInventoryRequest, "NewFileAgentInventory", null));
302
303 IRequestHandler req = new RestStreamHandler(
304 "POST", GetNewCapPath(), NoteCardAgentInventory, "Update*", null);
305 m_HostCapsObj.RegisterHandler("UpdateNotecardAgentInventory", req);
306 m_HostCapsObj.RegisterHandler("UpdateAnimSetAgentInventory", req);
307 m_HostCapsObj.RegisterHandler("UpdateScriptAgentInventory", req);
308 m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req);
309
310 IRequestHandler UpdateAgentInformationHandler = new RestStreamHandler(
311 "POST", GetNewCapPath(), UpdateAgentInformation, "UpdateAgentInformation", null);
312 m_HostCapsObj.RegisterHandler("UpdateAgentInformation", UpdateAgentInformationHandler);
313
314 IRequestHandler CopyInventoryFromNotecardHandler = new RestStreamHandler(
315 "POST", GetNewCapPath(), CopyInventoryFromNotecard, "CopyInventoryFromNotecard", null);
316 m_HostCapsObj.RegisterHandler("CopyInventoryFromNotecard", CopyInventoryFromNotecardHandler);
317
318 }
319 catch (Exception e)
320 {
321 m_log.Error("[CAPS]: " + e.ToString());
322 }
323 }
324
325 public void RegisterOtherHandlers()
326 {
327 try
328 {
329 if (m_UserManager != null)
330 {
331 IRequestHandler GetDisplayNamesHandler = new RestStreamHandler(
332 "GET", GetNewCapPath(), GetDisplayNames, "GetDisplayNames", null);
333 m_HostCapsObj.RegisterHandler("GetDisplayNames", GetDisplayNamesHandler);
334 }
335 }
336 catch (Exception e)
337 {
338 m_log.Error("[CAPS]: " + e.ToString());
339 }
340 }
341 /// <summary>
342 /// Construct a client response detailing all the capabilities this server can provide.
343 /// </summary>
344 /// <param name="request"></param>
345 /// <param name="path"></param>
346 /// <param name="param"></param>
347 /// <param name="httpRequest">HTTP request header object</param>
348 /// <param name="httpResponse">HTTP response header object</param>
349 /// <returns></returns>
350 public string SeedCapRequest(string request, string path, string param,
351 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
352 {
353 m_log.DebugFormat(
354 "[CAPS]: Received SEED caps request in {0} for agent {1}", m_regionName, m_HostCapsObj.AgentID);
355
356 if (!m_HostCapsObj.WaitForActivation())
357 return string.Empty;
358
359 if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint))
360 {
361 m_log.WarnFormat(
362 "[CAPS]: Unauthorized CAPS client {0} from {1}",
363 m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint);
364
365 return string.Empty;
366 }
367
368 OSDArray capsRequested = (OSDArray)OSDParser.DeserializeLLSDXml(request);
369 List<string> validCaps = new List<string>();
370
371 foreach (OSD c in capsRequested)
372 validCaps.Add(c.AsString());
373
374 string result = LLSDHelpers.SerialiseLLSDReply(m_HostCapsObj.GetCapsDetails(true, validCaps));
375
376 //m_log.DebugFormat("[CAPS] CapsRequest {0}", result);
377
378 return result;
379 }
380
381 /// <summary>
382 /// Called by the script task update handler. Provides a URL to which the client can upload a new asset.
383 /// </summary>
384 /// <param name="request"></param>
385 /// <param name="path"></param>
386 /// <param name="param"></param>
387 /// <param name="httpRequest">HTTP request header object</param>
388 /// <param name="httpResponse">HTTP response header object</param>
389 /// <returns></returns>
390 public string ScriptTaskInventory(string request, string path, string param,
391 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
392 {
393 try
394 {
395// m_log.Debug("[CAPS]: ScriptTaskInventory Request in region: " + m_regionName);
396 //m_log.DebugFormat("[CAPS]: request: {0}, path: {1}, param: {2}", request, path, param);
397
398 Hashtable hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request));
399 LLSDTaskScriptUpdate llsdUpdateRequest = new LLSDTaskScriptUpdate();
400 LLSDHelpers.DeserialiseOSDMap(hash, llsdUpdateRequest);
401
402 string uploaderPath = GetNewCapPath();
403
404 TaskInventoryScriptUpdater uploader =
405 new TaskInventoryScriptUpdater(
406 llsdUpdateRequest.item_id,
407 llsdUpdateRequest.task_id,
408 llsdUpdateRequest.is_script_running,
409 uploaderPath,
410 m_HostCapsObj.HttpListener,
411 m_dumpAssetsToFile);
412 uploader.OnUpLoad += TaskScriptUpdated;
413
414 m_HostCapsObj.HttpListener.AddStreamHandler(
415 new BinaryStreamHandler(
416 "POST", uploaderPath, uploader.uploaderCaps, "TaskInventoryScriptUpdater", null));
417
418 string protocol = "http://";
419
420 if (m_HostCapsObj.SSLCaps)
421 protocol = "https://";
422
423 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + uploaderPath;
424
425 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse();
426 uploadResponse.uploader = uploaderURL;
427 uploadResponse.state = "upload";
428
429 // m_log.InfoFormat("[CAPS]: " +
430 // "ScriptTaskInventory response: {0}",
431 // LLSDHelpers.SerialiseLLSDReply(uploadResponse)));
432
433 return LLSDHelpers.SerialiseLLSDReply(uploadResponse);
434 }
435 catch (Exception e)
436 {
437 m_log.Error("[CAPS]: " + e.ToString());
438 }
439
440 return null;
441 }
442
443 /// <summary>
444 /// Called when new asset data for an agent inventory item update has been uploaded.
445 /// </summary>
446 /// <param name="itemID">Item to update</param>
447 /// <param name="primID">Prim containing item to update</param>
448 /// <param name="isScriptRunning">Signals whether the script to update is currently running</param>
449 /// <param name="data">New asset data</param>
450 public void TaskScriptUpdated(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors)
451 {
452 if (TaskScriptUpdatedCall != null)
453 {
454 ArrayList e = TaskScriptUpdatedCall(m_HostCapsObj.AgentID, itemID, primID, isScriptRunning, data);
455 foreach (Object item in e)
456 errors.Add(item);
457 }
458 }
459
460 /// <summary>
461 /// Called when new asset data for an agent inventory item update has been uploaded.
462 /// </summary>
463 /// <param name="itemID">Item to update</param>
464 /// <param name="data">New asset data</param>
465 /// <returns></returns>
466 public UUID ItemUpdated(UUID itemID, byte[] data)
467 {
468 if (ItemUpdatedCall != null)
469 {
470 return ItemUpdatedCall(m_HostCapsObj.AgentID, itemID, data);
471 }
472
473 return UUID.Zero;
474 }
475
476 /// <summary>
477 ///
478 /// </summary>
479 /// <param name="llsdRequest"></param>
480 /// <returns></returns>
481 public LLSDAssetUploadResponse NewAgentInventoryRequest(LLSDAssetUploadRequest llsdRequest)
482 {
483 //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString());
484 //m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type);
485
486 // start by getting the client
487 IClientAPI client = null;
488 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
489
490 // check current state so we only have one service at a time
491 lock (m_ModelCost)
492 {
493 switch (m_FileAgentInventoryState)
494 {
495 case FileAgentInventoryState.processRequest:
496 case FileAgentInventoryState.processUpload:
497 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
498 resperror.message = "Uploader busy processing previus request";
499 resperror.identifier = UUID.Zero;
500
501 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
502 errorResponse.uploader = "";
503 errorResponse.state = "error";
504 errorResponse.error = resperror;
505 return errorResponse;
506// break;
507 case FileAgentInventoryState.waitUpload:
508 // todo stop current uploader server
509 break;
510 case FileAgentInventoryState.idle:
511 default:
512 break;
513 }
514
515 m_FileAgentInventoryState = FileAgentInventoryState.processRequest;
516 }
517
518 int cost = 0;
519 int nreqtextures = 0;
520 int nreqmeshs= 0;
521 int nreqinstances = 0;
522 bool IsAtestUpload = false;
523
524 string assetName = llsdRequest.name;
525
526 LLSDAssetUploadResponseData meshcostdata = new LLSDAssetUploadResponseData();
527
528 if (llsdRequest.asset_type == "texture" ||
529 llsdRequest.asset_type == "animation" ||
530 llsdRequest.asset_type == "animatn" || // this is the asset name actually used by viewers
531 llsdRequest.asset_type == "mesh" ||
532 llsdRequest.asset_type == "sound")
533 {
534 ScenePresence avatar = null;
535 m_Scene.TryGetScenePresence(m_HostCapsObj.AgentID, out avatar);
536
537 // check user level
538 if (avatar != null)
539 {
540 if (avatar.GodController.UserLevel < m_levelUpload)
541 {
542 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
543 resperror.message = "Insufficient permissions to upload";
544 resperror.identifier = UUID.Zero;
545
546 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
547 errorResponse.uploader = "";
548 errorResponse.state = "error";
549 errorResponse.error = resperror;
550 lock (m_ModelCost)
551 m_FileAgentInventoryState = FileAgentInventoryState.idle;
552 return errorResponse;
553 }
554 }
555
556 // check test upload and funds
557 if (client != null)
558 {
559 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>();
560
561 int baseCost = 0;
562 if (mm != null)
563 baseCost = mm.UploadCharge;
564
565 string warning = String.Empty;
566
567 if (llsdRequest.asset_type == "mesh")
568 {
569 string error;
570 int modelcost;
571
572
573 if (!m_ModelCost.MeshModelCost(llsdRequest.asset_resources, baseCost, out modelcost,
574 meshcostdata, out error, ref warning))
575 {
576 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
577 resperror.message = error;
578 resperror.identifier = UUID.Zero;
579
580 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
581 errorResponse.uploader = "";
582 errorResponse.state = "error";
583 errorResponse.error = resperror;
584
585 lock (m_ModelCost)
586 m_FileAgentInventoryState = FileAgentInventoryState.idle;
587 return errorResponse;
588 }
589 cost = modelcost;
590 }
591 else
592 {
593 cost = baseCost;
594 }
595
596 if (cost > 0 && mm != null)
597 {
598 // check for test upload
599
600 if (m_ForceFreeTestUpload) // all are test
601 {
602 if (!(assetName.Length > 5 && assetName.StartsWith("TEST-"))) // has normal name lets change it
603 assetName = "TEST-" + assetName;
604
605 IsAtestUpload = true;
606 }
607
608 else if (m_enableFreeTestUpload) // only if prefixed with "TEST-"
609 {
610
611 IsAtestUpload = (assetName.Length > 5 && assetName.StartsWith("TEST-"));
612 }
613
614
615 if(IsAtestUpload) // let user know, still showing cost estimation
616 warning += "Upload will have no cost, for testing purposes only. Other uses are prohibited. Items will not work after 48 hours or on other regions";
617
618 // check funds
619 else
620 {
621 if (!mm.UploadCovered(client.AgentId, (int)cost))
622 {
623 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
624 resperror.message = "Insuficient funds";
625 resperror.identifier = UUID.Zero;
626
627 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
628 errorResponse.uploader = "";
629 errorResponse.state = "error";
630 errorResponse.error = resperror;
631 lock (m_ModelCost)
632 m_FileAgentInventoryState = FileAgentInventoryState.idle;
633 return errorResponse;
634 }
635 }
636 }
637
638 if (client != null && warning != String.Empty)
639 client.SendAgentAlertMessage(warning, true);
640 }
641 }
642
643 string assetDes = llsdRequest.description;
644 UUID newAsset = UUID.Random();
645 UUID newInvItem = UUID.Random();
646 UUID parentFolder = llsdRequest.folder_id;
647 string uploaderPath = GetNewCapPath();
648 UUID texturesFolder = UUID.Zero;
649
650 if(!IsAtestUpload && m_enableModelUploadTextureToInventory)
651 texturesFolder = llsdRequest.texture_folder_id;
652
653 AssetUploader uploader =
654 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type,
655 llsdRequest.asset_type, uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile, cost,
656 texturesFolder, nreqtextures, nreqmeshs, nreqinstances, IsAtestUpload,
657 llsdRequest.next_owner_mask, llsdRequest.group_mask, llsdRequest.everyone_mask);
658
659 m_HostCapsObj.HttpListener.AddStreamHandler(
660 new BinaryStreamHandler(
661 "POST",
662 uploaderPath,
663 uploader.uploaderCaps,
664 "NewAgentInventoryRequest",
665 m_HostCapsObj.AgentID.ToString()));
666
667 string protocol = "http://";
668 if (m_HostCapsObj.SSLCaps)
669 protocol = "https://";
670
671 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + uploaderPath;
672
673 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse();
674 uploadResponse.uploader = uploaderURL;
675 uploadResponse.state = "upload";
676 uploadResponse.upload_price = (int)cost;
677
678 if (llsdRequest.asset_type == "mesh")
679 {
680 uploadResponse.data = meshcostdata;
681 }
682
683 uploader.OnUpLoad += UploadCompleteHandler;
684
685 lock (m_ModelCost)
686 m_FileAgentInventoryState = FileAgentInventoryState.waitUpload;
687
688 return uploadResponse;
689 }
690
691 /// <summary>
692 /// Convert raw uploaded data into the appropriate asset and item.
693 /// </summary>
694 /// <param name="assetID"></param>
695 /// <param name="inventoryItem"></param>
696 /// <param name="data"></param>
697 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID,
698 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType,
699 string assetType, int cost,
700 UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances,
701 bool IsAtestUpload, ref string error,
702 ref int nextOwnerMask, ref int groupMask, ref int everyoneMask)
703 {
704 lock (m_ModelCost)
705 m_FileAgentInventoryState = FileAgentInventoryState.processUpload;
706
707 m_log.DebugFormat(
708 "[BUNCH OF CAPS]: Uploaded asset {0} for inventory item {1}, inv type {2}, asset type {3}",
709 assetID, inventoryItem, inventoryType, assetType);
710
711 sbyte assType = 0;
712 sbyte inType = 0;
713
714 IClientAPI client = null;
715
716 UUID owner_id = m_HostCapsObj.AgentID;
717 UUID creatorID;
718
719 bool istest = IsAtestUpload && m_enableFreeTestUpload && (cost > 0);
720
721 bool restrictPerms = m_RestrictFreeTestUploadPerms && istest;
722
723 if (istest && m_testAssetsCreatorID != UUID.Zero)
724 creatorID = m_testAssetsCreatorID;
725 else
726 creatorID = owner_id;
727
728 string creatorIDstr = creatorID.ToString();
729
730 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>();
731 if (mm != null)
732 {
733 // make sure client still has enougth credit
734 if (!mm.UploadCovered(m_HostCapsObj.AgentID, (int)cost))
735 {
736 error = "Insufficient funds.";
737 return;
738 }
739 }
740
741 // strings to types
742 if (inventoryType == "sound")
743 {
744 inType = (sbyte)InventoryType.Sound;
745 assType = (sbyte)AssetType.Sound;
746 }
747 else if (inventoryType == "snapshot")
748 {
749 inType = (sbyte)InventoryType.Snapshot;
750 }
751 else if (inventoryType == "animation")
752 {
753 inType = (sbyte)InventoryType.Animation;
754 assType = (sbyte)AssetType.Animation;
755 }
756 else if (inventoryType == "animset")
757 {
758 inType = (sbyte)CustomInventoryType.AnimationSet;
759 assType = (sbyte)CustomAssetType.AnimationSet;
760 m_log.Debug("got animset upload request");
761 }
762 else if (inventoryType == "wearable")
763 {
764 inType = (sbyte)InventoryType.Wearable;
765 switch (assetType)
766 {
767 case "bodypart":
768 assType = (sbyte)AssetType.Bodypart;
769 break;
770 case "clothing":
771 assType = (sbyte)AssetType.Clothing;
772 break;
773 }
774 }
775 else if (inventoryType == "object")
776 {
777 if (assetType == "mesh") // this code for now is for mesh models uploads only
778 {
779 inType = (sbyte)InventoryType.Object;
780 assType = (sbyte)AssetType.Object;
781
782 List<Vector3> positions = new List<Vector3>();
783 List<Quaternion> rotations = new List<Quaternion>();
784 OSDMap request = (OSDMap)OSDParser.DeserializeLLSDXml(data);
785
786 // compare and get updated information
787/* does nothing still we do need something to avoid special viewer to upload something diferent from the cost estimation
788 bool mismatchError = true;
789
790 while (mismatchError)
791 {
792 mismatchError = false;
793 }
794
795 if (mismatchError)
796 {
797 error = "Upload and fee estimation information don't match";
798 lock (m_ModelCost)
799 m_FileAgentInventoryState = FileAgentInventoryState.idle;
800
801 return;
802 }
803*/
804 OSDArray instance_list = (OSDArray)request["instance_list"];
805 OSDArray mesh_list = (OSDArray)request["mesh_list"];
806 OSDArray texture_list = (OSDArray)request["texture_list"];
807 SceneObjectGroup grp = null;
808
809 // create and store texture assets
810 bool doTextInv = (!istest && m_enableModelUploadTextureToInventory &&
811 texturesFolder != UUID.Zero);
812
813
814 List<UUID> textures = new List<UUID>();
815
816
817// if (doTextInv)
818 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
819
820 if(client == null) // don't put textures in inventory if there is no client
821 doTextInv = false;
822
823 for (int i = 0; i < texture_list.Count; i++)
824 {
825 AssetBase textureAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Texture, creatorIDstr);
826 textureAsset.Data = texture_list[i].AsBinary();
827 if (istest)
828 textureAsset.Local = true;
829 m_assetService.Store(textureAsset);
830 textures.Add(textureAsset.FullID);
831
832 if (doTextInv)
833 {
834 string name = assetName;
835 if (name.Length > 25)
836 name = name.Substring(0, 24);
837 name += "_Texture#" + i.ToString();
838 InventoryItemBase texitem = new InventoryItemBase();
839 texitem.Owner = m_HostCapsObj.AgentID;
840 texitem.CreatorId = creatorIDstr;
841 texitem.CreatorData = String.Empty;
842 texitem.ID = UUID.Random();
843 texitem.AssetID = textureAsset.FullID;
844 texitem.Description = "mesh model texture";
845 texitem.Name = name;
846 texitem.AssetType = (int)AssetType.Texture;
847 texitem.InvType = (int)InventoryType.Texture;
848 texitem.Folder = texturesFolder;
849
850 texitem.CurrentPermissions
851 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Export);
852
853 texitem.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export;
854 texitem.EveryOnePermissions = 0;
855 texitem.NextPermissions = (uint)PermissionMask.All;
856 texitem.CreationDate = Util.UnixTimeSinceEpoch();
857
858 m_Scene.AddInventoryItem(client, texitem);
859 texitem = null;
860 }
861 }
862
863 // create and store meshs assets
864 List<UUID> meshAssets = new List<UUID>();
865 List<bool> meshAvatarSkeletons = new List<bool>();
866 List<bool> meshAvatarColliders = new List<bool>();
867
868 bool curAvSkeleton;
869 bool curAvCollider;
870 for (int i = 0; i < mesh_list.Count; i++)
871 {
872 curAvSkeleton = false;
873 curAvCollider = false;
874
875 // we do need to parse the mesh now
876 OSD osd = OSDParser.DeserializeLLSDBinary(mesh_list[i]);
877 if (osd is OSDMap)
878 {
879 OSDMap mosd = (OSDMap)osd;
880 if (mosd.ContainsKey("skeleton"))
881 {
882 OSDMap skeleton = (OSDMap)mosd["skeleton"];
883 int sksize = skeleton["size"].AsInteger();
884 if (sksize > 0)
885 curAvSkeleton = true;
886 }
887 }
888
889 AssetBase meshAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Mesh, creatorIDstr);
890 meshAsset.Data = mesh_list[i].AsBinary();
891 if (istest)
892 meshAsset.Local = true;
893 m_assetService.Store(meshAsset);
894 meshAssets.Add(meshAsset.FullID);
895 meshAvatarSkeletons.Add(curAvSkeleton);
896 meshAvatarColliders.Add(curAvCollider);
897
898 // test code
899 if (curAvSkeleton && client != null)
900 {
901 string name = assetName;
902 if (name.Length > 25)
903 name = name.Substring(0, 24);
904 name += "_Mesh#" + i.ToString();
905 InventoryItemBase meshitem = new InventoryItemBase();
906 meshitem.Owner = m_HostCapsObj.AgentID;
907 meshitem.CreatorId = creatorIDstr;
908 meshitem.CreatorData = String.Empty;
909 meshitem.ID = UUID.Random();
910 meshitem.AssetID = meshAsset.FullID;
911 meshitem.Description = "mesh ";
912 meshitem.Name = name;
913 meshitem.AssetType = (int)AssetType.Mesh;
914 meshitem.InvType = (int)InventoryType.Mesh;
915 // meshitem.Folder = UUID.Zero; // send to default
916
917 meshitem.Folder = parentFolder; // dont let it go to folder Meshes that viewers dont show
918
919 // If we set PermissionMask.All then when we rez the item the next permissions will replace the current
920 // (owner) permissions. This becomes a problem if next permissions are changed.
921 meshitem.CurrentPermissions
922 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer);
923
924 meshitem.BasePermissions = (uint)PermissionMask.All;
925 meshitem.EveryOnePermissions = 0;
926 meshitem.NextPermissions = (uint)PermissionMask.All;
927 meshitem.CreationDate = Util.UnixTimeSinceEpoch();
928
929 m_Scene.AddInventoryItem(client, meshitem);
930 meshitem = null;
931 }
932 }
933
934 int skipedMeshs = 0;
935 // build prims from instances
936 for (int i = 0; i < instance_list.Count; i++)
937 {
938 OSDMap inner_instance_list = (OSDMap)instance_list[i];
939
940 // skip prims that are 2 small
941 Vector3 scale = inner_instance_list["scale"].AsVector3();
942
943 if (scale.X < m_PrimScaleMin || scale.Y < m_PrimScaleMin || scale.Z < m_PrimScaleMin)
944 {
945 skipedMeshs++;
946 continue;
947 }
948
949 OSDArray face_list = (OSDArray)inner_instance_list["face_list"];
950
951 PrimitiveBaseShape pbs = null;
952 if (inner_instance_list.ContainsKey("mesh")) // seems to happen always but ...
953 {
954 int meshindx = inner_instance_list["mesh"].AsInteger();
955 if (meshAssets.Count > meshindx)
956 pbs = PrimitiveBaseShape.CreateMesh(face_list.Count, meshAssets[meshindx]);
957 }
958 if(pbs == null) // fallback
959 pbs = PrimitiveBaseShape.CreateBox();
960
961 Primitive.TextureEntry textureEntry
962 = new Primitive.TextureEntry(Primitive.TextureEntry.WHITE_TEXTURE);
963
964 for (uint face = 0; face < face_list.Count; face++)
965 {
966 OSDMap faceMap = (OSDMap)face_list[(int)face];
967
968 Primitive.TextureEntryFace f = textureEntry.CreateFace(face); //clone the default
969 if (faceMap.ContainsKey("fullbright"))
970 f.Fullbright = faceMap["fullbright"].AsBoolean();
971 if (faceMap.ContainsKey("diffuse_color"))
972 f.RGBA = faceMap["diffuse_color"].AsColor4();
973
974 int textureNum = faceMap["image"].AsInteger();
975 float imagerot = faceMap["imagerot"].AsInteger();
976 float offsets = (float)faceMap["offsets"].AsReal();
977 float offsett = (float)faceMap["offsett"].AsReal();
978 float scales = (float)faceMap["scales"].AsReal();
979 float scalet = (float)faceMap["scalet"].AsReal();
980
981 if (imagerot != 0)
982 f.Rotation = imagerot;
983
984 if (offsets != 0)
985 f.OffsetU = offsets;
986
987 if (offsett != 0)
988 f.OffsetV = offsett;
989
990 if (scales != 0)
991 f.RepeatU = scales;
992
993 if (scalet != 0)
994 f.RepeatV = scalet;
995
996 if (textures.Count > textureNum)
997 f.TextureID = textures[textureNum];
998
999 textureEntry.FaceTextures[face] = f;
1000 }
1001 pbs.TextureEntry = textureEntry.GetBytes();
1002
1003 Vector3 position = inner_instance_list["position"].AsVector3();
1004 Quaternion rotation = inner_instance_list["rotation"].AsQuaternion();
1005
1006 // for now viwers do send fixed defaults
1007 // but this may change
1008// int physicsShapeType = inner_instance_list["physics_shape_type"].AsInteger();
1009 byte physicsShapeType = (byte)PhysShapeType.convex; // default is simple convex
1010// int material = inner_instance_list["material"].AsInteger();
1011 byte material = (byte)Material.Wood;
1012
1013 SceneObjectPart prim
1014 = new SceneObjectPart(owner_id, pbs, position, Quaternion.Identity, Vector3.Zero);
1015
1016 prim.Scale = scale;
1017 rotations.Add(rotation);
1018 positions.Add(position);
1019 prim.UUID = UUID.Random();
1020 prim.CreatorID = creatorID;
1021 prim.OwnerID = owner_id;
1022 prim.GroupID = UUID.Zero;
1023 prim.LastOwnerID = creatorID;
1024 prim.RezzerID = creatorID;
1025 prim.CreationDate = Util.UnixTimeSinceEpoch();
1026
1027 if (grp == null)
1028 prim.Name = assetName;
1029 else
1030 prim.Name = assetName + "#" + i.ToString();
1031
1032 prim.EveryoneMask = 0;
1033 prim.GroupMask = 0;
1034
1035 if (restrictPerms)
1036 {
1037 prim.BaseMask = (uint)(PermissionMask.Move | PermissionMask.Modify);
1038 prim.OwnerMask = (uint)(PermissionMask.Move | PermissionMask.Modify);
1039 prim.NextOwnerMask = 0;
1040 }
1041 else
1042 {
1043 prim.BaseMask = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1044 prim.OwnerMask = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1045 prim.GroupMask = prim.BaseMask & (uint)groupMask;
1046 prim.EveryoneMask = prim.BaseMask & (uint)everyoneMask;
1047 prim.NextOwnerMask = prim.BaseMask & (uint)nextOwnerMask;
1048 // If the viewer gives us bogus permissions, revert to the SL
1049 // default of transfer only.
1050 if ((prim.NextOwnerMask & (uint)PermissionMask.All) == 0)
1051 prim.NextOwnerMask = (uint)PermissionMask.Transfer;
1052 }
1053
1054 if(istest)
1055 prim.Description = "For testing only. Other uses are prohibited";
1056 else
1057 prim.Description = "";
1058
1059 prim.Material = material;
1060 prim.PhysicsShapeType = physicsShapeType;
1061
1062// prim.BaseMask = (uint)base_mask;
1063// prim.EveryoneMask = (uint)everyone_mask;
1064// prim.GroupMask = (uint)group_mask;
1065// prim.NextOwnerMask = (uint)next_owner_mask;
1066// prim.OwnerMask = (uint)owner_mask;
1067
1068 if (grp == null)
1069 {
1070 grp = new SceneObjectGroup(prim);
1071 grp.LastOwnerID = creatorID;
1072 grp.RezzerID = creatorID;
1073 }
1074 else
1075 grp.AddPart(prim);
1076 }
1077
1078 Vector3 rootPos = positions[0];
1079
1080 if (grp.Parts.Length > 1)
1081 {
1082 // Fix first link number
1083 grp.RootPart.LinkNum++;
1084
1085 Quaternion rootRotConj = Quaternion.Conjugate(rotations[0]);
1086 Quaternion tmprot;
1087 Vector3 offset;
1088
1089 // fix children rotations and positions
1090 for (int i = 1; i < rotations.Count; i++)
1091 {
1092 tmprot = rotations[i];
1093 tmprot = rootRotConj * tmprot;
1094
1095 grp.Parts[i].RotationOffset = tmprot;
1096
1097 offset = positions[i] - rootPos;
1098
1099 offset *= rootRotConj;
1100 grp.Parts[i].OffsetPosition = offset;
1101 }
1102
1103 grp.AbsolutePosition = rootPos;
1104 grp.UpdateGroupRotationR(rotations[0]);
1105 }
1106 else
1107 {
1108 grp.AbsolutePosition = rootPos;
1109 grp.UpdateGroupRotationR(rotations[0]);
1110 }
1111
1112 data = ASCIIEncoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(grp));
1113 }
1114
1115 else // not a mesh model
1116 {
1117 m_log.ErrorFormat("[CAPS Asset Upload] got unsuported assetType for object upload");
1118 return;
1119 }
1120 }
1121
1122 AssetBase asset;
1123 asset = new AssetBase(assetID, assetName, assType, creatorIDstr);
1124 asset.Data = data;
1125 if (istest)
1126 asset.Local = true;
1127 if (AddNewAsset != null)
1128 AddNewAsset(asset);
1129 else if (m_assetService != null)
1130 m_assetService.Store(asset);
1131
1132 InventoryItemBase item = new InventoryItemBase();
1133 item.Owner = m_HostCapsObj.AgentID;
1134 item.CreatorId = creatorIDstr;
1135 item.CreatorData = String.Empty;
1136 item.ID = inventoryItem;
1137 item.AssetID = asset.FullID;
1138 if (istest)
1139 {
1140 item.Description = "For testing only. Other uses are prohibited";
1141 item.Flags = (uint) (InventoryItemFlags.SharedSingleReference);
1142 }
1143 else
1144 item.Description = assetDescription;
1145 item.Name = assetName;
1146 item.AssetType = assType;
1147 item.InvType = inType;
1148 item.Folder = parentFolder;
1149
1150 // If we set PermissionMask.All then when we rez the item the next permissions will replace the current
1151 // (owner) permissions. This becomes a problem if next permissions are changed.
1152
1153 if (inType == (sbyte)CustomInventoryType.AnimationSet)
1154 {
1155 AnimationSet.setCreateItemPermitions(item);
1156 }
1157
1158 else if (restrictPerms)
1159 {
1160 item.BasePermissions = (uint)(PermissionMask.Move | PermissionMask.Modify);
1161 item.CurrentPermissions = (uint)(PermissionMask.Move | PermissionMask.Modify);
1162 item.GroupPermissions = 0;
1163 item.EveryOnePermissions = 0;
1164 item.NextPermissions = 0;
1165 }
1166 else
1167 {
1168 item.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1169 item.CurrentPermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1170 item.GroupPermissions = item.BasePermissions & (uint)groupMask;
1171 item.EveryOnePermissions = item.BasePermissions & (uint)everyoneMask;
1172 item.NextPermissions = item.BasePermissions & (uint)nextOwnerMask;
1173 if ((item.NextPermissions & (uint)PermissionMask.All) == 0)
1174 item.NextPermissions = (uint)PermissionMask.Transfer;
1175 }
1176
1177 item.CreationDate = Util.UnixTimeSinceEpoch();
1178
1179 everyoneMask = (int)item.EveryOnePermissions;
1180 groupMask = (int)item.GroupPermissions;
1181 nextOwnerMask = (int)item.NextPermissions;
1182
1183 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
1184
1185 if (AddNewInventoryItem != null)
1186 {
1187 if (istest)
1188 {
1189 m_Scene.AddInventoryItem(client, item);
1190/*
1191 AddNewInventoryItem(m_HostCapsObj.AgentID, item, 0);
1192 if (client != null)
1193 client.SendAgentAlertMessage("Upload will have no cost, for personal test purposes only. Other uses are forbiden. Items may not work on a another region" , true);
1194 */
1195 }
1196 else
1197 {
1198 AddNewInventoryItem(m_HostCapsObj.AgentID, item, (uint)cost);
1199// if (client != null)
1200// {
1201// // let users see anything.. i don't so far
1202// string str;
1203// if (cost > 0)
1204// // dont remember where is money unit name to put here
1205// str = "Upload complete. charged " + cost.ToString() + "$";
1206// else
1207// str = "Upload complete";
1208// client.SendAgentAlertMessage(str, true);
1209// }
1210 }
1211 }
1212
1213 lock (m_ModelCost)
1214 m_FileAgentInventoryState = FileAgentInventoryState.idle;
1215 }
1216
1217 /// <summary>
1218 ///
1219 /// </summary>
1220 /// <param name="mapReq"></param>
1221 /// <returns></returns>
1222 public LLSDMapLayerResponse GetMapLayer(LLSDMapRequest mapReq)
1223 {
1224 m_log.Debug("[CAPS]: MapLayer Request in region: " + m_regionName);
1225 LLSDMapLayerResponse mapResponse = new LLSDMapLayerResponse();
1226 mapResponse.LayerData.Array.Add(GetOSDMapLayerResponse());
1227 return mapResponse;
1228 }
1229
1230 /// <summary>
1231 ///
1232 /// </summary>
1233 /// <returns></returns>
1234 protected static OSDMapLayer GetOSDMapLayerResponse()
1235 {
1236 OSDMapLayer mapLayer = new OSDMapLayer();
1237 mapLayer.Right = 5000;
1238 mapLayer.Top = 5000;
1239 mapLayer.ImageID = new UUID("00000000-0000-1111-9999-000000000006");
1240
1241 return mapLayer;
1242 }
1243
1244 /// <summary>
1245 ///
1246 /// </summary>
1247 /// <param name="request"></param>
1248 /// <param name="path"></param>
1249 /// <param name="param"></param>
1250 /// <returns></returns>
1251 public string RequestTexture(string request, string path, string param)
1252 {
1253 m_log.Debug("texture request " + request);
1254 // Needs implementing (added to remove compiler warning)
1255 return String.Empty;
1256 }
1257
1258
1259 /// <summary>
1260 /// Called by the notecard update handler. Provides a URL to which the client can upload a new asset.
1261 /// </summary>
1262 /// <param name="request"></param>
1263 /// <param name="path"></param>
1264 /// <param name="param"></param>
1265 /// <returns></returns>
1266 public string NoteCardAgentInventory(string request, string path, string param,
1267 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
1268 {
1269 //m_log.Debug("[CAPS]: NoteCardAgentInventory Request in region: " + m_regionName + "\n" + request);
1270 //m_log.Debug("[CAPS]: NoteCardAgentInventory Request is: " + request);
1271
1272 //OpenMetaverse.StructuredData.OSDMap hash = (OpenMetaverse.StructuredData.OSDMap)OpenMetaverse.StructuredData.LLSDParser.DeserializeBinary(Utils.StringToBytes(request));
1273 Hashtable hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request));
1274 LLSDItemUpdate llsdRequest = new LLSDItemUpdate();
1275 LLSDHelpers.DeserialiseOSDMap(hash, llsdRequest);
1276
1277 string uploaderPath = GetNewCapPath();
1278
1279 ItemUpdater uploader =
1280 new ItemUpdater(llsdRequest.item_id, uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile);
1281 uploader.OnUpLoad += ItemUpdated;
1282
1283 m_HostCapsObj.HttpListener.AddStreamHandler(
1284 new BinaryStreamHandler(
1285 "POST", uploaderPath, uploader.uploaderCaps, "NoteCardAgentInventory", null));
1286
1287 string protocol = "http://";
1288
1289 if (m_HostCapsObj.SSLCaps)
1290 protocol = "https://";
1291
1292 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + uploaderPath;
1293
1294 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse();
1295 uploadResponse.uploader = uploaderURL;
1296 uploadResponse.state = "upload";
1297
1298 // m_log.InfoFormat("[CAPS]: " +
1299 // "NoteCardAgentInventory response: {0}",
1300 // LLSDHelpers.SerialiseLLSDReply(uploadResponse)));
1301
1302 return LLSDHelpers.SerialiseLLSDReply(uploadResponse);
1303 }
1304
1305 /// <summary>
1306 /// Called by the CopyInventoryFromNotecard caps handler.
1307 /// </summary>
1308 /// <param name="request"></param>
1309 /// <param name="path"></param>
1310 /// <param name="param"></param>
1311 public string CopyInventoryFromNotecard(string request, string path, string param,
1312 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
1313 {
1314 Hashtable response = new Hashtable();
1315 response["int_response_code"] = 404;
1316 response["content_type"] = "text/plain";
1317 response["keepalive"] = false;
1318 response["str_response_string"] = "";
1319
1320 try
1321 {
1322 OSDMap content = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1323 UUID objectID = content["object-id"].AsUUID();
1324 UUID notecardID = content["notecard-id"].AsUUID();
1325 UUID folderID = content["folder-id"].AsUUID();
1326 UUID itemID = content["item-id"].AsUUID();
1327
1328 // m_log.InfoFormat("[CAPS]: CopyInventoryFromNotecard, FolderID:{0}, ItemID:{1}, NotecardID:{2}, ObjectID:{3}", folderID, itemID, notecardID, objectID);
1329
1330 if (objectID != UUID.Zero)
1331 {
1332 SceneObjectPart part = m_Scene.GetSceneObjectPart(objectID);
1333 if (part != null)
1334 {
1335// TaskInventoryItem taskItem = part.Inventory.GetInventoryItem(notecardID);
1336 if (!m_Scene.Permissions.CanCopyObjectInventory(notecardID, objectID, m_HostCapsObj.AgentID))
1337 {
1338 return LLSDHelpers.SerialiseLLSDReply(response);
1339 }
1340 }
1341 }
1342
1343 InventoryItemBase item = null;
1344 InventoryItemBase copyItem = null;
1345 IClientAPI client = null;
1346
1347 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
1348 item = m_Scene.InventoryService.GetItem(m_HostCapsObj.AgentID, itemID);
1349 if (item != null)
1350 {
1351 string message;
1352 copyItem = m_Scene.GiveInventoryItem(m_HostCapsObj.AgentID, item.Owner, itemID, folderID, out message);
1353 if (copyItem != null && client != null)
1354 {
1355 m_log.InfoFormat("[CAPS]: CopyInventoryFromNotecard, ItemID:{0}, FolderID:{1}", copyItem.ID, copyItem.Folder);
1356 client.SendBulkUpdateInventory(copyItem);
1357 }
1358 }
1359 else
1360 {
1361 m_log.ErrorFormat("[CAPS]: CopyInventoryFromNotecard - Failed to retrieve item {0} from notecard {1}", itemID, notecardID);
1362 if (client != null)
1363 client.SendAlertMessage("Failed to retrieve item");
1364 }
1365 }
1366 catch (Exception e)
1367 {
1368 m_log.ErrorFormat("[CAPS]: CopyInventoryFromNotecard : {0}", e.ToString());
1369 }
1370
1371 response["int_response_code"] = 200;
1372 return LLSDHelpers.SerialiseLLSDReply(response);
1373 }
1374
1375 public string GetObjectPhysicsData(string request, string path,
1376 string param, IOSHttpRequest httpRequest,
1377 IOSHttpResponse httpResponse)
1378 {
1379 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1380 OSDMap resp = new OSDMap();
1381 OSDArray object_ids = (OSDArray)req["object_ids"];
1382
1383 for (int i = 0 ; i < object_ids.Count ; i++)
1384 {
1385 UUID uuid = object_ids[i].AsUUID();
1386
1387 SceneObjectPart obj = m_Scene.GetSceneObjectPart(uuid);
1388 if (obj != null)
1389 {
1390 OSDMap object_data = new OSDMap();
1391
1392 object_data["PhysicsShapeType"] = obj.PhysicsShapeType;
1393 object_data["Density"] = obj.Density;
1394 object_data["Friction"] = obj.Friction;
1395 object_data["Restitution"] = obj.Restitution;
1396 object_data["GravityMultiplier"] = obj.GravityModifier;
1397
1398 resp[uuid.ToString()] = object_data;
1399 }
1400 }
1401
1402 string response = OSDParser.SerializeLLSDXmlString(resp);
1403 return response;
1404 }
1405
1406 public string GetObjectCost(string request, string path,
1407 string param, IOSHttpRequest httpRequest,
1408 IOSHttpResponse httpResponse)
1409 {
1410 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1411 OSDMap resp = new OSDMap();
1412
1413 OSDArray object_ids = (OSDArray)req["object_ids"];
1414
1415 for (int i = 0; i < object_ids.Count; i++)
1416 {
1417 UUID uuid = object_ids[i].AsUUID();
1418
1419 SceneObjectPart part = m_Scene.GetSceneObjectPart(uuid);
1420 SceneObjectGroup grp = null;
1421 if (part != null)
1422 grp = part.ParentGroup;
1423 if (grp != null)
1424 {
1425 float linksetCost;
1426 float linksetPhysCost;
1427 float partCost;
1428 float partPhysCost;
1429
1430 grp.GetResourcesCosts(part,out linksetCost,out linksetPhysCost,out partCost,out partPhysCost);
1431
1432 OSDMap object_data = new OSDMap();
1433 object_data["linked_set_resource_cost"] = linksetCost;
1434 object_data["resource_cost"] = partCost;
1435 object_data["physics_cost"] = partPhysCost;
1436 object_data["linked_set_physics_cost"] = linksetPhysCost;
1437 object_data["resource_limiting_type"] = "legacy";
1438 resp[uuid.ToString()] = object_data;
1439 }
1440 }
1441 if(resp.Count == 0)
1442 {
1443 OSDMap object_data = new OSDMap();
1444 object_data["linked_set_resource_cost"] = 0;
1445 object_data["resource_cost"] = 0;
1446 object_data["physics_cost"] = 0;
1447 object_data["linked_set_physics_cost"] = 0;
1448 resp[UUID.Zero.ToString()] = object_data;
1449 }
1450 string response = OSDParser.SerializeLLSDXmlString(resp);
1451 return response;
1452 }
1453
1454 public string ResourceCostSelected(string request, string path,
1455 string param, IOSHttpRequest httpRequest,
1456 IOSHttpResponse httpResponse)
1457 {
1458 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1459 OSDMap resp = new OSDMap();
1460
1461
1462 float phys=0;
1463 float stream=0;
1464 float simul=0;
1465
1466 if (req.ContainsKey("selected_roots"))
1467 {
1468 OSDArray object_ids = (OSDArray)req["selected_roots"];
1469
1470 // should go by SOG suming costs for all parts
1471 // ll v3 works ok with several objects select we get the list and adds ok
1472 // FS calls per object so results are wrong guess fs bug
1473 for (int i = 0; i < object_ids.Count; i++)
1474 {
1475 UUID uuid = object_ids[i].AsUUID();
1476 float Physc;
1477 float simulc;
1478 float streamc;
1479
1480 SceneObjectGroup grp = m_Scene.GetGroupByPrim(uuid);
1481 if (grp != null)
1482 {
1483 grp.GetSelectedCosts(out Physc, out streamc, out simulc);
1484 phys += Physc;
1485 stream += streamc;
1486 simul += simulc;
1487 }
1488 }
1489 }
1490 else if (req.ContainsKey("selected_prims"))
1491 {
1492 OSDArray object_ids = (OSDArray)req["selected_prims"];
1493
1494 // don't see in use in any of the 2 viewers
1495 // guess it should be for edit linked but... nothing
1496 // should go to SOP per part
1497 for (int i = 0; i < object_ids.Count; i++)
1498 {
1499 UUID uuid = object_ids[i].AsUUID();
1500
1501 SceneObjectPart part = m_Scene.GetSceneObjectPart(uuid);
1502 if (part != null)
1503 {
1504 phys += part.PhysicsCost;
1505 stream += part.StreamingCost;
1506 simul += part.SimulationCost;
1507 }
1508 }
1509 }
1510
1511 OSDMap object_data = new OSDMap();
1512
1513 object_data["physics"] = phys;
1514 object_data["streaming"] = stream;
1515 object_data["simulation"] = simul;
1516
1517 resp["selected"] = object_data;
1518// resp["transaction_id"] = "undef";
1519 string response = OSDParser.SerializeLLSDXmlString(resp);
1520 return response;
1521 }
1522
1523 public string UpdateAgentInformation(string request, string path,
1524 string param, IOSHttpRequest httpRequest,
1525 IOSHttpResponse httpResponse)
1526 {
1527// OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1528 OSDMap resp = new OSDMap();
1529
1530 OSDMap accessPrefs = new OSDMap();
1531 accessPrefs["max"] = "A";
1532
1533 resp["access_prefs"] = accessPrefs;
1534
1535 string response = OSDParser.SerializeLLSDXmlString(resp);
1536 return response;
1537 }
1538
1539 public bool OSDMapTOVector3(OSDMap map, out Vector3 v)
1540 {
1541 v = Vector3.Zero;
1542 if(!map.ContainsKey("X"))
1543 return false;
1544 if(!map.ContainsKey("Y"))
1545 return false;
1546 if(!map.ContainsKey("Z"))
1547 return false;
1548 v.X = (float)map["X"].AsReal();
1549 v.Y = (float)map["Y"].AsReal();
1550 v.Z = (float)map["Z"].AsReal();
1551 return true;
1552 }
1553
1554 public string HomeLocation(string request, string path, string param, IOSHttpRequest httpRequest,
1555 IOSHttpResponse httpResponse)
1556 {
1557 OSDMap resp = new OSDMap();
1558
1559 resp["success"] = "false";
1560
1561
1562 bool fail = true;
1563 string message = "Set Home request failed";
1564 int locationID = 1;
1565 Vector3 pos = Vector3.Zero;
1566 Vector3 lookAt = Vector3.Zero;
1567
1568 IClientAPI client = null;
1569 ScenePresence sp;
1570
1571 while(true)
1572 {
1573 if(m_Scene.GridUserService == null)
1574 break;
1575
1576 if(m_Scene.UserManagementModule == null)
1577 break;
1578
1579 m_Scene.TryGetScenePresence(m_AgentID, out sp);
1580 if(sp == null || sp.IsChildAgent || sp.IsDeleted)
1581 break;
1582
1583 if(sp.IsInTransit && !sp.IsInLocalTransit)
1584 break;
1585
1586 client = sp.ControllingClient;
1587
1588 if(!m_Scene.UserManagementModule.IsLocalGridUser(m_AgentID))
1589 break;
1590
1591 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1592 if(!req.ContainsKey("HomeLocation"))
1593 break;
1594
1595 OSDMap HLocation = (OSDMap)req["HomeLocation"];
1596 if(!HLocation.ContainsKey("LocationPos"))
1597 break;
1598 if(!HLocation.ContainsKey("LocationLookAt"))
1599 break;
1600
1601 locationID = HLocation["LocationId"].AsInteger();
1602
1603 if(!OSDMapTOVector3((OSDMap)HLocation["LocationPos"], out pos))
1604 break;
1605
1606 if(!OSDMapTOVector3((OSDMap)HLocation["LocationLookAt"], out lookAt))
1607 break;
1608
1609 ILandObject land = m_Scene.LandChannel.GetLandObject(pos);
1610 if(land == null)
1611 break;
1612
1613 ulong gpowers = client.GetGroupPowers(land.LandData.GroupID);
1614 SceneObjectGroup telehub = null;
1615 if (m_Scene.RegionInfo.RegionSettings.TelehubObject != UUID.Zero)
1616 // Does the telehub exist in the scene?
1617 telehub = m_Scene.GetSceneObjectGroup(m_Scene.RegionInfo.RegionSettings.TelehubObject);
1618
1619 if (!m_Scene.Permissions.IsAdministrator(m_AgentID) && // (a) gods and land managers can set home
1620 !m_Scene.Permissions.IsGod(m_AgentID) &&
1621 m_AgentID != land.LandData.OwnerID && // (b) land owners can set home
1622 // (c) members of the land-associated group in roles that can set home
1623 ((gpowers & (ulong)GroupPowers.AllowSetHome) != (ulong)GroupPowers.AllowSetHome) &&
1624 // (d) parcels with telehubs can be the home of anyone
1625 (telehub == null || !land.ContainsPoint((int)telehub.AbsolutePosition.X, (int)telehub.AbsolutePosition.Y)))
1626 {
1627 message = "You are not allowed to set your home location in this parcel.";
1628 break;
1629 }
1630
1631 string userId;
1632 UUID test;
1633 if (!m_Scene.UserManagementModule.GetUserUUI(m_AgentID, out userId))
1634 {
1635 message = "Set Home request failed. (User Lookup)";
1636 break;
1637 }
1638
1639 if (!UUID.TryParse(userId, out test))
1640 {
1641 message = "Set Home request failed. (HG visitor)";
1642 break;
1643 }
1644
1645 if (m_Scene.GridUserService.SetHome(userId, land.RegionUUID, pos, lookAt))
1646 fail = false;
1647
1648 break;
1649 }
1650
1651 string response;
1652
1653 if(fail)
1654 {
1655 if(client != null)
1656 client.SendAlertMessage(message);
1657 response = OSDParser.SerializeLLSDXmlString(resp);
1658 return response;
1659 }
1660
1661 // so its http but still needs a udp reply to inform user? crap :p
1662 if(client != null)
1663 client.SendAlertMessage("Home position set.","HomePositionSet");
1664
1665 resp["success"] = "true";
1666 OSDMap homeloc = new OSDMap();
1667 OSDMap homelocpos = new OSDMap();
1668 // for some odd reason viewers send pos as reals but read as integer
1669 homelocpos["X"] = new OSDReal(pos.X);
1670 homelocpos["Y"] = new OSDReal(pos.Y);
1671 homelocpos["Z"] = new OSDReal(pos.Z);
1672 homeloc["LocationPos"] = homelocpos;
1673
1674 resp["HomeLocation"] = homeloc;
1675
1676 response = OSDParser.SerializeLLSDXmlString(resp);
1677 return response;
1678 }
1679
1680 private static int CompareRolesByMembersDesc(GroupRolesData x, GroupRolesData y)
1681 {
1682 return -(x.Members.CompareTo(y.Members));
1683 }
1684
1685 public string GroupMemberData(string request, string path, string param, IOSHttpRequest httpRequest,
1686 IOSHttpResponse httpResponse)
1687 {
1688 OSDMap resp = new OSDMap();
1689
1690 string response;
1691
1692 bool fail = true;
1693 IClientAPI client = null;
1694 ScenePresence sp;
1695 IGroupsModule m_GroupsModule;
1696 UUID groupID = UUID.Zero;
1697
1698 while(true)
1699 {
1700 m_GroupsModule = m_Scene.RequestModuleInterface<IGroupsModule>();
1701 if(m_GroupsModule == null)
1702 break;
1703
1704 m_Scene.TryGetScenePresence(m_AgentID, out sp);
1705 if(sp == null || sp.IsChildAgent || sp.IsDeleted)
1706 break;
1707
1708 if(sp.IsInTransit && !sp.IsInLocalTransit)
1709 break;
1710
1711 client = sp.ControllingClient;
1712
1713 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1714 if(!req.ContainsKey("group_id"))
1715 break;
1716
1717 groupID = req["group_id"].AsUUID();
1718 if(groupID == UUID.Zero)
1719 break;
1720
1721 List<GroupRolesData> roles = m_GroupsModule.GroupRoleDataRequest(client, groupID);
1722 if(roles == null || roles.Count == 0)
1723 break;
1724
1725 List<GroupMembersData> members = m_GroupsModule.GroupMembersRequest(client, groupID);
1726 if(members == null || members.Count == 0)
1727 break;
1728
1729 int memberCount = members.Count;
1730
1731 Dictionary<string,int> titles = new Dictionary<string,int>();
1732 int i = 0;
1733
1734 ulong defaultPowers = 0;
1735
1736
1737 // build titles array and index
1738 roles.Sort(CompareRolesByMembersDesc);
1739
1740 OSDArray osdtitles = new OSDArray();
1741 foreach(GroupRolesData grd in roles)
1742 {
1743 if(grd.Title == null)
1744 continue;
1745 string title = grd.Title;
1746 if(i==0)
1747 defaultPowers = grd.Powers;
1748
1749 if(!titles.ContainsKey(title))
1750 {
1751 titles[title] = i++;
1752 osdtitles.Add(new OSDString(title));
1753 }
1754 }
1755
1756 if(titles.Count == 0)
1757 break;
1758
1759 OSDMap osdmembers = new OSDMap();
1760 foreach(GroupMembersData gmd in members)
1761 {
1762 OSDMap m = new OSDMap();
1763 if(gmd.OnlineStatus != null && gmd.OnlineStatus != "")
1764 m["last_login"] = new OSDString(gmd.OnlineStatus);
1765 if(gmd.AgentPowers != defaultPowers)
1766 m["powers"] = new OSDString((gmd.AgentPowers).ToString("X"));
1767 if(gmd.Title != null && titles.ContainsKey(gmd.Title) && titles[gmd.Title] != 0)
1768 m["title"] = new OSDInteger(titles[gmd.Title]);
1769 if(gmd.IsOwner)
1770 m["owner"] = new OSDString("true");
1771 if(gmd.Contribution != 0)
1772 m["donated_square_meters"] = new OSDInteger(gmd.Contribution);
1773
1774 osdmembers[(gmd.AgentID).ToString()] = m;
1775 }
1776
1777 OSDMap osddefaults = new OSDMap();
1778 osddefaults["default_powers"] = new OSDString(defaultPowers.ToString("X"));
1779
1780 resp["group_id"] = new OSDUUID(groupID);
1781 resp["agent_id"] = new OSDUUID(m_AgentID);
1782 resp["member_count"] = new OSDInteger(memberCount);
1783 resp["defaults"] = osddefaults;
1784 resp["titles"] = osdtitles;
1785 resp["members"] = osdmembers;
1786
1787 fail = false;
1788 break;
1789 }
1790
1791 if(fail)
1792 {
1793 resp["group_id"] = new OSDUUID(groupID);
1794 resp["agent_id"] = new OSDUUID(m_AgentID);
1795 resp["member_count"] = new OSDInteger(0);
1796 resp["defaults"] = new OSDMap();
1797 resp["titles"] = new OSDArray();
1798 resp["members"] = new OSDMap();
1799 }
1800
1801 response = OSDParser.SerializeLLSDXmlString(resp);
1802 return response;
1803 }
1804
1805 public string GetDisplayNames(string request, string path,
1806 string param, IOSHttpRequest httpRequest,
1807 IOSHttpResponse httpResponse)
1808 {
1809 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.Gone;
1810 httpResponse.ContentType = "text/plain";
1811
1812 ScenePresence sp = m_Scene.GetScenePresence(m_AgentID);
1813 if(sp == null || sp.IsDeleted)
1814 return "";
1815
1816 if(sp.IsInTransit && !sp.IsInLocalTransit)
1817 {
1818 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.ServiceUnavailable;
1819 httpResponse.AddHeader("Retry-After","30");
1820 return "";
1821 }
1822
1823 NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query);
1824 string[] ids = query.GetValues("ids");
1825
1826 Dictionary<UUID,string> names = m_UserManager.GetUsersNames(ids);
1827
1828 OSDMap osdReply = new OSDMap();
1829 OSDArray agents = new OSDArray();
1830
1831 osdReply["agents"] = agents;
1832 foreach (KeyValuePair<UUID,string> kvp in names)
1833 {
1834 if (string.IsNullOrEmpty(kvp.Value))
1835 continue;
1836 if(kvp.Key == UUID.Zero)
1837 continue;
1838
1839 string[] parts = kvp.Value.Split(new char[] {' '});
1840 OSDMap osdname = new OSDMap();
1841
1842 // dont tell about unknown users, we can't send them back on Bad either
1843 if(parts[0] == "Unknown")
1844 continue;
1845/*
1846 if(parts[0] == "Unknown")
1847 {
1848 osdname["display_name_next_update"] = OSD.FromDate(DateTime.UtcNow.AddHours(1));
1849 osdname["display_name_expires"] = OSD.FromDate(DateTime.UtcNow.AddHours(2));
1850 }
1851 else
1852*/
1853 {
1854 osdname["display_name_next_update"] = OSD.FromDate(DateTime.UtcNow.AddDays(8));
1855 osdname["display_name_expires"] = OSD.FromDate(DateTime.UtcNow.AddMonths(1));
1856 }
1857 osdname["display_name"] = OSD.FromString(kvp.Value);
1858 osdname["legacy_first_name"] = parts[0];
1859 osdname["legacy_last_name"] = parts[1];
1860 osdname["username"] = OSD.FromString(kvp.Value);
1861 osdname["id"] = OSD.FromUUID(kvp.Key);
1862 osdname["is_display_name_default"] = OSD.FromBoolean(true);
1863
1864 agents.Add(osdname);
1865 }
1866
1867 // Full content request
1868 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.OK;
1869 //httpResponse.ContentLength = ??;
1870 httpResponse.ContentType = "application/llsd+xml";
1871
1872 string reply = OSDParser.SerializeLLSDXmlString(osdReply);
1873 return reply;
1874 }
1875 }
1876
1877 public class AssetUploader
1878 {
1879 private static readonly ILog m_log =
1880 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
1881
1882
1883 public event UpLoadedAsset OnUpLoad;
1884 private UpLoadedAsset handlerUpLoad = null;
1885
1886 private string uploaderPath = String.Empty;
1887 private UUID newAssetID;
1888 private UUID inventoryItemID;
1889 private UUID parentFolder;
1890 private IHttpServer httpListener;
1891 private bool m_dumpAssetsToFile;
1892 private string m_assetName = String.Empty;
1893 private string m_assetDes = String.Empty;
1894
1895 private string m_invType = String.Empty;
1896 private string m_assetType = String.Empty;
1897 private int m_cost;
1898 private string m_error = String.Empty;
1899
1900 private Timer m_timeoutTimer = new Timer();
1901 private UUID m_texturesFolder;
1902 private int m_nreqtextures;
1903 private int m_nreqmeshs;
1904 private int m_nreqinstances;
1905 private bool m_IsAtestUpload;
1906
1907 private int m_nextOwnerMask;
1908 private int m_groupMask;
1909 private int m_everyoneMask;
1910
1911
1912 public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem,
1913 UUID parentFolderID, string invType, string assetType, string path,
1914 IHttpServer httpServer, bool dumpAssetsToFile,
1915 int totalCost, UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances,
1916 bool IsAtestUpload, int nextOwnerMask, int groupMask, int everyoneMask)
1917 {
1918 m_assetName = assetName;
1919 m_assetDes = description;
1920 newAssetID = assetID;
1921 inventoryItemID = inventoryItem;
1922 uploaderPath = path;
1923 httpListener = httpServer;
1924 parentFolder = parentFolderID;
1925 m_assetType = assetType;
1926 m_invType = invType;
1927 m_dumpAssetsToFile = dumpAssetsToFile;
1928 m_cost = totalCost;
1929
1930 m_texturesFolder = texturesFolder;
1931 m_nreqtextures = nreqtextures;
1932 m_nreqmeshs = nreqmeshs;
1933 m_nreqinstances = nreqinstances;
1934 m_IsAtestUpload = IsAtestUpload;
1935
1936 m_timeoutTimer.Elapsed += TimedOut;
1937 m_timeoutTimer.Interval = 120000;
1938 m_timeoutTimer.AutoReset = false;
1939 m_timeoutTimer.Start();
1940
1941 m_nextOwnerMask = nextOwnerMask;
1942 m_groupMask = groupMask;
1943 m_everyoneMask = everyoneMask;
1944 }
1945
1946 /// <summary>
1947 /// Handle raw asset upload data via the capability.
1948 /// </summary>
1949 /// <param name="data"></param>
1950 /// <param name="path"></param>
1951 /// <param name="param"></param>
1952 /// <returns></returns>
1953 public string uploaderCaps(byte[] data, string path, string param)
1954 {
1955 UUID inv = inventoryItemID;
1956 string res = String.Empty;
1957 LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete();
1958/*
1959 uploadComplete.new_asset = newAssetID.ToString();
1960 uploadComplete.new_inventory_item = inv;
1961 uploadComplete.state = "complete";
1962
1963 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
1964*/
1965 m_timeoutTimer.Stop();
1966 httpListener.RemoveStreamHandler("POST", uploaderPath);
1967
1968 // TODO: probably make this a better set of extensions here
1969 string extension = ".jp2";
1970 if (m_invType != "image")
1971 {
1972 extension = ".dat";
1973 }
1974
1975 if (m_dumpAssetsToFile)
1976 {
1977 SaveAssetToFile(m_assetName + extension, data);
1978 }
1979 handlerUpLoad = OnUpLoad;
1980 if (handlerUpLoad != null)
1981 {
1982 handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType,
1983 m_cost, m_texturesFolder, m_nreqtextures, m_nreqmeshs, m_nreqinstances, m_IsAtestUpload,
1984 ref m_error, ref m_nextOwnerMask, ref m_groupMask, ref m_everyoneMask);
1985 }
1986
1987 uploadComplete.new_next_owner_mask = m_nextOwnerMask;
1988 uploadComplete.new_group_mask = m_groupMask;
1989 uploadComplete.new_everyone_mask = m_everyoneMask;
1990
1991 if (m_IsAtestUpload)
1992 {
1993 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
1994 resperror.message = "Upload SUCESSEFULL for testing purposes only. Other uses are prohibited. Item will not work after 48 hours or on other regions";
1995 resperror.identifier = inv;
1996
1997 uploadComplete.error = resperror;
1998 uploadComplete.state = "Upload4Testing";
1999 }
2000 else
2001 {
2002 if (m_error == String.Empty)
2003 {
2004 uploadComplete.new_asset = newAssetID.ToString();
2005 uploadComplete.new_inventory_item = inv;
2006 // if (m_texturesFolder != UUID.Zero)
2007 // uploadComplete.new_texture_folder_id = m_texturesFolder;
2008 uploadComplete.state = "complete";
2009 }
2010 else
2011 {
2012 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
2013 resperror.message = m_error;
2014 resperror.identifier = inv;
2015
2016 uploadComplete.error = resperror;
2017 uploadComplete.state = "failed";
2018 }
2019 }
2020
2021 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
2022 return res;
2023 }
2024
2025 private void TimedOut(object sender, ElapsedEventArgs args)
2026 {
2027 m_log.InfoFormat("[CAPS]: Removing URL and handler for timed out mesh upload");
2028 httpListener.RemoveStreamHandler("POST", uploaderPath);
2029 }
2030
2031 ///Left this in and commented in case there are unforseen issues
2032 //private void SaveAssetToFile(string filename, byte[] data)
2033 //{
2034 // FileStream fs = File.Create(filename);
2035 // BinaryWriter bw = new BinaryWriter(fs);
2036 // bw.Write(data);
2037 // bw.Close();
2038 // fs.Close();
2039 //}
2040
2041 private static void SaveAssetToFile(string filename, byte[] data)
2042 {
2043 string assetPath = "UserAssets";
2044 if (!Directory.Exists(assetPath))
2045 {
2046 Directory.CreateDirectory(assetPath);
2047 }
2048 FileStream fs = File.Create(Path.Combine(assetPath, Util.safeFileName(filename)));
2049 BinaryWriter bw = new BinaryWriter(fs);
2050 bw.Write(data);
2051 bw.Close();
2052 fs.Close();
2053 }
2054 }
2055
2056 /// <summary>
2057 /// This class is a callback invoked when a client sends asset data to
2058 /// an agent inventory notecard update url
2059 /// </summary>
2060 public class ItemUpdater
2061 {
2062 public event UpdateItem OnUpLoad;
2063
2064 private UpdateItem handlerUpdateItem = null;
2065
2066 private string uploaderPath = String.Empty;
2067 private UUID inventoryItemID;
2068 private IHttpServer httpListener;
2069 private bool m_dumpAssetToFile;
2070
2071 public ItemUpdater(UUID inventoryItem, string path, IHttpServer httpServer, bool dumpAssetToFile)
2072 {
2073 m_dumpAssetToFile = dumpAssetToFile;
2074
2075 inventoryItemID = inventoryItem;
2076 uploaderPath = path;
2077 httpListener = httpServer;
2078 }
2079
2080 /// <summary>
2081 /// Handle raw uploaded asset data.
2082 /// </summary>
2083 /// <param name="data"></param>
2084 /// <param name="path"></param>
2085 /// <param name="param"></param>
2086 /// <returns></returns>
2087 public string uploaderCaps(byte[] data, string path, string param)
2088 {
2089 UUID inv = inventoryItemID;
2090 string res = String.Empty;
2091 LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete();
2092 UUID assetID = UUID.Zero;
2093 handlerUpdateItem = OnUpLoad;
2094 if (handlerUpdateItem != null)
2095 {
2096 assetID = handlerUpdateItem(inv, data);
2097 }
2098
2099 uploadComplete.new_asset = assetID.ToString();
2100 uploadComplete.new_inventory_item = inv;
2101 uploadComplete.state = "complete";
2102
2103 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
2104
2105 httpListener.RemoveStreamHandler("POST", uploaderPath);
2106
2107 if (m_dumpAssetToFile)
2108 {
2109 SaveAssetToFile("updateditem" + Util.RandomClass.Next(1, 1000) + ".dat", data);
2110 }
2111
2112 return res;
2113 }
2114
2115 ///Left this in and commented in case there are unforseen issues
2116 //private void SaveAssetToFile(string filename, byte[] data)
2117 //{
2118 // FileStream fs = File.Create(filename);
2119 // BinaryWriter bw = new BinaryWriter(fs);
2120 // bw.Write(data);
2121 // bw.Close();
2122 // fs.Close();
2123 //}
2124
2125 private static void SaveAssetToFile(string filename, byte[] data)
2126 {
2127 string assetPath = "UserAssets";
2128 if (!Directory.Exists(assetPath))
2129 {
2130 Directory.CreateDirectory(assetPath);
2131 }
2132 FileStream fs = File.Create(Path.Combine(assetPath, filename));
2133 BinaryWriter bw = new BinaryWriter(fs);
2134 bw.Write(data);
2135 bw.Close();
2136 fs.Close();
2137 }
2138 }
2139
2140 /// <summary>
2141 /// This class is a callback invoked when a client sends asset data to
2142 /// a task inventory script update url
2143 /// </summary>
2144 public class TaskInventoryScriptUpdater
2145 {
2146 private static readonly ILog m_log =
2147 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
2148
2149 public event UpdateTaskScript OnUpLoad;
2150
2151 private UpdateTaskScript handlerUpdateTaskScript = null;
2152
2153 private string uploaderPath = String.Empty;
2154 private UUID inventoryItemID;
2155 private UUID primID;
2156 private bool isScriptRunning;
2157 private IHttpServer httpListener;
2158 private bool m_dumpAssetToFile;
2159
2160 public TaskInventoryScriptUpdater(UUID inventoryItemID, UUID primID, int isScriptRunning,
2161 string path, IHttpServer httpServer, bool dumpAssetToFile)
2162 {
2163 m_dumpAssetToFile = dumpAssetToFile;
2164
2165 this.inventoryItemID = inventoryItemID;
2166 this.primID = primID;
2167
2168 // This comes in over the packet as an integer, but actually appears to be treated as a bool
2169 this.isScriptRunning = (0 == isScriptRunning ? false : true);
2170
2171 uploaderPath = path;
2172 httpListener = httpServer;
2173 }
2174
2175 /// <summary>
2176 ///
2177 /// </summary>
2178 /// <param name="data"></param>
2179 /// <param name="path"></param>
2180 /// <param name="param"></param>
2181 /// <returns></returns>
2182 public string uploaderCaps(byte[] data, string path, string param)
2183 {
2184 try
2185 {
2186 // m_log.InfoFormat("[CAPS]: " +
2187 // "TaskInventoryScriptUpdater received data: {0}, path: {1}, param: {2}",
2188 // data, path, param));
2189
2190 string res = String.Empty;
2191 LLSDTaskScriptUploadComplete uploadComplete = new LLSDTaskScriptUploadComplete();
2192
2193 ArrayList errors = new ArrayList();
2194 handlerUpdateTaskScript = OnUpLoad;
2195 if (handlerUpdateTaskScript != null)
2196 {
2197 handlerUpdateTaskScript(inventoryItemID, primID, isScriptRunning, data, ref errors);
2198 }
2199
2200 uploadComplete.new_asset = inventoryItemID;
2201 uploadComplete.compiled = errors.Count > 0 ? false : true;
2202 uploadComplete.state = "complete";
2203 uploadComplete.errors = new OpenSim.Framework.Capabilities.OSDArray();
2204 uploadComplete.errors.Array = errors;
2205
2206 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
2207
2208 httpListener.RemoveStreamHandler("POST", uploaderPath);
2209
2210 if (m_dumpAssetToFile)
2211 {
2212 SaveAssetToFile("updatedtaskscript" + Util.RandomClass.Next(1, 1000) + ".dat", data);
2213 }
2214
2215 // m_log.InfoFormat("[CAPS]: TaskInventoryScriptUpdater.uploaderCaps res: {0}", res);
2216
2217 return res;
2218 }
2219 catch (Exception e)
2220 {
2221 m_log.Error("[CAPS]: " + e.ToString());
2222 }
2223
2224 // XXX Maybe this should be some meaningful error packet
2225 return null;
2226 }
2227
2228 ///Left this in and commented in case there are unforseen issues
2229 //private void SaveAssetToFile(string filename, byte[] data)
2230 //{
2231 // FileStream fs = File.Create(filename);
2232 // BinaryWriter bw = new BinaryWriter(fs);
2233 // bw.Write(data);
2234 // bw.Close();
2235 // fs.Close();
2236 //}
2237 private static void SaveAssetToFile(string filename, byte[] data)
2238 {
2239 string assetPath = "UserAssets";
2240 if (!Directory.Exists(assetPath))
2241 {
2242 Directory.CreateDirectory(assetPath);
2243 }
2244 FileStream fs = File.Create(Path.Combine(assetPath, filename));
2245 BinaryWriter bw = new BinaryWriter(fs);
2246 bw.Write(data);
2247 bw.Close();
2248 fs.Close();
2249 }
2250 }
2251}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCapsModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCapsModule.cs
new file mode 100644
index 0000000..683c3d5
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCapsModule.cs
@@ -0,0 +1,91 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31
32using log4net;
33using Nini.Config;
34using OpenMetaverse;
35using Mono.Addins;
36
37using OpenSim.Framework;
38using OpenSim.Region.Framework;
39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Region.Framework.Scenes;
41using Caps = OpenSim.Framework.Capabilities.Caps;
42
43[assembly: Addin("LindenCaps", OpenSim.VersionInfo.VersionNumber)]
44[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]
45namespace OpenSim.Region.ClientStack.Linden
46{
47
48 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "BunchOfCapsModule")]
49 public class BunchOfCapsModule : INonSharedRegionModule
50 {
51// private static readonly ILog m_log =
52// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
53
54 private Scene m_Scene;
55
56 #region INonSharedRegionModule
57
58 public string Name { get { return "BunchOfCapsModule"; } }
59
60 public Type ReplaceableInterface { get { return null; } }
61
62 public void Initialise(IConfigSource source)
63 {
64 }
65
66 public void Close() { }
67
68 public void AddRegion(Scene scene)
69 {
70 m_Scene = scene;
71 m_Scene.EventManager.OnRegisterCaps += OnRegisterCaps;
72 }
73
74 public void RemoveRegion(Scene scene)
75 {
76 }
77
78 public void RegionLoaded(Scene scene)
79 {
80 }
81
82 public void PostInitialise() { }
83 #endregion
84
85 private void OnRegisterCaps(UUID agentID, Caps caps)
86 {
87 new BunchOfCaps(m_Scene, agentID, caps);
88 }
89
90 }
91}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs
new file mode 100644
index 0000000..eb1ab45
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs
@@ -0,0 +1,746 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28
29using System;
30using System.IO;
31using System.Collections;
32using System.Collections.Generic;
33using System.Text;
34
35using OpenMetaverse;
36using OpenMetaverse.StructuredData;
37
38using OpenSim.Framework;
39using OpenSim.Region.Framework;
40using OpenSim.Region.Framework.Scenes;
41using OpenSim.Framework.Capabilities;
42
43using ComponentAce.Compression.Libs.zlib;
44
45using OSDArray = OpenMetaverse.StructuredData.OSDArray;
46using OSDMap = OpenMetaverse.StructuredData.OSDMap;
47
48using Nini.Config;
49
50namespace OpenSim.Region.ClientStack.Linden
51{
52 public struct ModelPrimLimits
53 {
54
55 }
56
57 public class ModelCost
58 {
59
60 // upload fee defaults
61 // fees are normalized to 1.0
62 // this parameters scale them to basic cost ( so 1.0 translates to 10 )
63
64 public float ModelMeshCostFactor = 0.0f; // scale total cost relative to basic (excluding textures)
65 public float ModelTextureCostFactor = 1.0f; // scale textures fee to basic.
66 public float ModelMinCostFactor = 0.0f; // 0.5f; // minimum total model free excluding textures
67
68 // itens costs in normalized values
69 // ie will be multiplied by basicCost and factors above
70 public float primCreationCost = 0.002f; // extra cost for each prim creation overhead
71 // weigthed size to normalized cost
72 public float bytecost = 1e-5f;
73
74 // mesh upload fees based on compressed data sizes
75 // several data sections are counted more that once
76 // to promote user optimization
77 // following parameters control how many extra times they are added
78 // to global size.
79 // LOD meshs
80 const float medSizeWth = 1f; // 2x
81 const float lowSizeWth = 1.5f; // 2.5x
82 const float lowestSizeWth = 2f; // 3x
83 // favor potencially physical optimized meshs versus automatic decomposition
84 const float physMeshSizeWth = 6f; // counts 7x
85 const float physHullSizeWth = 8f; // counts 9x
86
87 // stream cost area factors
88 // more or less like SL
89 const float highLodFactor = 17.36f;
90 const float midLodFactor = 277.78f;
91 const float lowLodFactor = 1111.11f;
92
93 // physics cost is below, identical to SL, assuming shape type convex
94 // server cost is below identical to SL assuming non scripted non physical object
95
96 // internal
97 const int bytesPerCoord = 6; // 3 coords, 2 bytes per each
98
99 // control prims dimensions
100 public float PrimScaleMin = 0.001f;
101 public float NonPhysicalPrimScaleMax = 256f;
102 public float PhysicalPrimScaleMax = 10f;
103 public int ObjectLinkedPartsMax = 512;
104
105
106 public ModelCost(Scene scene)
107 {
108 PrimScaleMin = scene.m_minNonphys;
109 NonPhysicalPrimScaleMax = scene.m_maxNonphys;
110 PhysicalPrimScaleMax = scene.m_maxPhys;
111 ObjectLinkedPartsMax = scene.m_linksetCapacity;
112 }
113
114 public void Econfig(IConfig EconomyConfig)
115 {
116 ModelMeshCostFactor = EconomyConfig.GetFloat("MeshModelUploadCostFactor", ModelMeshCostFactor);
117 ModelTextureCostFactor = EconomyConfig.GetFloat("MeshModelUploadTextureCostFactor", ModelTextureCostFactor);
118 ModelMinCostFactor = EconomyConfig.GetFloat("MeshModelMinCostFactor", ModelMinCostFactor);
119 // next 2 are normalized so final cost is afected by modelUploadFactor above and normal cost
120 primCreationCost = EconomyConfig.GetFloat("ModelPrimCreationCost", primCreationCost);
121 bytecost = EconomyConfig.GetFloat("ModelMeshByteCost", bytecost);
122 }
123
124 // storage for a single mesh asset cost parameters
125 private class ameshCostParam
126 {
127 // LOD sizes for size dependent streaming cost
128 public int highLODSize;
129 public int medLODSize;
130 public int lowLODSize;
131 public int lowestLODSize;
132 // normalized fee based on compressed data sizes
133 public float costFee;
134 // physics cost
135 public float physicsCost;
136 }
137
138 // calculates a mesh model costs
139 // returns false on error, with a reason on parameter error
140 // resources input LLSD request
141 // basicCost input region assets upload cost
142 // totalcost returns model total upload fee
143 // meshcostdata returns detailed costs for viewer
144 // avatarSkeleton if mesh includes a avatar skeleton
145 // useAvatarCollider if we should use physics mesh for avatar
146 public bool MeshModelCost(LLSDAssetResource resources, int basicCost, out int totalcost,
147 LLSDAssetUploadResponseData meshcostdata, out string error, ref string warning)
148 {
149 totalcost = 0;
150 error = string.Empty;
151
152 bool avatarSkeleton = false;
153
154 if (resources == null ||
155 resources.instance_list == null ||
156 resources.instance_list.Array.Count == 0)
157 {
158 error = "missing model information.";
159 return false;
160 }
161
162 int numberInstances = resources.instance_list.Array.Count;
163
164 if (ObjectLinkedPartsMax != 0 && numberInstances > ObjectLinkedPartsMax)
165 {
166 error = "Model would have more than " + ObjectLinkedPartsMax.ToString() + " linked prims";
167 return false;
168 }
169
170 meshcostdata.model_streaming_cost = 0.0;
171 meshcostdata.simulation_cost = 0.0;
172 meshcostdata.physics_cost = 0.0;
173 meshcostdata.resource_cost = 0.0;
174
175 meshcostdata.upload_price_breakdown.mesh_instance = 0;
176 meshcostdata.upload_price_breakdown.mesh_physics = 0;
177 meshcostdata.upload_price_breakdown.mesh_streaming = 0;
178 meshcostdata.upload_price_breakdown.model = 0;
179
180 int itmp;
181
182 // textures cost
183 if (resources.texture_list != null && resources.texture_list.Array.Count > 0)
184 {
185 float textures_cost = (float)(resources.texture_list.Array.Count * basicCost);
186 textures_cost *= ModelTextureCostFactor;
187
188 itmp = (int)(textures_cost + 0.5f); // round
189 meshcostdata.upload_price_breakdown.texture = itmp;
190 totalcost += itmp;
191 }
192
193 // meshs assets cost
194 float meshsfee = 0;
195 int numberMeshs = 0;
196 bool haveMeshs = false;
197
198 bool curskeleton;
199 bool curAvatarPhys;
200
201 List<ameshCostParam> meshsCosts = new List<ameshCostParam>();
202
203 if (resources.mesh_list != null && resources.mesh_list.Array.Count > 0)
204 {
205 numberMeshs = resources.mesh_list.Array.Count;
206
207 for (int i = 0; i < numberMeshs; i++)
208 {
209 ameshCostParam curCost = new ameshCostParam();
210 byte[] data = (byte[])resources.mesh_list.Array[i];
211
212 if (!MeshCost(data, curCost,out curskeleton, out curAvatarPhys, out error))
213 {
214 return false;
215 }
216
217 if (curskeleton)
218 {
219 if (avatarSkeleton)
220 {
221 error = "model can only contain a avatar skeleton";
222 return false;
223 }
224 avatarSkeleton = true;
225 }
226 meshsCosts.Add(curCost);
227 meshsfee += curCost.costFee;
228 }
229 haveMeshs = true;
230 }
231
232 // instances (prims) cost
233
234
235 int mesh;
236 int skipedSmall = 0;
237 for (int i = 0; i < numberInstances; i++)
238 {
239 Hashtable inst = (Hashtable)resources.instance_list.Array[i];
240
241 ArrayList ascale = (ArrayList)inst["scale"];
242 Vector3 scale;
243 double tmp;
244 tmp = (double)ascale[0];
245 scale.X = (float)tmp;
246 tmp = (double)ascale[1];
247 scale.Y = (float)tmp;
248 tmp = (double)ascale[2];
249 scale.Z = (float)tmp;
250
251 if (scale.X < PrimScaleMin || scale.Y < PrimScaleMin || scale.Z < PrimScaleMin)
252 {
253 skipedSmall++;
254 continue;
255 }
256
257 if (scale.X > NonPhysicalPrimScaleMax || scale.Y > NonPhysicalPrimScaleMax || scale.Z > NonPhysicalPrimScaleMax)
258 {
259 error = "Model contains parts with sides larger than " + NonPhysicalPrimScaleMax.ToString() + "m. Please ajust scale";
260 return false;
261 }
262
263 if (haveMeshs && inst.ContainsKey("mesh"))
264 {
265 mesh = (int)inst["mesh"];
266
267 if (mesh >= numberMeshs)
268 {
269 error = "Incoerent model information.";
270 return false;
271 }
272
273 // streamming cost
274
275 float sqdiam = scale.LengthSquared();
276
277 ameshCostParam curCost = meshsCosts[mesh];
278 float mesh_streaming = streamingCost(curCost, sqdiam);
279
280 meshcostdata.model_streaming_cost += mesh_streaming;
281 meshcostdata.physics_cost += curCost.physicsCost;
282 }
283 else // instance as no mesh ??
284 {
285 // to do later if needed
286 meshcostdata.model_streaming_cost += 0.5f;
287 meshcostdata.physics_cost += 1.0f;
288 }
289
290 // assume unscripted and static prim server cost
291 meshcostdata.simulation_cost += 0.5f;
292 // charge for prims creation
293 meshsfee += primCreationCost;
294 }
295
296 if (skipedSmall > 0)
297 {
298 if (skipedSmall > numberInstances / 2)
299 {
300 error = "Model contains too many prims smaller than " + PrimScaleMin.ToString() +
301 "m minimum allowed size. Please check scalling";
302 return false;
303 }
304 else
305 warning += skipedSmall.ToString() + " of the requested " +numberInstances.ToString() +
306 " model prims will not upload because they are smaller than " + PrimScaleMin.ToString() +
307 "m minimum allowed size. Please check scalling ";
308 }
309
310 if (meshcostdata.physics_cost <= meshcostdata.model_streaming_cost)
311 meshcostdata.resource_cost = meshcostdata.model_streaming_cost;
312 else
313 meshcostdata.resource_cost = meshcostdata.physics_cost;
314
315 if (meshcostdata.resource_cost < meshcostdata.simulation_cost)
316 meshcostdata.resource_cost = meshcostdata.simulation_cost;
317
318 // scale cost
319 // at this point a cost of 1.0 whould mean basic cost
320 meshsfee *= ModelMeshCostFactor;
321
322 if (meshsfee < ModelMinCostFactor)
323 meshsfee = ModelMinCostFactor;
324
325 // actually scale it to basic cost
326 meshsfee *= (float)basicCost;
327
328 meshsfee += 0.5f; // rounding
329
330 totalcost += (int)meshsfee;
331
332 // breakdown prices
333 // don't seem to be in use so removed code for now
334
335 return true;
336 }
337
338 // single mesh asset cost
339 private bool MeshCost(byte[] data, ameshCostParam cost,out bool skeleton, out bool avatarPhys, out string error)
340 {
341 cost.highLODSize = 0;
342 cost.medLODSize = 0;
343 cost.lowLODSize = 0;
344 cost.lowestLODSize = 0;
345 cost.physicsCost = 0.0f;
346 cost.costFee = 0.0f;
347
348 error = string.Empty;
349
350 skeleton = false;
351 avatarPhys = false;
352
353 if (data == null || data.Length == 0)
354 {
355 error = "Missing model information.";
356 return false;
357 }
358
359 OSD meshOsd = null;
360 int start = 0;
361
362 error = "Invalid model data";
363
364 using (MemoryStream ms = new MemoryStream(data))
365 {
366 try
367 {
368 OSD osd = OSDParser.DeserializeLLSDBinary(ms);
369 if (osd is OSDMap)
370 meshOsd = (OSDMap)osd;
371 else
372 return false;
373 }
374 catch
375 {
376 return false;
377 }
378 start = (int)ms.Position;
379 }
380
381 OSDMap map = (OSDMap)meshOsd;
382 OSDMap tmpmap;
383
384 int highlod_size = 0;
385 int medlod_size = 0;
386 int lowlod_size = 0;
387 int lowestlod_size = 0;
388 int skin_size = 0;
389
390 int hulls_size = 0;
391 int phys_nhulls;
392 int phys_hullsvertices = 0;
393
394 int physmesh_size = 0;
395 int phys_ntriangles = 0;
396
397 int submesh_offset = -1;
398
399 if (map.ContainsKey("skeleton"))
400 {
401 tmpmap = (OSDMap)map["skeleton"];
402 if (tmpmap.ContainsKey("offset") && tmpmap.ContainsKey("size"))
403 {
404 int sksize = tmpmap["size"].AsInteger();
405 if(sksize > 0)
406 skeleton = true;
407 }
408 }
409
410 if (map.ContainsKey("physics_convex"))
411 {
412 tmpmap = (OSDMap)map["physics_convex"];
413 if (tmpmap.ContainsKey("offset"))
414 submesh_offset = tmpmap["offset"].AsInteger() + start;
415 if (tmpmap.ContainsKey("size"))
416 hulls_size = tmpmap["size"].AsInteger();
417 }
418
419 if (submesh_offset < 0 || hulls_size == 0)
420 {
421 error = "Missing physics_convex block";
422 return false;
423 }
424
425 if (!hulls(data, submesh_offset, hulls_size, out phys_hullsvertices, out phys_nhulls))
426 {
427 error = "Bad physics_convex block";
428 return false;
429 }
430
431 submesh_offset = -1;
432
433 // only look for LOD meshs sizes
434
435 if (map.ContainsKey("high_lod"))
436 {
437 tmpmap = (OSDMap)map["high_lod"];
438 // see at least if there is a offset for this one
439 if (tmpmap.ContainsKey("offset"))
440 submesh_offset = tmpmap["offset"].AsInteger() + start;
441 if (tmpmap.ContainsKey("size"))
442 highlod_size = tmpmap["size"].AsInteger();
443 }
444
445 if (submesh_offset < 0 || highlod_size <= 0)
446 {
447 error = "Missing high_lod block";
448 return false;
449 }
450
451 bool haveprev = true;
452
453 if (map.ContainsKey("medium_lod"))
454 {
455 tmpmap = (OSDMap)map["medium_lod"];
456 if (tmpmap.ContainsKey("size"))
457 medlod_size = tmpmap["size"].AsInteger();
458 else
459 haveprev = false;
460 }
461
462 if (haveprev && map.ContainsKey("low_lod"))
463 {
464 tmpmap = (OSDMap)map["low_lod"];
465 if (tmpmap.ContainsKey("size"))
466 lowlod_size = tmpmap["size"].AsInteger();
467 else
468 haveprev = false;
469 }
470
471 if (haveprev && map.ContainsKey("lowest_lod"))
472 {
473 tmpmap = (OSDMap)map["lowest_lod"];
474 if (tmpmap.ContainsKey("size"))
475 lowestlod_size = tmpmap["size"].AsInteger();
476 }
477
478 if (map.ContainsKey("skin"))
479 {
480 tmpmap = (OSDMap)map["skin"];
481 if (tmpmap.ContainsKey("size"))
482 skin_size = tmpmap["size"].AsInteger();
483 }
484
485 cost.highLODSize = highlod_size;
486 cost.medLODSize = medlod_size;
487 cost.lowLODSize = lowlod_size;
488 cost.lowestLODSize = lowestlod_size;
489
490 submesh_offset = -1;
491
492 tmpmap = null;
493 if(map.ContainsKey("physics_mesh"))
494 tmpmap = (OSDMap)map["physics_mesh"];
495 else if (map.ContainsKey("physics_shape")) // old naming
496 tmpmap = (OSDMap)map["physics_shape"];
497
498 if(tmpmap != null)
499 {
500 if (tmpmap.ContainsKey("offset"))
501 submesh_offset = tmpmap["offset"].AsInteger() + start;
502 if (tmpmap.ContainsKey("size"))
503 physmesh_size = tmpmap["size"].AsInteger();
504
505 if (submesh_offset >= 0 || physmesh_size > 0)
506 {
507
508 if (!submesh(data, submesh_offset, physmesh_size, out phys_ntriangles))
509 {
510 error = "Model data parsing error";
511 return false;
512 }
513 }
514 }
515
516 // upload is done in convex shape type so only one hull
517 phys_hullsvertices++;
518 cost.physicsCost = 0.04f * phys_hullsvertices;
519
520 float sfee;
521
522 sfee = data.Length; // start with total compressed data size
523
524 // penalize lod meshs that should be more builder optimized
525 sfee += medSizeWth * medlod_size;
526 sfee += lowSizeWth * lowlod_size;
527 sfee += lowestSizeWth * lowlod_size;
528
529 // physics
530 // favor potencial optimized meshs versus automatic decomposition
531 if (physmesh_size != 0)
532 sfee += physMeshSizeWth * (physmesh_size + hulls_size / 4); // reduce cost of mandatory convex hull
533 else
534 sfee += physHullSizeWth * hulls_size;
535
536 // bytes to money
537 sfee *= bytecost;
538
539 cost.costFee = sfee;
540 return true;
541 }
542
543 // parses a LOD or physics mesh component
544 private bool submesh(byte[] data, int offset, int size, out int ntriangles)
545 {
546 ntriangles = 0;
547
548 OSD decodedMeshOsd = new OSD();
549 byte[] meshBytes = new byte[size];
550 System.Buffer.BlockCopy(data, offset, meshBytes, 0, size);
551 try
552 {
553 using (MemoryStream inMs = new MemoryStream(meshBytes))
554 {
555 using (MemoryStream outMs = new MemoryStream())
556 {
557 using (ZOutputStream zOut = new ZOutputStream(outMs))
558 {
559 byte[] readBuffer = new byte[4096];
560 int readLen = 0;
561 while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0)
562 {
563 zOut.Write(readBuffer, 0, readLen);
564 }
565 zOut.Flush();
566 outMs.Seek(0, SeekOrigin.Begin);
567
568 byte[] decompressedBuf = outMs.GetBuffer();
569 decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf);
570 }
571 }
572 }
573 }
574 catch
575 {
576 return false;
577 }
578
579 OSDArray decodedMeshOsdArray = null;
580
581 byte[] dummy;
582
583 decodedMeshOsdArray = (OSDArray)decodedMeshOsd;
584 foreach (OSD subMeshOsd in decodedMeshOsdArray)
585 {
586 if (subMeshOsd is OSDMap)
587 {
588 OSDMap subtmpmap = (OSDMap)subMeshOsd;
589 if (subtmpmap.ContainsKey("NoGeometry") && ((OSDBoolean)subtmpmap["NoGeometry"]))
590 continue;
591
592 if (!subtmpmap.ContainsKey("Position"))
593 return false;
594
595 if (subtmpmap.ContainsKey("TriangleList"))
596 {
597 dummy = subtmpmap["TriangleList"].AsBinary();
598 ntriangles += dummy.Length / bytesPerCoord;
599 }
600 else
601 return false;
602 }
603 }
604
605 return true;
606 }
607
608 // parses convex hulls component
609 private bool hulls(byte[] data, int offset, int size, out int nvertices, out int nhulls)
610 {
611 nvertices = 0;
612 nhulls = 1;
613
614 OSD decodedMeshOsd = new OSD();
615 byte[] meshBytes = new byte[size];
616 System.Buffer.BlockCopy(data, offset, meshBytes, 0, size);
617 try
618 {
619 using (MemoryStream inMs = new MemoryStream(meshBytes))
620 {
621 using (MemoryStream outMs = new MemoryStream())
622 {
623 using (ZOutputStream zOut = new ZOutputStream(outMs))
624 {
625 byte[] readBuffer = new byte[4096];
626 int readLen = 0;
627 while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0)
628 {
629 zOut.Write(readBuffer, 0, readLen);
630 }
631 zOut.Flush();
632 outMs.Seek(0, SeekOrigin.Begin);
633
634 byte[] decompressedBuf = outMs.GetBuffer();
635 decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf);
636 }
637 }
638 }
639 }
640 catch
641 {
642 return false;
643 }
644
645 OSDMap cmap = (OSDMap)decodedMeshOsd;
646 if (cmap == null)
647 return false;
648
649 byte[] dummy;
650
651 // must have one of this
652 if (cmap.ContainsKey("BoundingVerts"))
653 {
654 dummy = cmap["BoundingVerts"].AsBinary();
655 nvertices = dummy.Length / bytesPerCoord;
656 }
657 else
658 return false;
659
660/* upload is done with convex shape type
661 if (cmap.ContainsKey("HullList"))
662 {
663 dummy = cmap["HullList"].AsBinary();
664 nhulls += dummy.Length;
665 }
666
667
668 if (cmap.ContainsKey("Positions"))
669 {
670 dummy = cmap["Positions"].AsBinary();
671 nvertices = dummy.Length / bytesPerCoord;
672 }
673 */
674
675 return true;
676 }
677
678 // returns streaming cost from on mesh LODs sizes in curCost and square of prim size length
679 private float streamingCost(ameshCostParam curCost, float sqdiam)
680 {
681 // compute efective areas
682 float ma = 262144f;
683
684 float mh = sqdiam * highLodFactor;
685 if (mh > ma)
686 mh = ma;
687 float mm = sqdiam * midLodFactor;
688 if (mm > ma)
689 mm = ma;
690
691 float ml = sqdiam * lowLodFactor;
692 if (ml > ma)
693 ml = ma;
694
695 float mlst = ma;
696
697 mlst -= ml;
698 ml -= mm;
699 mm -= mh;
700
701 if (mlst < 1.0f)
702 mlst = 1.0f;
703 if (ml < 1.0f)
704 ml = 1.0f;
705 if (mm < 1.0f)
706 mm = 1.0f;
707 if (mh < 1.0f)
708 mh = 1.0f;
709
710 ma = mlst + ml + mm + mh;
711
712 // get LODs compressed sizes
713 // giving 384 bytes bonus
714 int lst = curCost.lowestLODSize - 384;
715 int l = curCost.lowLODSize - 384;
716 int m = curCost.medLODSize - 384;
717 int h = curCost.highLODSize - 384;
718
719 // use previus higher LOD size on missing ones
720 if (m <= 0)
721 m = h;
722 if (l <= 0)
723 l = m;
724 if (lst <= 0)
725 lst = l;
726
727 // force minumum sizes
728 if (lst < 16)
729 lst = 16;
730 if (l < 16)
731 l = 16;
732 if (m < 16)
733 m = 16;
734 if (h < 16)
735 h = 16;
736
737 // compute cost weighted by relative effective areas
738 float cost = (float)lst * mlst + (float)l * ml + (float)m * mm + (float)h * mh;
739 cost /= ma;
740
741 cost *= 0.004f; // overall tunning parameter
742
743 return cost;
744 }
745 }
746}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
new file mode 100644
index 0000000..7c9a1c4
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
@@ -0,0 +1,623 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Net;
32using System.Reflection;
33using System.Threading;
34using log4net;
35using Nini.Config;
36using Mono.Addins;
37using OpenMetaverse;
38using OpenMetaverse.Messages.Linden;
39using OpenMetaverse.Packets;
40using OpenMetaverse.StructuredData;
41using OpenSim.Framework;
42using OpenSim.Framework.Console;
43using OpenSim.Framework.Servers;
44using OpenSim.Framework.Servers.HttpServer;
45using OpenSim.Region.Framework.Interfaces;
46using OpenSim.Region.Framework.Scenes;
47using BlockingLLSDQueue = OpenSim.Framework.BlockingQueue<OpenMetaverse.StructuredData.OSD>;
48using Caps=OpenSim.Framework.Capabilities.Caps;
49
50namespace OpenSim.Region.ClientStack.Linden
51{
52 public struct QueueItem
53 {
54 public int id;
55 public OSDMap body;
56 }
57
58 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "EventQueueGetModule")]
59 public class EventQueueGetModule : IEventQueue, INonSharedRegionModule
60 {
61 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
62 private static string LogHeader = "[EVENT QUEUE GET MODULE]";
63
64 /// <value>
65 /// Debug level.
66 /// </value>
67 public int DebugLevel { get; set; }
68
69 // Viewer post requests timeout in 60 secs
70 // https://bitbucket.org/lindenlab/viewer-release/src/421c20423df93d650cc305dc115922bb30040999/indra/llmessage/llhttpclient.cpp?at=default#cl-44
71 //
72 private const int VIEWER_TIMEOUT = 60 * 1000;
73 // Just to be safe, we work on a 10 sec shorter cycle
74 private const int SERVER_EQ_TIME_NO_EVENTS = VIEWER_TIMEOUT - (10 * 1000);
75
76 protected Scene m_scene;
77
78 private Dictionary<UUID, int> m_ids = new Dictionary<UUID, int>();
79
80 private Dictionary<UUID, Queue<OSD>> queues = new Dictionary<UUID, Queue<OSD>>();
81 private Dictionary<UUID, UUID> m_AvatarQueueUUIDMapping = new Dictionary<UUID, UUID>();
82
83 #region INonSharedRegionModule methods
84 public virtual void Initialise(IConfigSource config)
85 {
86 }
87
88 public void AddRegion(Scene scene)
89 {
90 m_scene = scene;
91 scene.RegisterModuleInterface<IEventQueue>(this);
92
93 scene.EventManager.OnClientClosed += ClientClosed;
94 scene.EventManager.OnRegisterCaps += OnRegisterCaps;
95
96 MainConsole.Instance.Commands.AddCommand(
97 "Debug",
98 false,
99 "debug eq",
100 "debug eq [0|1|2]",
101 "Turn on event queue debugging\n"
102 + " <= 0 - turns off all event queue logging\n"
103 + " >= 1 - turns on event queue setup and outgoing event logging\n"
104 + " >= 2 - turns on poll notification",
105 HandleDebugEq);
106
107 MainConsole.Instance.Commands.AddCommand(
108 "Debug",
109 false,
110 "show eq",
111 "show eq",
112 "Show contents of event queues for logged in avatars. Used for debugging.",
113 HandleShowEq);
114 }
115
116 public void RemoveRegion(Scene scene)
117 {
118 if (m_scene != scene)
119 return;
120
121 scene.EventManager.OnClientClosed -= ClientClosed;
122 scene.EventManager.OnRegisterCaps -= OnRegisterCaps;
123
124 scene.UnregisterModuleInterface<IEventQueue>(this);
125 m_scene = null;
126 }
127
128 public void RegionLoaded(Scene scene)
129 {
130 }
131
132 public virtual void Close()
133 {
134 }
135
136 public virtual string Name
137 {
138 get { return "EventQueueGetModule"; }
139 }
140
141 public Type ReplaceableInterface
142 {
143 get { return null; }
144 }
145
146 #endregion
147
148 protected void HandleDebugEq(string module, string[] args)
149 {
150 int debugLevel;
151
152 if (!(args.Length == 3 && int.TryParse(args[2], out debugLevel)))
153 {
154 MainConsole.Instance.OutputFormat("Usage: debug eq [0|1|2]");
155 }
156 else
157 {
158 DebugLevel = debugLevel;
159 MainConsole.Instance.OutputFormat(
160 "Set event queue debug level to {0} in {1}", DebugLevel, m_scene.RegionInfo.RegionName);
161 }
162 }
163
164 protected void HandleShowEq(string module, string[] args)
165 {
166 MainConsole.Instance.OutputFormat("For scene {0}", m_scene.Name);
167
168 lock (queues)
169 {
170 foreach (KeyValuePair<UUID, Queue<OSD>> kvp in queues)
171 {
172 MainConsole.Instance.OutputFormat(
173 "For agent {0} there are {1} messages queued for send.",
174 kvp.Key, kvp.Value.Count);
175 }
176 }
177 }
178
179 /// <summary>
180 /// Always returns a valid queue
181 /// </summary>
182 /// <param name="agentId"></param>
183 /// <returns></returns>
184 private Queue<OSD> TryGetQueue(UUID agentId)
185 {
186 lock (queues)
187 {
188 if (!queues.ContainsKey(agentId))
189 {
190 if (DebugLevel > 0)
191 m_log.DebugFormat(
192 "[EVENTQUEUE]: Adding new queue for agent {0} in region {1}",
193 agentId, m_scene.RegionInfo.RegionName);
194
195 queues[agentId] = new Queue<OSD>();
196 }
197
198 return queues[agentId];
199 }
200 }
201
202 /// <summary>
203
204 /// May return a null queue
205 /// </summary>
206 /// <param name="agentId"></param>
207 /// <returns></returns>
208 private Queue<OSD> GetQueue(UUID agentId)
209 {
210 lock (queues)
211 {
212 if (queues.ContainsKey(agentId))
213 {
214 return queues[agentId];
215 }
216 else
217 return null;
218 }
219 }
220
221 #region IEventQueue Members
222
223 public bool Enqueue(OSD ev, UUID avatarID)
224 {
225 //m_log.DebugFormat("[EVENTQUEUE]: Enqueuing event for {0} in region {1}", avatarID, m_scene.RegionInfo.RegionName);
226 try
227 {
228 Queue<OSD> queue = GetQueue(avatarID);
229 if (queue != null)
230 {
231 lock (queue)
232 queue.Enqueue(ev);
233 }
234 else
235 {
236 OSDMap evMap = (OSDMap)ev;
237 m_log.WarnFormat(
238 "[EVENTQUEUE]: (Enqueue) No queue found for agent {0} when placing message {1} in region {2}",
239 avatarID, evMap["message"], m_scene.Name);
240 }
241 }
242 catch (NullReferenceException e)
243 {
244 m_log.Error("[EVENTQUEUE] Caught exception: " + e);
245 return false;
246 }
247
248 return true;
249 }
250
251 #endregion
252
253 private void ClientClosed(UUID agentID, Scene scene)
254 {
255 //m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", agentID, m_scene.RegionInfo.RegionName);
256
257 lock (queues)
258 queues.Remove(agentID);
259
260 lock (m_AvatarQueueUUIDMapping)
261 m_AvatarQueueUUIDMapping.Remove(agentID);
262
263 lock (m_ids)
264 {
265 if (!m_ids.ContainsKey(agentID))
266 m_ids.Remove(agentID);
267 }
268
269 // m_log.DebugFormat("[EVENTQUEUE]: Deleted queues for {0} in region {1}", agentID, m_scene.RegionInfo.RegionName);
270
271 }
272
273 /// <summary>
274 /// Generate an Event Queue Get handler path for the given eqg uuid.
275 /// </summary>
276 /// <param name='eqgUuid'></param>
277 private string GenerateEqgCapPath(UUID eqgUuid)
278 {
279 return string.Format("/CAPS/EQG/{0}/", eqgUuid);
280 }
281
282 public void OnRegisterCaps(UUID agentID, Caps caps)
283 {
284 // Register an event queue for the client
285
286 if (DebugLevel > 0)
287 m_log.DebugFormat(
288 "[EVENTQUEUE]: OnRegisterCaps: agentID {0} caps {1} region {2}",
289 agentID, caps, m_scene.RegionInfo.RegionName);
290
291 UUID eventQueueGetUUID;
292 Queue<OSD> queue;
293 Random rnd = new Random(Environment.TickCount);
294 int nrnd = rnd.Next(30000000);
295 if (nrnd < 0)
296 nrnd = -nrnd;
297
298 lock (queues)
299 {
300 if (queues.ContainsKey(agentID))
301 queue = queues[agentID];
302 else
303 queue = null;
304
305 if (queue == null)
306 {
307 queue = new Queue<OSD>();
308 queues[agentID] = queue;
309
310 // push markers to handle old responses still waiting
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 lock (m_AvatarQueueUUIDMapping)
317 {
318 eventQueueGetUUID = UUID.Random();
319 if (m_AvatarQueueUUIDMapping.ContainsKey(agentID))
320 {
321 // oops this should not happen ?
322 m_log.DebugFormat("[EVENTQUEUE]: Found Existing UUID without a queue");
323 eventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID];
324 }
325 m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID);
326 }
327 lock (m_ids)
328 {
329 if (!m_ids.ContainsKey(agentID))
330 m_ids.Add(agentID, nrnd);
331 else
332 m_ids[agentID] = nrnd;
333 }
334 }
335 else
336 {
337 // push markers to handle old responses still waiting
338 // this will cost at most viewer getting two forced noevents
339 // even being a new queue better be safe
340 queue.Enqueue(null);
341 queue.Enqueue(null); // one should be enough
342
343 // reuse or not to reuse TODO FIX
344 lock (m_AvatarQueueUUIDMapping)
345 {
346 // Reuse open queues. The client does!
347 // Its reuse caps path not queues those are been reused already
348 if (m_AvatarQueueUUIDMapping.ContainsKey(agentID))
349 {
350 m_log.DebugFormat("[EVENTQUEUE]: Found Existing UUID!");
351 eventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID];
352 }
353 else
354 {
355 eventQueueGetUUID = UUID.Random();
356 m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID);
357 m_log.DebugFormat("[EVENTQUEUE]: Using random UUID!");
358 }
359 }
360 lock (m_ids)
361 {
362 // change to negative numbers so they are changed at end of sending first marker
363 // old data on a queue may be sent on a response for a new caps
364 // but at least will be sent with coerent IDs
365 if (!m_ids.ContainsKey(agentID))
366 m_ids.Add(agentID, -nrnd); // should not happen
367 else
368 m_ids[agentID] = -m_ids[agentID];
369 }
370 }
371 }
372
373 caps.RegisterPollHandler(
374 "EventQueueGet",
375 new PollServiceEventArgs(null, GenerateEqgCapPath(eventQueueGetUUID), HasEvents, GetEvents, NoEvents, agentID, SERVER_EQ_TIME_NO_EVENTS));
376 }
377
378 public bool HasEvents(UUID requestID, UUID agentID)
379 {
380 Queue<OSD> queue = GetQueue(agentID);
381 if (queue != null)
382 lock (queue)
383 {
384 //m_log.WarnFormat("POLLED FOR EVENTS BY {0} in {1} -- {2}", agentID, m_scene.RegionInfo.RegionName, queue.Count);
385 return queue.Count > 0;
386 }
387
388 //m_log.WarnFormat("POLLED FOR EVENTS BY {0} unknown agent", agentID);
389 return true;
390 }
391
392 /// <summary>
393 /// Logs a debug line for an outbound event queue message if appropriate.
394 /// </summary>
395 /// <param name='element'>Element containing message</param>
396 private void LogOutboundDebugMessage(OSD element, UUID agentId)
397 {
398 if (element is OSDMap)
399 {
400 OSDMap ev = (OSDMap)element;
401 m_log.DebugFormat(
402 "Eq OUT {0,-30} to {1,-20} {2,-20}",
403 ev["message"], m_scene.GetScenePresence(agentId).Name, m_scene.Name);
404 }
405 }
406 public void Drop(UUID requestID, UUID pAgentId)
407 {
408 // do nothing for now, hope client close will do it
409 }
410
411 public Hashtable GetEvents(UUID requestID, UUID pAgentId)
412 {
413 if (DebugLevel >= 2)
414 m_log.WarnFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.Name);
415
416 Queue<OSD> queue = GetQueue(pAgentId);
417 if (queue == null)
418 {
419 return NoEvents(requestID, pAgentId);
420 }
421
422 OSD element = null;;
423 OSDArray array = new OSDArray();
424 int thisID = 0;
425 bool negativeID = false;
426
427 lock (queue)
428 {
429 if (queue.Count == 0)
430 return NoEvents(requestID, pAgentId);
431
432 lock (m_ids)
433 thisID = m_ids[pAgentId];
434
435 if (thisID < 0)
436 {
437 negativeID = true;
438 thisID = -thisID;
439 }
440
441 while (queue.Count > 0)
442 {
443 element = queue.Dequeue();
444 // add elements until a marker is found
445 // so they get into a response
446 if (element == null)
447 break;
448 if (DebugLevel > 0)
449 LogOutboundDebugMessage(element, pAgentId);
450 array.Add(element);
451 thisID++;
452 }
453 }
454
455 OSDMap events = null;
456
457 if (array.Count > 0)
458 {
459 events = new OSDMap();
460 events.Add("events", array);
461 events.Add("id", new OSDInteger(thisID));
462 }
463
464 if (negativeID && element == null)
465 {
466 Random rnd = new Random(Environment.TickCount);
467 thisID = rnd.Next(30000000);
468 if (thisID < 0)
469 thisID = -thisID;
470 }
471
472 lock (m_ids)
473 {
474 m_ids[pAgentId] = thisID + 1;
475 }
476
477 // if there where no elements before a marker send a NoEvents
478 if (array.Count == 0)
479 return NoEvents(requestID, pAgentId);
480
481 Hashtable responsedata = new Hashtable();
482 responsedata["int_response_code"] = 200;
483 responsedata["content_type"] = "application/xml";
484 responsedata["keepalive"] = false;
485 responsedata["reusecontext"] = false;
486 responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(events);
487 //m_log.DebugFormat("[EVENTQUEUE]: sending response for {0} in region {1}: {2}", pAgentId, m_scene.RegionInfo.RegionName, responsedata["str_response_string"]);
488 return responsedata;
489 }
490
491 public Hashtable NoEvents(UUID requestID, UUID agentID)
492 {
493 Hashtable responsedata = new Hashtable();
494 responsedata["int_response_code"] = 502;
495 responsedata["content_type"] = "text/plain";
496 responsedata["keepalive"] = false;
497 responsedata["reusecontext"] = false;
498 responsedata["str_response_string"] = "<llsd></llsd>";
499 responsedata["error_status_text"] = "<llsd></llsd>";
500 responsedata["http_protocol_version"] = "HTTP/1.0";
501 return responsedata;
502 }
503/* this is not a event message
504 public void DisableSimulator(ulong handle, UUID avatarID)
505 {
506 OSD item = EventQueueHelper.DisableSimulator(handle);
507 Enqueue(item, avatarID);
508 }
509*/
510 public virtual void EnableSimulator(ulong handle, IPEndPoint endPoint, UUID avatarID, int regionSizeX, int regionSizeY)
511 {
512 if (DebugLevel > 0)
513 m_log.DebugFormat("{0} EnableSimulator. handle={1}, endPoint={2}, avatarID={3}",
514 LogHeader, handle, endPoint, avatarID, regionSizeX, regionSizeY);
515
516 OSD item = EventQueueHelper.EnableSimulator(handle, endPoint, regionSizeX, regionSizeY);
517 Enqueue(item, avatarID);
518 }
519
520 public virtual void EstablishAgentCommunication(UUID avatarID, IPEndPoint endPoint, string capsPath,
521 ulong regionHandle, int regionSizeX, int regionSizeY)
522 {
523 if (DebugLevel > 0)
524 m_log.DebugFormat("{0} EstablishAgentCommunication. handle={1}, endPoint={2}, avatarID={3}",
525 LogHeader, regionHandle, endPoint, avatarID, regionSizeX, regionSizeY);
526
527 OSD item = EventQueueHelper.EstablishAgentCommunication(avatarID, endPoint.ToString(), capsPath, regionHandle, regionSizeX, regionSizeY);
528 Enqueue(item, avatarID);
529 }
530
531 public virtual void TeleportFinishEvent(ulong regionHandle, byte simAccess,
532 IPEndPoint regionExternalEndPoint,
533 uint locationID, uint flags, string capsURL,
534 UUID avatarID, int regionSizeX, int regionSizeY)
535 {
536 if (DebugLevel > 0)
537 m_log.DebugFormat("{0} TeleportFinishEvent. handle={1}, endPoint={2}, avatarID={3}",
538 LogHeader, regionHandle, regionExternalEndPoint, avatarID, regionSizeX, regionSizeY);
539
540 OSD item = EventQueueHelper.TeleportFinishEvent(regionHandle, simAccess, regionExternalEndPoint,
541 locationID, flags, capsURL, avatarID, regionSizeX, regionSizeY);
542 Enqueue(item, avatarID);
543 }
544
545 public virtual void CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt,
546 IPEndPoint newRegionExternalEndPoint,
547 string capsURL, UUID avatarID, UUID sessionID, int regionSizeX, int regionSizeY)
548 {
549 if (DebugLevel > 0)
550 m_log.DebugFormat("{0} CrossRegion. handle={1}, avatarID={2}, regionSize={3},{4}>",
551 LogHeader, handle, avatarID, regionSizeX, regionSizeY);
552
553 OSD item = EventQueueHelper.CrossRegion(handle, pos, lookAt, newRegionExternalEndPoint,
554 capsURL, avatarID, sessionID, regionSizeX, regionSizeY);
555 Enqueue(item, avatarID);
556 }
557
558 public void ChatterboxInvitation(UUID sessionID, string sessionName,
559 UUID fromAgent, string message, UUID toAgent, string fromName, byte dialog,
560 uint timeStamp, bool offline, int parentEstateID, Vector3 position,
561 uint ttl, UUID transactionID, bool fromGroup, byte[] binaryBucket)
562 {
563 OSD item = EventQueueHelper.ChatterboxInvitation(sessionID, sessionName, fromAgent, message, toAgent, fromName, dialog,
564 timeStamp, offline, parentEstateID, position, ttl, transactionID,
565 fromGroup, binaryBucket);
566 Enqueue(item, toAgent);
567 //m_log.InfoFormat("########### eq ChatterboxInvitation #############\n{0}", item);
568
569 }
570
571 public void ChatterBoxSessionAgentListUpdates(UUID sessionID, UUID fromAgent, UUID toAgent, bool canVoiceChat,
572 bool isModerator, bool textMute, bool isEnterorLeave)
573 {
574 OSD item = EventQueueHelper.ChatterBoxSessionAgentListUpdates(sessionID, fromAgent, canVoiceChat,
575 isModerator, textMute, isEnterorLeave);
576 Enqueue(item, toAgent);
577 //m_log.InfoFormat("########### eq ChatterBoxSessionAgentListUpdates #############\n{0}", item);
578 }
579
580 public void ChatterBoxForceClose(UUID toAgent, UUID sessionID, string reason)
581 {
582 OSD item = EventQueueHelper.ChatterBoxForceClose(sessionID, reason);
583
584 Enqueue(item, toAgent);
585 }
586
587 public void ParcelProperties(ParcelPropertiesMessage parcelPropertiesMessage, UUID avatarID)
588 {
589 OSD item = EventQueueHelper.ParcelProperties(parcelPropertiesMessage);
590 Enqueue(item, avatarID);
591 }
592
593 public void GroupMembershipData(UUID receiverAgent, GroupMembershipData[] data)
594 {
595 OSD item = EventQueueHelper.GroupMembershipData(receiverAgent, data);
596 Enqueue(item, receiverAgent);
597 }
598
599 public void QueryReply(PlacesReplyPacket groupUpdate, UUID avatarID)
600 {
601 OSD item = EventQueueHelper.PlacesQuery(groupUpdate);
602 Enqueue(item, avatarID);
603 }
604
605 public OSD ScriptRunningEvent(UUID objectID, UUID itemID, bool running, bool mono)
606 {
607 return EventQueueHelper.ScriptRunningReplyEvent(objectID, itemID, running, mono);
608 }
609
610 public OSD BuildEvent(string eventName, OSD eventBody)
611 {
612 return EventQueueHelper.BuildEvent(eventName, eventBody);
613 }
614
615 public void partPhysicsProperties(uint localID, byte physhapetype,
616 float density, float friction, float bounce, float gravmod,UUID avatarID)
617 {
618 OSD item = EventQueueHelper.partPhysicsProperties(localID, physhapetype,
619 density, friction, bounce, gravmod);
620 Enqueue(item, avatarID);
621 }
622 }
623}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
new file mode 100644
index 0000000..461f776
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
@@ -0,0 +1,465 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Net;
30using OpenMetaverse;
31using OpenMetaverse.Packets;
32using OpenMetaverse.StructuredData;
33using OpenMetaverse.Messages.Linden;
34
35using OpenSim.Framework;
36
37namespace OpenSim.Region.ClientStack.Linden
38{
39 public class EventQueueHelper
40 {
41 private EventQueueHelper() {} // no construction possible, it's an utility class
42
43 private static byte[] ulongToByteArray(ulong uLongValue)
44 {
45 // Reverse endianness of RegionHandle
46 return new byte[]
47 {
48 (byte)((uLongValue >> 56) % 256),
49 (byte)((uLongValue >> 48) % 256),
50 (byte)((uLongValue >> 40) % 256),
51 (byte)((uLongValue >> 32) % 256),
52 (byte)((uLongValue >> 24) % 256),
53 (byte)((uLongValue >> 16) % 256),
54 (byte)((uLongValue >> 8) % 256),
55 (byte)(uLongValue % 256)
56 };
57 }
58
59// private static byte[] uintToByteArray(uint uIntValue)
60// {
61// byte[] result = new byte[4];
62// Utils.UIntToBytesBig(uIntValue, result, 0);
63// return result;
64// }
65
66 public static OSD BuildEvent(string eventName, OSD eventBody)
67 {
68 OSDMap llsdEvent = new OSDMap(2);
69 llsdEvent.Add("message", new OSDString(eventName));
70 llsdEvent.Add("body", eventBody);
71
72 return llsdEvent;
73 }
74
75 public static OSD EnableSimulator(ulong handle, IPEndPoint endPoint, int regionSizeX, int regionSizeY)
76 {
77 OSDMap llsdSimInfo = new OSDMap(5);
78
79 llsdSimInfo.Add("Handle", new OSDBinary(ulongToByteArray(handle)));
80 llsdSimInfo.Add("IP", new OSDBinary(endPoint.Address.GetAddressBytes()));
81 llsdSimInfo.Add("Port", OSD.FromInteger(endPoint.Port));
82 llsdSimInfo.Add("RegionSizeX", OSD.FromUInteger((uint)regionSizeX));
83 llsdSimInfo.Add("RegionSizeY", OSD.FromUInteger((uint)regionSizeY));
84
85 OSDArray arr = new OSDArray(1);
86 arr.Add(llsdSimInfo);
87
88 OSDMap llsdBody = new OSDMap(1);
89 llsdBody.Add("SimulatorInfo", arr);
90
91 return BuildEvent("EnableSimulator", llsdBody);
92 }
93/*
94 public static OSD DisableSimulator(ulong handle)
95 {
96 //OSDMap llsdSimInfo = new OSDMap(1);
97
98 //llsdSimInfo.Add("Handle", new OSDBinary(regionHandleToByteArray(handle)));
99
100 //OSDArray arr = new OSDArray(1);
101 //arr.Add(llsdSimInfo);
102
103 OSDMap llsdBody = new OSDMap(0);
104 //llsdBody.Add("SimulatorInfo", arr);
105
106 return BuildEvent("DisableSimulator", llsdBody);
107 }
108*/
109 public static OSD CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt,
110 IPEndPoint newRegionExternalEndPoint,
111 string capsURL, UUID agentID, UUID sessionID,
112 int regionSizeX, int regionSizeY)
113 {
114 OSDArray lookAtArr = new OSDArray(3);
115 lookAtArr.Add(OSD.FromReal(lookAt.X));
116 lookAtArr.Add(OSD.FromReal(lookAt.Y));
117 lookAtArr.Add(OSD.FromReal(lookAt.Z));
118
119 OSDArray positionArr = new OSDArray(3);
120 positionArr.Add(OSD.FromReal(pos.X));
121 positionArr.Add(OSD.FromReal(pos.Y));
122 positionArr.Add(OSD.FromReal(pos.Z));
123
124 OSDMap infoMap = new OSDMap(2);
125 infoMap.Add("LookAt", lookAtArr);
126 infoMap.Add("Position", positionArr);
127
128 OSDArray infoArr = new OSDArray(1);
129 infoArr.Add(infoMap);
130
131 OSDMap agentDataMap = new OSDMap(2);
132 agentDataMap.Add("AgentID", OSD.FromUUID(agentID));
133 agentDataMap.Add("SessionID", OSD.FromUUID(sessionID));
134
135 OSDArray agentDataArr = new OSDArray(1);
136 agentDataArr.Add(agentDataMap);
137
138 OSDMap regionDataMap = new OSDMap(6);
139 regionDataMap.Add("RegionHandle", OSD.FromBinary(ulongToByteArray(handle)));
140 regionDataMap.Add("SeedCapability", OSD.FromString(capsURL));
141 regionDataMap.Add("SimIP", OSD.FromBinary(newRegionExternalEndPoint.Address.GetAddressBytes()));
142 regionDataMap.Add("SimPort", OSD.FromInteger(newRegionExternalEndPoint.Port));
143 regionDataMap.Add("RegionSizeX", OSD.FromUInteger((uint)regionSizeX));
144 regionDataMap.Add("RegionSizeY", OSD.FromUInteger((uint)regionSizeY));
145
146 OSDArray regionDataArr = new OSDArray(1);
147 regionDataArr.Add(regionDataMap);
148
149 OSDMap llsdBody = new OSDMap(3);
150 llsdBody.Add("Info", infoArr);
151 llsdBody.Add("AgentData", agentDataArr);
152 llsdBody.Add("RegionData", regionDataArr);
153
154 return BuildEvent("CrossedRegion", llsdBody);
155 }
156
157 public static OSD TeleportFinishEvent(
158 ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint,
159 uint locationID, uint flags, string capsURL, UUID agentID,
160 int regionSizeX, int regionSizeY)
161 {
162 // not sure why flags get overwritten here
163 if ((flags & (uint)TeleportFlags.IsFlying) != 0)
164 flags = (uint)TeleportFlags.ViaLocation | (uint)TeleportFlags.IsFlying;
165 else
166 flags = (uint)TeleportFlags.ViaLocation;
167
168 OSDMap info = new OSDMap();
169 info.Add("AgentID", OSD.FromUUID(agentID));
170 info.Add("LocationID", OSD.FromInteger(4)); // TODO what is this?
171 info.Add("RegionHandle", OSD.FromBinary(ulongToByteArray(regionHandle)));
172 info.Add("SeedCapability", OSD.FromString(capsURL));
173 info.Add("SimAccess", OSD.FromInteger(simAccess));
174 info.Add("SimIP", OSD.FromBinary(regionExternalEndPoint.Address.GetAddressBytes()));
175 info.Add("SimPort", OSD.FromInteger(regionExternalEndPoint.Port));
176// info.Add("TeleportFlags", OSD.FromULong(1L << 4)); // AgentManager.TeleportFlags.ViaLocation
177 info.Add("TeleportFlags", OSD.FromUInteger(flags));
178 info.Add("RegionSizeX", OSD.FromUInteger((uint)regionSizeX));
179 info.Add("RegionSizeY", OSD.FromUInteger((uint)regionSizeY));
180
181 OSDArray infoArr = new OSDArray();
182 infoArr.Add(info);
183
184 OSDMap body = new OSDMap();
185 body.Add("Info", infoArr);
186
187 return BuildEvent("TeleportFinish", body);
188 }
189
190 public static OSD ScriptRunningReplyEvent(UUID objectID, UUID itemID, bool running, bool mono)
191 {
192 OSDMap script = new OSDMap();
193 script.Add("ObjectID", OSD.FromUUID(objectID));
194 script.Add("ItemID", OSD.FromUUID(itemID));
195 script.Add("Running", OSD.FromBoolean(running));
196 script.Add("Mono", OSD.FromBoolean(mono));
197
198 OSDArray scriptArr = new OSDArray();
199 scriptArr.Add(script);
200
201 OSDMap body = new OSDMap();
202 body.Add("Script", scriptArr);
203
204 return BuildEvent("ScriptRunningReply", body);
205 }
206
207 public static OSD EstablishAgentCommunication(UUID agentID, string simIpAndPort, string seedcap,
208 ulong regionHandle, int regionSizeX, int regionSizeY)
209 {
210 OSDMap body = new OSDMap(6)
211 {
212 {"agent-id", new OSDUUID(agentID)},
213 {"sim-ip-and-port", new OSDString(simIpAndPort)},
214 {"seed-capability", new OSDString(seedcap)},
215 {"region-handle", OSD.FromULong(regionHandle)},
216 {"region-size-x", OSD.FromUInteger((uint)regionSizeX)},
217 {"region-size-y", OSD.FromUInteger((uint)regionSizeY)}
218 };
219
220 return BuildEvent("EstablishAgentCommunication", body);
221 }
222
223 public static OSD KeepAliveEvent()
224 {
225 return BuildEvent("FAKEEVENT", new OSDMap());
226 }
227
228 public static OSD AgentParams(UUID agentID, bool checkEstate, int godLevel, bool limitedToEstate)
229 {
230 OSDMap body = new OSDMap(4);
231
232 body.Add("agent_id", new OSDUUID(agentID));
233 body.Add("check_estate", new OSDInteger(checkEstate ? 1 : 0));
234 body.Add("god_level", new OSDInteger(godLevel));
235 body.Add("limited_to_estate", new OSDInteger(limitedToEstate ? 1 : 0));
236
237 return body;
238 }
239
240 public static OSD InstantMessageParams(UUID fromAgent, string message, UUID toAgent,
241 string fromName, byte dialog, uint timeStamp, bool offline, int parentEstateID,
242 Vector3 position, uint ttl, UUID transactionID, bool fromGroup, byte[] binaryBucket)
243 {
244 OSDMap messageParams = new OSDMap(15);
245 messageParams.Add("type", new OSDInteger((int)dialog));
246
247 OSDArray positionArray = new OSDArray(3);
248 positionArray.Add(OSD.FromReal(position.X));
249 positionArray.Add(OSD.FromReal(position.Y));
250 positionArray.Add(OSD.FromReal(position.Z));
251 messageParams.Add("position", positionArray);
252
253 messageParams.Add("region_id", new OSDUUID(UUID.Zero));
254 messageParams.Add("to_id", new OSDUUID(toAgent));
255 messageParams.Add("source", new OSDInteger(0));
256
257 OSDMap data = new OSDMap(1);
258 data.Add("binary_bucket", OSD.FromBinary(binaryBucket));
259 messageParams.Add("data", data);
260 messageParams.Add("message", new OSDString(message));
261 messageParams.Add("id", new OSDUUID(transactionID));
262 messageParams.Add("from_name", new OSDString(fromName));
263 messageParams.Add("timestamp", new OSDInteger((int)timeStamp));
264 messageParams.Add("offline", new OSDInteger(offline ? 1 : 0));
265 messageParams.Add("parent_estate_id", new OSDInteger(parentEstateID));
266 messageParams.Add("ttl", new OSDInteger((int)ttl));
267 messageParams.Add("from_id", new OSDUUID(fromAgent));
268 messageParams.Add("from_group", new OSDInteger(fromGroup ? 1 : 0));
269
270 return messageParams;
271 }
272
273 public static OSD InstantMessage(UUID fromAgent, string message, UUID toAgent,
274 string fromName, byte dialog, uint timeStamp, bool offline, int parentEstateID,
275 Vector3 position, uint ttl, UUID transactionID, bool fromGroup, byte[] binaryBucket,
276 bool checkEstate, int godLevel, bool limitedToEstate)
277 {
278 OSDMap im = new OSDMap(2);
279 im.Add("message_params", InstantMessageParams(fromAgent, message, toAgent,
280 fromName, dialog, timeStamp, offline, parentEstateID,
281 position, ttl, transactionID, fromGroup, binaryBucket));
282
283 im.Add("agent_params", AgentParams(fromAgent, checkEstate, godLevel, limitedToEstate));
284
285 return im;
286 }
287
288
289 public static OSD ChatterboxInvitation(UUID sessionID, string sessionName,
290 UUID fromAgent, string message, UUID toAgent, string fromName, byte dialog,
291 uint timeStamp, bool offline, int parentEstateID, Vector3 position,
292 uint ttl, UUID transactionID, bool fromGroup, byte[] binaryBucket)
293 {
294 OSDMap body = new OSDMap(5);
295 body.Add("session_id", new OSDUUID(sessionID));
296 body.Add("from_name", new OSDString(fromName));
297 body.Add("session_name", new OSDString(sessionName));
298 body.Add("from_id", new OSDUUID(fromAgent));
299
300 body.Add("instantmessage", InstantMessage(fromAgent, message, toAgent,
301 fromName, dialog, timeStamp, offline, parentEstateID, position,
302 ttl, transactionID, fromGroup, binaryBucket, true, 0, true));
303
304 OSDMap chatterboxInvitation = new OSDMap(2);
305 chatterboxInvitation.Add("message", new OSDString("ChatterBoxInvitation"));
306 chatterboxInvitation.Add("body", body);
307 return chatterboxInvitation;
308 }
309
310 public static OSD ChatterBoxSessionAgentListUpdates(UUID sessionID,
311 UUID agentID, bool canVoiceChat, bool isModerator, bool textMute, bool isEnterorLeave)
312 {
313 OSDMap body = new OSDMap();
314 OSDMap agentUpdates = new OSDMap();
315 OSDMap infoDetail = new OSDMap();
316 OSDMap mutes = new OSDMap();
317
318 // this should be a list of agents and parameters
319 // foreach agent
320 mutes.Add("text", OSD.FromBoolean(textMute));
321 infoDetail.Add("can_voice_chat", OSD.FromBoolean(canVoiceChat));
322 infoDetail.Add("is_moderator", OSD.FromBoolean(isModerator));
323 infoDetail.Add("mutes", mutes);
324 OSDMap info = new OSDMap();
325 info.Add("info", infoDetail);
326 if(isEnterorLeave)
327 info.Add("transition",OSD.FromString("ENTER"));
328 else
329 info.Add("transition",OSD.FromString("LEAVE"));
330 agentUpdates.Add(agentID.ToString(), info);
331
332 // foreach end
333
334 body.Add("agent_updates", agentUpdates);
335 body.Add("session_id", OSD.FromUUID(sessionID));
336 body.Add("updates", new OSD());
337
338 OSDMap chatterBoxSessionAgentListUpdates = new OSDMap();
339 chatterBoxSessionAgentListUpdates.Add("message", OSD.FromString("ChatterBoxSessionAgentListUpdates"));
340 chatterBoxSessionAgentListUpdates.Add("body", body);
341
342 return chatterBoxSessionAgentListUpdates;
343 }
344
345 public static OSD ChatterBoxForceClose(UUID sessionID, string reason)
346 {
347 OSDMap body = new OSDMap(2);
348 body.Add("session_id", new OSDUUID(sessionID));
349 body.Add("reason", new OSDString(reason));
350
351 OSDMap chatterBoxForceClose = new OSDMap(2);
352 chatterBoxForceClose.Add("message", new OSDString("ForceCloseChatterBoxSession"));
353 chatterBoxForceClose.Add("body", body);
354 return chatterBoxForceClose;
355 }
356
357 public static OSD GroupMembershipData(UUID receiverAgent, GroupMembershipData[] data)
358 {
359 OSDArray AgentData = new OSDArray(1);
360 OSDMap AgentDataMap = new OSDMap(1);
361 AgentDataMap.Add("AgentID", OSD.FromUUID(receiverAgent));
362 AgentData.Add(AgentDataMap);
363
364 OSDArray GroupData = new OSDArray(data.Length);
365 OSDArray NewGroupData = new OSDArray(data.Length);
366
367 foreach (GroupMembershipData membership in data)
368 {
369 OSDMap GroupDataMap = new OSDMap(6);
370 OSDMap NewGroupDataMap = new OSDMap(1);
371
372 GroupDataMap.Add("GroupID", OSD.FromUUID(membership.GroupID));
373 GroupDataMap.Add("GroupPowers", OSD.FromULong(membership.GroupPowers));
374 GroupDataMap.Add("AcceptNotices", OSD.FromBoolean(membership.AcceptNotices));
375 GroupDataMap.Add("GroupInsigniaID", OSD.FromUUID(membership.GroupPicture));
376 GroupDataMap.Add("Contribution", OSD.FromInteger(membership.Contribution));
377 GroupDataMap.Add("GroupName", OSD.FromString(membership.GroupName));
378 NewGroupDataMap.Add("ListInProfile", OSD.FromBoolean(membership.ListInProfile));
379
380 GroupData.Add(GroupDataMap);
381 NewGroupData.Add(NewGroupDataMap);
382 }
383
384 OSDMap llDataStruct = new OSDMap(3);
385 llDataStruct.Add("AgentData", AgentData);
386 llDataStruct.Add("GroupData", GroupData);
387 llDataStruct.Add("NewGroupData", NewGroupData);
388
389 return BuildEvent("AgentGroupDataUpdate", llDataStruct);
390
391 }
392
393 public static OSD PlacesQuery(PlacesReplyPacket PlacesReply)
394 {
395 OSDMap placesReply = new OSDMap();
396 placesReply.Add("message", OSD.FromString("PlacesReplyMessage"));
397
398 OSDMap body = new OSDMap();
399 OSDArray agentData = new OSDArray();
400 OSDMap agentDataMap = new OSDMap();
401 agentDataMap.Add("AgentID", OSD.FromUUID(PlacesReply.AgentData.AgentID));
402 agentDataMap.Add("QueryID", OSD.FromUUID(PlacesReply.AgentData.QueryID));
403 agentDataMap.Add("TransactionID", OSD.FromUUID(PlacesReply.TransactionData.TransactionID));
404 agentData.Add(agentDataMap);
405 body.Add("AgentData", agentData);
406
407 OSDArray QueryData = new OSDArray();
408
409 foreach (PlacesReplyPacket.QueryDataBlock groupDataBlock in PlacesReply.QueryData)
410 {
411 OSDMap QueryDataMap = new OSDMap();
412 QueryDataMap.Add("ActualArea", OSD.FromInteger(groupDataBlock.ActualArea));
413 QueryDataMap.Add("BillableArea", OSD.FromInteger(groupDataBlock.BillableArea));
414 QueryDataMap.Add("Description", OSD.FromBinary(groupDataBlock.Desc));
415 QueryDataMap.Add("Dwell", OSD.FromInteger((int)groupDataBlock.Dwell));
416 QueryDataMap.Add("Flags", OSD.FromString(Convert.ToString(groupDataBlock.Flags)));
417 QueryDataMap.Add("GlobalX", OSD.FromInteger((int)groupDataBlock.GlobalX));
418 QueryDataMap.Add("GlobalY", OSD.FromInteger((int)groupDataBlock.GlobalY));
419 QueryDataMap.Add("GlobalZ", OSD.FromInteger((int)groupDataBlock.GlobalZ));
420 QueryDataMap.Add("Name", OSD.FromBinary(groupDataBlock.Name));
421 QueryDataMap.Add("OwnerID", OSD.FromUUID(groupDataBlock.OwnerID));
422 QueryDataMap.Add("SimName", OSD.FromBinary(groupDataBlock.SimName));
423 QueryDataMap.Add("SnapShotID", OSD.FromUUID(groupDataBlock.SnapshotID));
424 QueryDataMap.Add("ProductSku", OSD.FromInteger(0));
425 QueryDataMap.Add("Price", OSD.FromInteger(groupDataBlock.Price));
426
427 QueryData.Add(QueryDataMap);
428 }
429 body.Add("QueryData", QueryData);
430 placesReply.Add("QueryData[]", body);
431
432 return placesReply;
433 }
434
435 public static OSD ParcelProperties(ParcelPropertiesMessage parcelPropertiesMessage)
436 {
437 OSDMap message = new OSDMap();
438 message.Add("message", OSD.FromString("ParcelProperties"));
439 OSD message_body = parcelPropertiesMessage.Serialize();
440 message.Add("body", message_body);
441 return message;
442 }
443
444 public static OSD partPhysicsProperties(uint localID, byte physhapetype,
445 float density, float friction, float bounce, float gravmod)
446 {
447
448 OSDMap physinfo = new OSDMap(6);
449 physinfo["LocalID"] = localID;
450 physinfo["Density"] = density;
451 physinfo["Friction"] = friction;
452 physinfo["GravityMultiplier"] = gravmod;
453 physinfo["Restitution"] = bounce;
454 physinfo["PhysicsShapeType"] = (int)physhapetype;
455
456 OSDArray array = new OSDArray(1);
457 array.Add(physinfo);
458
459 OSDMap llsdBody = new OSDMap(1);
460 llsdBody.Add("ObjectData", array);
461
462 return BuildEvent("ObjectPhysicsProperties", llsdBody);
463 }
464 }
465}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs
new file mode 100644
index 0000000..ee3f4f1
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs
@@ -0,0 +1,198 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Net;
32using log4net.Config;
33using Nini.Config;
34using NUnit.Framework;
35using OpenMetaverse;
36using OpenMetaverse.Packets;
37using OpenMetaverse.StructuredData;
38using OpenSim.Framework;
39using OpenSim.Framework.Servers;
40using OpenSim.Framework.Servers.HttpServer;
41using OpenSim.Region.ClientStack.Linden;
42using OpenSim.Region.CoreModules.Framework;
43using OpenSim.Region.Framework.Scenes;
44using OpenSim.Region.OptionalModules.World.NPC;
45using OpenSim.Tests.Common;
46
47namespace OpenSim.Region.ClientStack.Linden.Tests
48{
49 [TestFixture]
50 public class EventQueueTests : OpenSimTestCase
51 {
52 private TestScene m_scene;
53 private EventQueueGetModule m_eqgMod;
54 private NPCModule m_npcMod;
55
56 [SetUp]
57 public override void SetUp()
58 {
59 base.SetUp();
60
61 uint port = 9999;
62 uint sslPort = 9998;
63
64 // This is an unfortunate bit of clean up we have to do because MainServer manages things through static
65 // variables and the VM is not restarted between tests.
66 MainServer.RemoveHttpServer(port);
67
68 BaseHttpServer server = new BaseHttpServer(port, false, sslPort, "");
69 MainServer.AddHttpServer(server);
70 MainServer.Instance = server;
71
72 IConfigSource config = new IniConfigSource();
73 config.AddConfig("Startup");
74
75 CapabilitiesModule capsModule = new CapabilitiesModule();
76 m_eqgMod = new EventQueueGetModule();
77
78 // For NPC test support
79 config.AddConfig("NPC");
80 config.Configs["NPC"].Set("Enabled", "true");
81 m_npcMod = new NPCModule();
82
83 m_scene = new SceneHelpers().SetupScene();
84 SceneHelpers.SetupSceneModules(m_scene, config, capsModule, m_eqgMod, m_npcMod);
85 }
86
87 [Test]
88 public void TestAddForClient()
89 {
90 TestHelpers.InMethod();
91// log4net.Config.XmlConfigurator.Configure();
92
93 SceneHelpers.AddScenePresence(m_scene, TestHelpers.ParseTail(0x1));
94
95 // TODO: Add more assertions for the other aspects of event queues
96 Assert.That(MainServer.Instance.GetPollServiceHandlerKeys().Count, Is.EqualTo(1));
97 }
98
99 [Test]
100 public void TestRemoveForClient()
101 {
102 TestHelpers.InMethod();
103// TestHelpers.EnableLogging();
104
105 UUID spId = TestHelpers.ParseTail(0x1);
106
107 SceneHelpers.AddScenePresence(m_scene, spId);
108 m_scene.CloseAgent(spId, false);
109
110 // TODO: Add more assertions for the other aspects of event queues
111 Assert.That(MainServer.Instance.GetPollServiceHandlerKeys().Count, Is.EqualTo(0));
112 }
113
114 [Test]
115 public void TestEnqueueMessage()
116 {
117 TestHelpers.InMethod();
118// log4net.Config.XmlConfigurator.Configure();
119
120 ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, TestHelpers.ParseTail(0x1));
121
122 string messageName = "TestMessage";
123
124 m_eqgMod.Enqueue(m_eqgMod.BuildEvent(messageName, new OSDMap()), sp.UUID);
125
126 Hashtable eventsResponse = m_eqgMod.GetEvents(UUID.Zero, sp.UUID);
127
128 // initial queue as null events
129 eventsResponse = m_eqgMod.GetEvents(UUID.Zero, sp.UUID);
130 if((int)eventsResponse["int_response_code"] != (int)HttpStatusCode.OK)
131 {
132 eventsResponse = m_eqgMod.GetEvents(UUID.Zero, sp.UUID);
133 if((int)eventsResponse["int_response_code"] != (int)HttpStatusCode.OK)
134 eventsResponse = m_eqgMod.GetEvents(UUID.Zero, sp.UUID);
135 }
136
137 Assert.That((int)eventsResponse["int_response_code"], Is.EqualTo((int)HttpStatusCode.OK));
138
139// Console.WriteLine("Response [{0}]", (string)eventsResponse["str_response_string"]);
140
141 OSDMap rawOsd = (OSDMap)OSDParser.DeserializeLLSDXml((string)eventsResponse["str_response_string"]);
142 OSDArray eventsOsd = (OSDArray)rawOsd["events"];
143
144 bool foundUpdate = false;
145 foreach (OSD osd in eventsOsd)
146 {
147 OSDMap eventOsd = (OSDMap)osd;
148
149 if (eventOsd["message"] == messageName)
150 foundUpdate = true;
151 }
152
153 Assert.That(foundUpdate, Is.True, string.Format("Did not find {0} in response", messageName));
154 }
155
156 /// <summary>
157 /// Test an attempt to put a message on the queue of a user that is not in the region.
158 /// </summary>
159 [Test]
160 public void TestEnqueueMessageNoUser()
161 {
162 TestHelpers.InMethod();
163 TestHelpers.EnableLogging();
164
165 string messageName = "TestMessage";
166
167 m_eqgMod.Enqueue(m_eqgMod.BuildEvent(messageName, new OSDMap()), TestHelpers.ParseTail(0x1));
168
169 Hashtable eventsResponse = m_eqgMod.GetEvents(UUID.Zero, TestHelpers.ParseTail(0x1));
170
171 Assert.That((int)eventsResponse["int_response_code"], Is.EqualTo((int)HttpStatusCode.BadGateway));
172 }
173
174 /// <summary>
175 /// NPCs do not currently have an event queue but a caller may try to send a message anyway, so check behaviour.
176 /// </summary>
177 [Test]
178 public void TestEnqueueMessageToNpc()
179 {
180 TestHelpers.InMethod();
181// TestHelpers.EnableLogging();
182
183 UUID npcId
184 = m_npcMod.CreateNPC(
185 "John", "Smith", new Vector3(128, 128, 30), UUID.Zero, true, m_scene, new AvatarAppearance());
186
187 ScenePresence npc = m_scene.GetScenePresence(npcId);
188
189 string messageName = "TestMessage";
190
191 m_eqgMod.Enqueue(m_eqgMod.BuildEvent(messageName, new OSDMap()), npc.UUID);
192
193 Hashtable eventsResponse = m_eqgMod.GetEvents(UUID.Zero, npc.UUID);
194
195 Assert.That((int)eventsResponse["int_response_code"], Is.EqualTo((int)HttpStatusCode.BadGateway));
196 }
197 }
198}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/FetchInventory2Module.cs b/OpenSim/Region/ClientStack/Linden/Caps/FetchInventory2Module.cs
new file mode 100644
index 0000000..e0a11cc
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/FetchInventory2Module.cs
@@ -0,0 +1,144 @@
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 Mono.Addins;
29using Nini.Config;
30using OpenMetaverse;
31using OpenSim.Capabilities.Handlers;
32using OpenSim.Framework.Servers.HttpServer;
33using OpenSim.Region.Framework.Interfaces;
34using OpenSim.Region.Framework.Scenes;
35using OpenSim.Services.Interfaces;
36using System;
37using Caps = OpenSim.Framework.Capabilities.Caps;
38
39namespace OpenSim.Region.ClientStack.Linden
40{
41 /// <summary>
42 /// This module implements both WebFetchInventoryDescendents and FetchInventoryDescendents2 capabilities.
43 /// </summary>
44 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "FetchInventory2Module")]
45 public class FetchInventory2Module : INonSharedRegionModule
46 {
47// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48
49 public bool Enabled { get; private set; }
50
51 private Scene m_scene;
52
53 private IInventoryService m_inventoryService;
54
55 private string m_fetchInventory2Url;
56
57 #region ISharedRegionModule Members
58
59 public void Initialise(IConfigSource source)
60 {
61 IConfig config = source.Configs["ClientStack.LindenCaps"];
62 if (config == null)
63 return;
64
65 m_fetchInventory2Url = config.GetString("Cap_FetchInventory2", string.Empty);
66
67 if (m_fetchInventory2Url != string.Empty)
68 Enabled = true;
69 }
70
71 public void AddRegion(Scene s)
72 {
73 if (!Enabled)
74 return;
75
76 m_scene = s;
77 }
78
79 public void RemoveRegion(Scene s)
80 {
81 if (!Enabled)
82 return;
83
84 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
85 m_scene = null;
86 }
87
88 public void RegionLoaded(Scene s)
89 {
90 if (!Enabled)
91 return;
92
93 m_inventoryService = m_scene.InventoryService;
94
95 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
96 }
97
98 public void PostInitialise() {}
99
100 public void Close() {}
101
102 public string Name { get { return "FetchInventory2Module"; } }
103
104 public Type ReplaceableInterface
105 {
106 get { return null; }
107 }
108
109 #endregion
110
111 private void RegisterCaps(UUID agentID, Caps caps)
112 {
113 RegisterFetchCap(agentID, caps, "FetchInventory2", m_fetchInventory2Url);
114 }
115
116 private void RegisterFetchCap(UUID agentID, Caps caps, string capName, string url)
117 {
118 string capUrl;
119
120 if (url == "localhost")
121 {
122 capUrl = "/CAPS/" + UUID.Random();
123
124 FetchInventory2Handler fetchHandler = new FetchInventory2Handler(m_inventoryService, agentID);
125
126 IRequestHandler reqHandler
127 = new RestStreamHandler(
128 "POST", capUrl, fetchHandler.FetchInventoryRequest, capName, agentID.ToString());
129
130 caps.RegisterHandler(capName, reqHandler);
131 }
132 else
133 {
134 capUrl = url;
135
136 caps.RegisterHandler(capName, capUrl);
137 }
138
139// m_log.DebugFormat(
140// "[FETCH INVENTORY2 MODULE]: Registered capability {0} at {1} in region {2} for {3}",
141// capName, capUrl, m_scene.RegionInfo.RegionName, agentID);
142 }
143 }
144}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs
new file mode 100644
index 0000000..ba917e39
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs
@@ -0,0 +1,456 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Collections.Specialized;
32using System.Reflection;
33using System.IO;
34using System.Threading;
35using System.Web;
36using Mono.Addins;
37using OpenSim.Framework.Monitoring;
38using log4net;
39using Nini.Config;
40using OpenMetaverse;
41using OpenMetaverse.StructuredData;
42using OpenSim.Capabilities.Handlers;
43using OpenSim.Framework;
44using OpenSim.Framework.Servers;
45using OpenSim.Framework.Servers.HttpServer;
46using OpenSim.Region.Framework.Interfaces;
47using OpenSim.Region.Framework.Scenes;
48using OpenSim.Services.Interfaces;
49using Caps = OpenSim.Framework.Capabilities.Caps;
50
51namespace OpenSim.Region.ClientStack.Linden
52{
53 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GetMeshModule")]
54 public class GetMeshModule : INonSharedRegionModule
55 {
56// private static readonly ILog m_log =
57// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
58
59 private Scene m_scene;
60 private IAssetService m_AssetService;
61 private bool m_Enabled = true;
62 private string m_URL;
63
64 private string m_URL2;
65 private string m_RedirectURL = null;
66 private string m_RedirectURL2 = null;
67
68 struct aPollRequest
69 {
70 public PollServiceMeshEventArgs thepoll;
71 public UUID reqID;
72 public Hashtable request;
73 }
74
75 public class aPollResponse
76 {
77 public Hashtable response;
78 public int bytes;
79 public int lod;
80 }
81
82
83 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
84
85 private static GetMeshHandler m_getMeshHandler;
86
87 private IAssetService m_assetService = null;
88
89 private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>();
90 private static Thread[] m_workerThreads = null;
91 private static int m_NumberScenes = 0;
92 private static OpenSim.Framework.BlockingQueue<aPollRequest> m_queue =
93 new OpenSim.Framework.BlockingQueue<aPollRequest>();
94
95 private Dictionary<UUID, PollServiceMeshEventArgs> m_pollservices = new Dictionary<UUID, PollServiceMeshEventArgs>();
96
97
98 #region Region Module interfaceBase Members
99
100 public Type ReplaceableInterface
101 {
102 get { return null; }
103 }
104
105 public void Initialise(IConfigSource source)
106 {
107 IConfig config = source.Configs["ClientStack.LindenCaps"];
108 if (config == null)
109 return;
110
111 m_URL = config.GetString("Cap_GetMesh", string.Empty);
112 // Cap doesn't exist
113 if (m_URL != string.Empty)
114 {
115 m_Enabled = true;
116 m_RedirectURL = config.GetString("GetMeshRedirectURL");
117 }
118
119 m_URL2 = config.GetString("Cap_GetMesh2", string.Empty);
120 // Cap doesn't exist
121 if (m_URL2 != string.Empty)
122 {
123 m_Enabled = true;
124
125 m_RedirectURL2 = config.GetString("GetMesh2RedirectURL");
126 }
127 }
128
129 public void AddRegion(Scene pScene)
130 {
131 if (!m_Enabled)
132 return;
133
134 m_scene = pScene;
135
136 m_assetService = pScene.AssetService;
137 }
138
139 public void RemoveRegion(Scene scene)
140 {
141 if (!m_Enabled)
142 return;
143
144 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
145 m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps;
146 m_scene.EventManager.OnThrottleUpdate -= ThrottleUpdate;
147 m_NumberScenes--;
148 m_scene = null;
149 }
150
151 public void RegionLoaded(Scene scene)
152 {
153 if (!m_Enabled)
154 return;
155
156 m_AssetService = m_scene.RequestModuleInterface<IAssetService>();
157 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
158 // We'll reuse the same handler for all requests.
159 m_getMeshHandler = new GetMeshHandler(m_assetService);
160 m_scene.EventManager.OnDeregisterCaps += DeregisterCaps;
161 m_scene.EventManager.OnThrottleUpdate += ThrottleUpdate;
162
163 m_NumberScenes++;
164
165 if (m_workerThreads == null)
166 {
167 m_workerThreads = new Thread[2];
168
169 for (uint i = 0; i < 2; i++)
170 {
171 m_workerThreads[i] = WorkManager.StartThread(DoMeshRequests,
172 String.Format("GetMeshWorker{0}", i),
173 ThreadPriority.Normal,
174 true,
175 false,
176 null,
177 int.MaxValue);
178 }
179 }
180 }
181
182 public void Close()
183 {
184 if(m_NumberScenes <= 0 && m_workerThreads != null)
185 {
186 m_log.DebugFormat("[GetMeshModule] Closing");
187 foreach (Thread t in m_workerThreads)
188 Watchdog.AbortThread(t.ManagedThreadId);
189 // This will fail on region shutdown. Its harmless.
190 // Prevent red ink.
191 try
192 {
193 m_queue.Clear();
194 }
195 catch {}
196 }
197 }
198
199 public string Name { get { return "GetMeshModule"; } }
200
201 #endregion
202
203 private static void DoMeshRequests()
204 {
205 while(true)
206 {
207 aPollRequest poolreq = m_queue.Dequeue(4500);
208 Watchdog.UpdateThread();
209 if(m_NumberScenes <= 0)
210 return;
211 if(poolreq.reqID != UUID.Zero)
212 poolreq.thepoll.Process(poolreq);
213 }
214 }
215
216 // 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.
217 public void ThrottleUpdate(ScenePresence p)
218 {
219 UUID user = p.UUID;
220 int imagethrottle = p.ControllingClient.GetAgentThrottleSilent((int)ThrottleOutPacketType.Asset);
221 PollServiceMeshEventArgs args;
222 if (m_pollservices.TryGetValue(user, out args))
223 {
224 args.UpdateThrottle(imagethrottle);
225 }
226 }
227
228 private class PollServiceMeshEventArgs : PollServiceEventArgs
229 {
230 private List<Hashtable> requests =
231 new List<Hashtable>();
232 private Dictionary<UUID, aPollResponse> responses =
233 new Dictionary<UUID, aPollResponse>();
234
235 private Scene m_scene;
236 private MeshCapsDataThrottler m_throttler;
237 public PollServiceMeshEventArgs(string uri, UUID pId, Scene scene) :
238 base(null, uri, null, null, null, pId, int.MaxValue)
239 {
240 m_scene = scene;
241 m_throttler = new MeshCapsDataThrottler(100000);
242 // x is request id, y is userid
243 HasEvents = (x, y) =>
244 {
245 lock (responses)
246 {
247 bool ret = m_throttler.hasEvents(x, responses);
248 return ret;
249
250 }
251 };
252 GetEvents = (x, y) =>
253 {
254 lock (responses)
255 {
256 try
257 {
258 return responses[x].response;
259 }
260 finally
261 {
262 responses.Remove(x);
263 m_throttler.PassTime();
264 }
265 }
266 };
267 // x is request id, y is request data hashtable
268 Request = (x, y) =>
269 {
270 aPollRequest reqinfo = new aPollRequest();
271 reqinfo.thepoll = this;
272 reqinfo.reqID = x;
273 reqinfo.request = y;
274
275 m_queue.Enqueue(reqinfo);
276 m_throttler.PassTime();
277 };
278
279 // this should never happen except possible on shutdown
280 NoEvents = (x, y) =>
281 {
282 /*
283 lock (requests)
284 {
285 Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString());
286 requests.Remove(request);
287 }
288 */
289 Hashtable response = new Hashtable();
290
291 response["int_response_code"] = 500;
292 response["str_response_string"] = "Script timeout";
293 response["content_type"] = "text/plain";
294 response["keepalive"] = false;
295 response["reusecontext"] = false;
296
297 return response;
298 };
299 }
300
301 public void Process(aPollRequest requestinfo)
302 {
303 Hashtable response;
304
305 UUID requestID = requestinfo.reqID;
306
307 if(m_scene.ShuttingDown)
308 return;
309
310 // If the avatar is gone, don't bother to get the texture
311 if (m_scene.GetScenePresence(Id) == null)
312 {
313 response = new Hashtable();
314
315 response["int_response_code"] = 500;
316 response["str_response_string"] = "Script timeout";
317 response["content_type"] = "text/plain";
318 response["keepalive"] = false;
319 response["reusecontext"] = false;
320
321 lock (responses)
322 responses[requestID] = new aPollResponse() { bytes = 0, response = response, lod = 0 };
323
324 return;
325 }
326
327 response = m_getMeshHandler.Handle(requestinfo.request);
328 lock (responses)
329 {
330 responses[requestID] = new aPollResponse()
331 {
332 bytes = (int)response["int_bytes"],
333 lod = (int)response["int_lod"],
334 response = response
335 };
336
337 }
338 m_throttler.PassTime();
339 }
340
341 internal void UpdateThrottle(int pthrottle)
342 {
343 int tmp = 2 * pthrottle;
344 if(tmp < 10000)
345 tmp = 10000;
346 m_throttler.ThrottleBytes = tmp;
347 }
348 }
349
350 public void RegisterCaps(UUID agentID, Caps caps)
351 {
352// UUID capID = UUID.Random();
353 if (m_URL == "localhost")
354 {
355 string capUrl = "/CAPS/" + UUID.Random() + "/";
356
357 // Register this as a poll service
358 PollServiceMeshEventArgs args = new PollServiceMeshEventArgs(capUrl, agentID, m_scene);
359
360 args.Type = PollServiceEventArgs.EventType.Mesh;
361 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
362
363 string hostName = m_scene.RegionInfo.ExternalHostName;
364 uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
365 string protocol = "http";
366
367 if (MainServer.Instance.UseSSL)
368 {
369 hostName = MainServer.Instance.SSLCommonName;
370 port = MainServer.Instance.SSLPort;
371 protocol = "https";
372 }
373 caps.RegisterHandler("GetMesh", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
374 m_pollservices[agentID] = args;
375 m_capsDict[agentID] = capUrl;
376 }
377 else
378 {
379 caps.RegisterHandler("GetMesh", m_URL);
380 }
381 }
382
383 private void DeregisterCaps(UUID agentID, Caps caps)
384 {
385 string capUrl;
386 PollServiceMeshEventArgs args;
387 if (m_capsDict.TryGetValue(agentID, out capUrl))
388 {
389 MainServer.Instance.RemoveHTTPHandler("", capUrl);
390 m_capsDict.Remove(agentID);
391 }
392 if (m_pollservices.TryGetValue(agentID, out args))
393 {
394 m_pollservices.Remove(agentID);
395 }
396 }
397
398 internal sealed class MeshCapsDataThrottler
399 {
400 private double lastTimeElapsed = 0;
401 private double BytesSent = 0;
402
403 public MeshCapsDataThrottler(int pBytes)
404 {
405 if(pBytes < 10000)
406 pBytes = 10000;
407 ThrottleBytes = pBytes;
408 lastTimeElapsed = Util.GetTimeStampMS();
409 }
410
411 public bool hasEvents(UUID key, Dictionary<UUID, aPollResponse> responses)
412 {
413 PassTime();
414 // Note, this is called IN LOCK
415 bool haskey = responses.ContainsKey(key);
416
417 if (!haskey)
418 {
419 return false;
420 }
421 aPollResponse response;
422 if (responses.TryGetValue(key, out response))
423 {
424 // Normal
425 if (BytesSent <= ThrottleBytes)
426 {
427 BytesSent += response.bytes;
428 return true;
429 }
430 else
431 {
432 return false;
433 }
434 }
435 return haskey;
436 }
437
438 public void PassTime()
439 {
440 double currenttime = Util.GetTimeStampMS();
441 double timeElapsed = currenttime - lastTimeElapsed;
442 if(timeElapsed < 50.0)
443 return;
444 int add = (int)(ThrottleBytes * timeElapsed * 0.001);
445 if (add >= 1000)
446 {
447 lastTimeElapsed = currenttime;
448 BytesSent -= add;
449 if (BytesSent < 0) BytesSent = 0;
450 }
451 }
452
453 public int ThrottleBytes;
454 }
455 }
456}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
new file mode 100644
index 0000000..b01c7dc
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
@@ -0,0 +1,488 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Reflection;
32using System.Threading;
33using log4net;
34using Nini.Config;
35using Mono.Addins;
36using OpenMetaverse;
37using OpenSim.Framework;
38using OpenSim.Framework.Servers;
39using OpenSim.Framework.Servers.HttpServer;
40using OpenSim.Region.Framework.Interfaces;
41using OpenSim.Region.Framework.Scenes;
42using OpenSim.Services.Interfaces;
43using Caps = OpenSim.Framework.Capabilities.Caps;
44using OpenSim.Capabilities.Handlers;
45using OpenSim.Framework.Monitoring;
46
47namespace OpenSim.Region.ClientStack.Linden
48{
49
50 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GetTextureModule")]
51 public class GetTextureModule : INonSharedRegionModule
52 {
53
54 struct aPollRequest
55 {
56 public PollServiceTextureEventArgs thepoll;
57 public UUID reqID;
58 public Hashtable request;
59 public bool send503;
60 }
61
62 public class aPollResponse
63 {
64 public Hashtable response;
65 public int bytes;
66 }
67
68
69 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
70
71 private Scene m_scene;
72
73 private static GetTextureHandler m_getTextureHandler;
74
75 private IAssetService m_assetService = null;
76
77 private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>();
78 private static Thread[] m_workerThreads = null;
79 private static int m_NumberScenes = 0;
80 private static OpenSim.Framework.BlockingQueue<aPollRequest> m_queue =
81 new OpenSim.Framework.BlockingQueue<aPollRequest>();
82
83 private Dictionary<UUID,PollServiceTextureEventArgs> m_pollservices = new Dictionary<UUID,PollServiceTextureEventArgs>();
84
85 private string m_Url = "localhost";
86
87 #region ISharedRegionModule Members
88
89 public void Initialise(IConfigSource source)
90 {
91 IConfig config = source.Configs["ClientStack.LindenCaps"];
92
93 if (config == null)
94 return;
95/*
96 m_URL = config.GetString("Cap_GetTexture", string.Empty);
97 // Cap doesn't exist
98 if (m_URL != string.Empty)
99 {
100 m_Enabled = true;
101 m_RedirectURL = config.GetString("GetTextureRedirectURL");
102 }
103*/
104 m_Url = config.GetString("Cap_GetTexture", "localhost");
105 }
106
107 public void AddRegion(Scene s)
108 {
109 m_scene = s;
110 m_assetService = s.AssetService;
111 }
112
113 public void RemoveRegion(Scene s)
114 {
115 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
116 m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps;
117 m_scene.EventManager.OnThrottleUpdate -= ThrottleUpdate;
118 m_NumberScenes--;
119 m_scene = null;
120 }
121
122 public void RegionLoaded(Scene s)
123 {
124 // We'll reuse the same handler for all requests.
125 m_getTextureHandler = new GetTextureHandler(m_assetService);
126
127 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
128 m_scene.EventManager.OnDeregisterCaps += DeregisterCaps;
129 m_scene.EventManager.OnThrottleUpdate += ThrottleUpdate;
130
131 m_NumberScenes++;
132
133 if (m_workerThreads == null)
134 {
135 m_workerThreads = new Thread[2];
136
137 for (uint i = 0; i < 2; i++)
138 {
139 m_workerThreads[i] = WorkManager.StartThread(DoTextureRequests,
140 String.Format("GetTextureWorker{0}", i),
141 ThreadPriority.Normal,
142 true,
143 false,
144 null,
145 int.MaxValue);
146 }
147 }
148 }
149 private int ExtractImageThrottle(byte[] pthrottles)
150 {
151
152 byte[] adjData;
153 int pos = 0;
154
155 if (!BitConverter.IsLittleEndian)
156 {
157 byte[] newData = new byte[7 * 4];
158 Buffer.BlockCopy(pthrottles, 0, newData, 0, 7 * 4);
159
160 for (int i = 0; i < 7; i++)
161 Array.Reverse(newData, i * 4, 4);
162
163 adjData = newData;
164 }
165 else
166 {
167 adjData = pthrottles;
168 }
169
170 pos = pos + 20;
171 int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); //pos += 4;
172 //int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
173 return texture;
174 }
175
176 // 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.
177 public void ThrottleUpdate(ScenePresence p)
178 {
179 byte[] throttles = p.ControllingClient.GetThrottlesPacked(1);
180 UUID user = p.UUID;
181 int imagethrottle = ExtractImageThrottle(throttles);
182 PollServiceTextureEventArgs args;
183 if (m_pollservices.TryGetValue(user,out args))
184 {
185 args.UpdateThrottle(imagethrottle);
186 }
187 }
188
189 public void PostInitialise()
190 {
191 }
192
193 public void Close()
194 {
195 if(m_NumberScenes <= 0 && m_workerThreads != null)
196 {
197 m_log.DebugFormat("[GetTextureModule] Closing");
198
199 foreach (Thread t in m_workerThreads)
200 Watchdog.AbortThread(t.ManagedThreadId);
201
202 m_queue.Clear();
203 }
204 }
205
206 public string Name { get { return "GetTextureModule"; } }
207
208 public Type ReplaceableInterface
209 {
210 get { return null; }
211 }
212
213 #endregion
214
215 private class PollServiceTextureEventArgs : PollServiceEventArgs
216 {
217 private List<Hashtable> requests =
218 new List<Hashtable>();
219 private Dictionary<UUID, aPollResponse> responses =
220 new Dictionary<UUID, aPollResponse>();
221
222 private Scene m_scene;
223 private CapsDataThrottler m_throttler = new CapsDataThrottler(100000);
224 public PollServiceTextureEventArgs(UUID pId, Scene scene) :
225 base(null, "", null, null, null, pId, int.MaxValue)
226 {
227 m_scene = scene;
228 // x is request id, y is userid
229 HasEvents = (x, y) =>
230 {
231 lock (responses)
232 {
233 bool ret = m_throttler.hasEvents(x, responses);
234 return ret;
235
236 }
237 };
238 GetEvents = (x, y) =>
239 {
240 lock (responses)
241 {
242 try
243 {
244 return responses[x].response;
245 }
246 finally
247 {
248 responses.Remove(x);
249 m_throttler.PassTime();
250 }
251 }
252 };
253 // x is request id, y is request data hashtable
254 Request = (x, y) =>
255 {
256 aPollRequest reqinfo = new aPollRequest();
257 reqinfo.thepoll = this;
258 reqinfo.reqID = x;
259 reqinfo.request = y;
260 reqinfo.send503 = false;
261
262 lock (responses)
263 {
264 if (responses.Count > 0)
265 {
266 if (m_queue.Count() >= 4)
267 {
268 // Never allow more than 4 fetches to wait
269 reqinfo.send503 = true;
270 }
271 }
272 }
273 m_queue.Enqueue(reqinfo);
274 m_throttler.PassTime();
275 };
276
277 // this should never happen except possible on shutdown
278 NoEvents = (x, y) =>
279 {
280/*
281 lock (requests)
282 {
283 Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString());
284 requests.Remove(request);
285 }
286*/
287 Hashtable response = new Hashtable();
288
289 response["int_response_code"] = 500;
290 response["str_response_string"] = "Script timeout";
291 response["content_type"] = "text/plain";
292 response["keepalive"] = false;
293 response["reusecontext"] = false;
294
295 return response;
296 };
297 }
298
299 public void Process(aPollRequest requestinfo)
300 {
301 Hashtable response;
302
303 UUID requestID = requestinfo.reqID;
304
305 if(m_scene.ShuttingDown)
306 return;
307
308 if (requestinfo.send503)
309 {
310 response = new Hashtable();
311
312 response["int_response_code"] = 503;
313 response["str_response_string"] = "Throttled";
314 response["content_type"] = "text/plain";
315 response["keepalive"] = false;
316 response["reusecontext"] = false;
317
318 Hashtable headers = new Hashtable();
319 headers["Retry-After"] = 30;
320 response["headers"] = headers;
321
322 lock (responses)
323 responses[requestID] = new aPollResponse() {bytes = 0, response = response};
324
325 return;
326 }
327
328 // If the avatar is gone, don't bother to get the texture
329 if (m_scene.GetScenePresence(Id) == null)
330 {
331 response = new Hashtable();
332
333 response["int_response_code"] = 500;
334 response["str_response_string"] = "Script timeout";
335 response["content_type"] = "text/plain";
336 response["keepalive"] = false;
337 response["reusecontext"] = false;
338
339 lock (responses)
340 responses[requestID] = new aPollResponse() {bytes = 0, response = response};
341
342 return;
343 }
344
345 response = m_getTextureHandler.Handle(requestinfo.request);
346 lock (responses)
347 {
348 responses[requestID] = new aPollResponse()
349 {
350 bytes = (int) response["int_bytes"],
351 response = response
352 };
353
354 }
355 m_throttler.PassTime();
356 }
357
358 internal void UpdateThrottle(int pimagethrottle)
359 {
360 int tmp = 2 * pimagethrottle;
361 if(tmp < 10000)
362 tmp = 10000;
363 m_throttler.ThrottleBytes = tmp;
364 }
365 }
366
367 private void RegisterCaps(UUID agentID, Caps caps)
368 {
369 if (m_Url == "localhost")
370 {
371 string capUrl = "/CAPS/" + UUID.Random() + "/";
372
373 // Register this as a poll service
374 PollServiceTextureEventArgs args = new PollServiceTextureEventArgs(agentID, m_scene);
375
376 args.Type = PollServiceEventArgs.EventType.Texture;
377 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
378
379 string hostName = m_scene.RegionInfo.ExternalHostName;
380 uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
381 string protocol = "http";
382
383 if (MainServer.Instance.UseSSL)
384 {
385 hostName = MainServer.Instance.SSLCommonName;
386 port = MainServer.Instance.SSLPort;
387 protocol = "https";
388 }
389 IExternalCapsModule handler = m_scene.RequestModuleInterface<IExternalCapsModule>();
390 if (handler != null)
391 handler.RegisterExternalUserCapsHandler(agentID, caps, "GetTexture", capUrl);
392 else
393 caps.RegisterHandler("GetTexture", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
394 m_pollservices[agentID] = args;
395 m_capsDict[agentID] = capUrl;
396 }
397 else
398 {
399 caps.RegisterHandler("GetTexture", m_Url);
400 }
401 }
402
403 private void DeregisterCaps(UUID agentID, Caps caps)
404 {
405 PollServiceTextureEventArgs args;
406
407 MainServer.Instance.RemoveHTTPHandler("", m_Url);
408 m_capsDict.Remove(agentID);
409
410 if (m_pollservices.TryGetValue(agentID, out args))
411 {
412 m_pollservices.Remove(agentID);
413 }
414 }
415
416 private static void DoTextureRequests()
417 {
418 while (true)
419 {
420 aPollRequest poolreq = m_queue.Dequeue(4500);
421 Watchdog.UpdateThread();
422 if(m_NumberScenes <= 0)
423 return;
424 if(poolreq.reqID != UUID.Zero)
425 poolreq.thepoll.Process(poolreq);
426 }
427 }
428
429 internal sealed class CapsDataThrottler
430 {
431 private double lastTimeElapsed = 0;
432 private volatile int BytesSent = 0;
433 public CapsDataThrottler(int pBytes)
434 {
435 if(pBytes < 10000)
436 pBytes = 10000;
437 ThrottleBytes = pBytes;
438 lastTimeElapsed = Util.GetTimeStampMS();
439 }
440 public bool hasEvents(UUID key, Dictionary<UUID, GetTextureModule.aPollResponse> responses)
441 {
442 PassTime();
443 // Note, this is called IN LOCK
444 bool haskey = responses.ContainsKey(key);
445 if (!haskey)
446 {
447 return false;
448 }
449 GetTextureModule.aPollResponse response;
450 if (responses.TryGetValue(key, out response))
451 {
452 // This is any error response
453 if (response.bytes == 0)
454 return true;
455
456 // Normal
457 if (BytesSent <= ThrottleBytes)
458 {
459 BytesSent += response.bytes;
460 return true;
461 }
462 else
463 {
464 return false;
465 }
466 }
467
468 return haskey;
469 }
470
471 public void PassTime()
472 {
473 double currenttime = Util.GetTimeStampMS();
474 double timeElapsed = currenttime - lastTimeElapsed;
475 if(timeElapsed < 50.0)
476 return;
477 int add = (int)(ThrottleBytes * timeElapsed * 0.001);
478 if (add >= 1000)
479 {
480 lastTimeElapsed = currenttime;
481 BytesSent -= add;
482 if (BytesSent < 0) BytesSent = 0;
483 }
484 }
485 public int ThrottleBytes;
486 }
487 }
488}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs
new file mode 100644
index 0000000..44bf1a5
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs
@@ -0,0 +1,151 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Reflection;
31using log4net;
32using Nini.Config;
33using Mono.Addins;
34using OpenMetaverse;
35using OpenMetaverse.StructuredData;
36using OpenSim.Framework;
37using OpenSim.Framework.Servers.HttpServer;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Services.Interfaces;
41using Caps = OpenSim.Framework.Capabilities.Caps;
42
43namespace OpenSim.Region.ClientStack.Linden
44{
45 /// <summary>
46 /// MeshUploadFlag capability. This is required for uploading Mesh.
47 /// </summary>
48 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "MeshUploadFlagModule")]
49 public class MeshUploadFlagModule : INonSharedRegionModule
50 {
51// private static readonly ILog m_log =
52// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
53
54 /// <summary>
55 /// Is this module enabled?
56 /// </summary>
57 public bool Enabled { get; private set; }
58
59 private Scene m_scene;
60
61 #region ISharedRegionModule Members
62
63 public MeshUploadFlagModule()
64 {
65 Enabled = true;
66 }
67
68 public void Initialise(IConfigSource source)
69 {
70 IConfig config = source.Configs["Mesh"];
71 if (config == null)
72 {
73 return;
74 }
75 else
76 {
77 Enabled = config.GetBoolean("AllowMeshUpload", Enabled);
78 }
79 }
80
81 public void AddRegion(Scene s)
82 {
83 if (!Enabled)
84 return;
85
86 m_scene = s;
87 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
88 }
89
90 public void RemoveRegion(Scene s)
91 {
92 if (!Enabled)
93 return;
94
95 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
96 }
97
98 public void RegionLoaded(Scene s)
99 {
100 }
101
102 public void PostInitialise()
103 {
104 }
105
106 public void Close() { }
107
108 public string Name { get { return "MeshUploadFlagModule"; } }
109
110 public Type ReplaceableInterface
111 {
112 get { return null; }
113 }
114
115 #endregion
116
117 public void RegisterCaps(UUID agentID, Caps caps)
118 {
119 IRequestHandler reqHandler
120 = new RestHTTPHandler(
121 "GET", "/CAPS/" + UUID.Random(), ht => MeshUploadFlag(ht, agentID), "MeshUploadFlag", agentID.ToString());
122
123 caps.RegisterHandler("MeshUploadFlag", reqHandler);
124
125 }
126
127 private Hashtable MeshUploadFlag(Hashtable mDhttpMethod, UUID agentID)
128 {
129// m_log.DebugFormat("[MESH UPLOAD FLAG MODULE]: MeshUploadFlag request");
130
131 OSDMap data = new OSDMap();
132// ScenePresence sp = m_scene.GetScenePresence(m_agentID);
133// data["username"] = sp.Firstname + "." + sp.Lastname;
134// data["display_name_next_update"] = new OSDDate(DateTime.Now);
135// data["legacy_first_name"] = sp.Firstname;
136 data["mesh_upload_status"] = "valid";
137// data["display_name"] = sp.Firstname + " " + sp.Lastname;
138// data["legacy_last_name"] = sp.Lastname;
139// data["id"] = m_agentID;
140// data["is_display_name_default"] = true;
141
142 //Send back data
143 Hashtable responsedata = new Hashtable();
144 responsedata["int_response_code"] = 200;
145 responsedata["content_type"] = "text/plain";
146 responsedata["keepalive"] = false;
147 responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(data);
148 return responsedata;
149 }
150 }
151}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs
new file mode 100644
index 0000000..b044e56
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs
@@ -0,0 +1,389 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Reflection;
31using log4net;
32using Nini.Config;
33using OpenMetaverse;
34using OpenMetaverse.StructuredData;
35using Mono.Addins;
36using OpenSim.Framework;
37using OpenSim.Framework.Servers;
38using OpenSim.Framework.Servers.HttpServer;
39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Region.Framework.Scenes;
41using Caps=OpenSim.Framework.Capabilities.Caps;
42
43namespace OpenSim.Region.ClientStack.Linden
44{
45 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "ObjectAdd")]
46 public class ObjectAdd : INonSharedRegionModule
47 {
48// private static readonly ILog m_log =
49// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
50
51 private Scene m_scene;
52
53 #region INonSharedRegionModule Members
54
55 public void Initialise(IConfigSource pSource)
56 {
57 }
58
59 public void AddRegion(Scene scene)
60 {
61 m_scene = scene;
62 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
63 }
64
65 public void RemoveRegion(Scene scene)
66 {
67 if (m_scene == scene)
68 {
69 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
70 m_scene = null;
71 }
72 }
73
74 public void RegionLoaded(Scene scene)
75 {
76 }
77
78 public void Close()
79 {
80 }
81
82 public string Name
83 {
84 get { return "ObjectAddModule"; }
85 }
86
87 public Type ReplaceableInterface
88 {
89 get { return null; }
90 }
91
92 #endregion
93
94 public void RegisterCaps(UUID agentID, Caps caps)
95 {
96 UUID capuuid = UUID.Random();
97
98 // m_log.InfoFormat("[OBJECTADD]: {0}", "/CAPS/OA/" + capuuid + "/");
99
100 caps.RegisterHandler(
101 "ObjectAdd",
102 new RestHTTPHandler(
103 "POST",
104 "/CAPS/OA/" + capuuid + "/",
105 httpMethod => ProcessAdd(httpMethod, agentID, caps),
106 "ObjectAdd",
107 agentID.ToString())); ;
108 }
109
110 public Hashtable ProcessAdd(Hashtable request, UUID AgentId, Caps cap)
111 {
112 Hashtable responsedata = new Hashtable();
113 responsedata["int_response_code"] = 400; //501; //410; //404;
114 responsedata["content_type"] = "text/plain";
115 responsedata["keepalive"] = false;
116 responsedata["str_response_string"] = "Request wasn't what was expected";
117 ScenePresence avatar;
118
119 if (!m_scene.TryGetScenePresence(AgentId, out avatar))
120 return responsedata;
121
122
123 OSD r = OSDParser.DeserializeLLSDXml((string)request["requestbody"]);
124 if (r.Type != OSDType.Map) // not a proper req
125 return responsedata;
126
127 //UUID session_id = UUID.Zero;
128 bool bypass_raycast = false;
129 uint everyone_mask = 0;
130 uint group_mask = 0;
131 uint next_owner_mask = 0;
132 uint flags = 0;
133 UUID group_id = UUID.Zero;
134 int hollow = 0;
135 int material = 0;
136 int p_code = 0;
137 int path_begin = 0;
138 int path_curve = 0;
139 int path_end = 0;
140 int path_radius_offset = 0;
141 int path_revolutions = 0;
142 int path_scale_x = 0;
143 int path_scale_y = 0;
144 int path_shear_x = 0;
145 int path_shear_y = 0;
146 int path_skew = 0;
147 int path_taper_x = 0;
148 int path_taper_y = 0;
149 int path_twist = 0;
150 int path_twist_begin = 0;
151 int profile_begin = 0;
152 int profile_curve = 0;
153 int profile_end = 0;
154 Vector3 ray_end = Vector3.Zero;
155 bool ray_end_is_intersection = false;
156 Vector3 ray_start = Vector3.Zero;
157 UUID ray_target_id = UUID.Zero;
158 Quaternion rotation = Quaternion.Identity;
159 Vector3 scale = Vector3.Zero;
160 int state = 0;
161 int lastattach = 0;
162
163 OSDMap rm = (OSDMap)r;
164
165 if (rm.ContainsKey("ObjectData")) //v2
166 {
167 if (rm["ObjectData"].Type != OSDType.Map)
168 {
169 responsedata["str_response_string"] = "Has ObjectData key, but data not in expected format";
170 return responsedata;
171 }
172
173 OSDMap ObjMap = (OSDMap)rm["ObjectData"];
174
175 bypass_raycast = ObjMap["BypassRaycast"].AsBoolean();
176 everyone_mask = readuintval(ObjMap["EveryoneMask"]);
177 flags = readuintval(ObjMap["Flags"]);
178 group_mask = readuintval(ObjMap["GroupMask"]);
179 material = ObjMap["Material"].AsInteger();
180 next_owner_mask = readuintval(ObjMap["NextOwnerMask"]);
181 p_code = ObjMap["PCode"].AsInteger();
182
183 if (ObjMap.ContainsKey("Path"))
184 {
185 if (ObjMap["Path"].Type != OSDType.Map)
186 {
187 responsedata["str_response_string"] = "Has Path key, but data not in expected format";
188 return responsedata;
189 }
190
191 OSDMap PathMap = (OSDMap)ObjMap["Path"];
192 path_begin = PathMap["Begin"].AsInteger();
193 path_curve = PathMap["Curve"].AsInteger();
194 path_end = PathMap["End"].AsInteger();
195 path_radius_offset = PathMap["RadiusOffset"].AsInteger();
196 path_revolutions = PathMap["Revolutions"].AsInteger();
197 path_scale_x = PathMap["ScaleX"].AsInteger();
198 path_scale_y = PathMap["ScaleY"].AsInteger();
199 path_shear_x = PathMap["ShearX"].AsInteger();
200 path_shear_y = PathMap["ShearY"].AsInteger();
201 path_skew = PathMap["Skew"].AsInteger();
202 path_taper_x = PathMap["TaperX"].AsInteger();
203 path_taper_y = PathMap["TaperY"].AsInteger();
204 path_twist = PathMap["Twist"].AsInteger();
205 path_twist_begin = PathMap["TwistBegin"].AsInteger();
206
207 }
208
209 if (ObjMap.ContainsKey("Profile"))
210 {
211 if (ObjMap["Profile"].Type != OSDType.Map)
212 {
213 responsedata["str_response_string"] = "Has Profile key, but data not in expected format";
214 return responsedata;
215 }
216
217 OSDMap ProfileMap = (OSDMap)ObjMap["Profile"];
218
219 profile_begin = ProfileMap["Begin"].AsInteger();
220 profile_curve = ProfileMap["Curve"].AsInteger();
221 profile_end = ProfileMap["End"].AsInteger();
222 hollow = ProfileMap["Hollow"].AsInteger();
223 }
224 ray_end_is_intersection = ObjMap["RayEndIsIntersection"].AsBoolean();
225
226 ray_target_id = ObjMap["RayTargetId"].AsUUID();
227 state = ObjMap["State"].AsInteger();
228 lastattach = ObjMap["LastAttachPoint"].AsInteger();
229 try
230 {
231 ray_end = ((OSDArray)ObjMap["RayEnd"]).AsVector3();
232 ray_start = ((OSDArray)ObjMap["RayStart"]).AsVector3();
233 scale = ((OSDArray)ObjMap["Scale"]).AsVector3();
234 rotation = ((OSDArray)ObjMap["Rotation"]).AsQuaternion();
235 }
236 catch (Exception)
237 {
238 responsedata["str_response_string"] = "RayEnd, RayStart, Scale or Rotation wasn't in the expected format";
239 return responsedata;
240 }
241
242 if (rm.ContainsKey("AgentData"))
243 {
244 if (rm["AgentData"].Type != OSDType.Map)
245 {
246 responsedata["str_response_string"] = "Has AgentData key, but data not in expected format";
247 return responsedata;
248 }
249
250 OSDMap AgentDataMap = (OSDMap)rm["AgentData"];
251
252 //session_id = AgentDataMap["SessionId"].AsUUID();
253 group_id = AgentDataMap["GroupId"].AsUUID();
254 }
255
256 }
257 else
258 { //v1
259 bypass_raycast = rm["bypass_raycast"].AsBoolean();
260
261 everyone_mask = readuintval(rm["everyone_mask"]);
262 flags = readuintval(rm["flags"]);
263 group_id = rm["group_id"].AsUUID();
264 group_mask = readuintval(rm["group_mask"]);
265 hollow = rm["hollow"].AsInteger();
266 material = rm["material"].AsInteger();
267 next_owner_mask = readuintval(rm["next_owner_mask"]);
268 hollow = rm["hollow"].AsInteger();
269 p_code = rm["p_code"].AsInteger();
270 path_begin = rm["path_begin"].AsInteger();
271 path_curve = rm["path_curve"].AsInteger();
272 path_end = rm["path_end"].AsInteger();
273 path_radius_offset = rm["path_radius_offset"].AsInteger();
274 path_revolutions = rm["path_revolutions"].AsInteger();
275 path_scale_x = rm["path_scale_x"].AsInteger();
276 path_scale_y = rm["path_scale_y"].AsInteger();
277 path_shear_x = rm["path_shear_x"].AsInteger();
278 path_shear_y = rm["path_shear_y"].AsInteger();
279 path_skew = rm["path_skew"].AsInteger();
280 path_taper_x = rm["path_taper_x"].AsInteger();
281 path_taper_y = rm["path_taper_y"].AsInteger();
282 path_twist = rm["path_twist"].AsInteger();
283 path_twist_begin = rm["path_twist_begin"].AsInteger();
284 profile_begin = rm["profile_begin"].AsInteger();
285 profile_curve = rm["profile_curve"].AsInteger();
286 profile_end = rm["profile_end"].AsInteger();
287
288 ray_end_is_intersection = rm["ray_end_is_intersection"].AsBoolean();
289
290 ray_target_id = rm["ray_target_id"].AsUUID();
291
292
293 //session_id = rm["session_id"].AsUUID();
294 state = rm["state"].AsInteger();
295 lastattach = rm["last_attach_point"].AsInteger();
296 try
297 {
298 ray_end = ((OSDArray)rm["ray_end"]).AsVector3();
299 ray_start = ((OSDArray)rm["ray_start"]).AsVector3();
300 rotation = ((OSDArray)rm["rotation"]).AsQuaternion();
301 scale = ((OSDArray)rm["scale"]).AsVector3();
302 }
303 catch (Exception)
304 {
305 responsedata["str_response_string"] = "RayEnd, RayStart, Scale or Rotation wasn't in the expected format";
306 return responsedata;
307 }
308 }
309
310 Vector3 pos = m_scene.GetNewRezLocation(ray_start, ray_end, ray_target_id, rotation, (bypass_raycast) ? (byte)1 : (byte)0, (ray_end_is_intersection) ? (byte)1 : (byte)0, true, scale, false);
311
312 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox();
313
314 pbs.PathBegin = (ushort)path_begin;
315 pbs.PathCurve = (byte)path_curve;
316 pbs.PathEnd = (ushort)path_end;
317 pbs.PathRadiusOffset = (sbyte)path_radius_offset;
318 pbs.PathRevolutions = (byte)path_revolutions;
319 pbs.PathScaleX = (byte)path_scale_x;
320 pbs.PathScaleY = (byte)path_scale_y;
321 pbs.PathShearX = (byte)path_shear_x;
322 pbs.PathShearY = (byte)path_shear_y;
323 pbs.PathSkew = (sbyte)path_skew;
324 pbs.PathTaperX = (sbyte)path_taper_x;
325 pbs.PathTaperY = (sbyte)path_taper_y;
326 pbs.PathTwist = (sbyte)path_twist;
327 pbs.PathTwistBegin = (sbyte)path_twist_begin;
328 pbs.HollowShape = (HollowShape)hollow;
329 pbs.PCode = (byte)p_code;
330 pbs.ProfileBegin = (ushort)profile_begin;
331 pbs.ProfileCurve = (byte)profile_curve;
332 pbs.ProfileEnd = (ushort)profile_end;
333 pbs.Scale = scale;
334 pbs.State = (byte)state;
335 pbs.LastAttachPoint = (byte)lastattach;
336
337 SceneObjectGroup obj = null; ;
338
339 if (m_scene.Permissions.CanRezObject(1, avatar.UUID, pos))
340 {
341 // rez ON the ground, not IN the ground
342 // pos.Z += 0.25F;
343
344 obj = m_scene.AddNewPrim(avatar.UUID, group_id, pos, rotation, pbs);
345 }
346
347
348 if (obj == null)
349 return responsedata;
350
351 SceneObjectPart rootpart = obj.RootPart;
352 rootpart.Shape = pbs;
353 rootpart.Flags |= (PrimFlags)flags;
354 rootpart.EveryoneMask = everyone_mask;
355 rootpart.GroupID = group_id;
356 rootpart.GroupMask = group_mask;
357 rootpart.NextOwnerMask = next_owner_mask;
358 rootpart.Material = (byte)material;
359
360 obj.InvalidateDeepEffectivePerms();
361
362 m_scene.PhysicsScene.AddPhysicsActorTaint(rootpart.PhysActor);
363
364 responsedata["int_response_code"] = 200; //501; //410; //404;
365 responsedata["content_type"] = "text/plain";
366 responsedata["keepalive"] = false;
367 responsedata["str_response_string"] = String.Format("<llsd><map><key>local_id</key>{0}</map></llsd>", ConvertUintToBytes(obj.LocalId));
368
369 return responsedata;
370 }
371
372 private uint readuintval(OSD obj)
373 {
374 byte[] tmp = obj.AsBinary();
375 if (BitConverter.IsLittleEndian)
376 Array.Reverse(tmp);
377 return Utils.BytesToUInt(tmp);
378
379 }
380 private string ConvertUintToBytes(uint val)
381 {
382 byte[] resultbytes = Utils.UIntToBytes(val);
383 if (BitConverter.IsLittleEndian)
384 Array.Reverse(resultbytes);
385 return String.Format("<binary encoding=\"base64\">{0}</binary>", Convert.ToBase64String(resultbytes));
386 }
387
388 }
389}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs
new file mode 100644
index 0000000..116c51f
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs
@@ -0,0 +1,380 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Specialized;
31using System.Reflection;
32using System.IO;
33using System.Web;
34using Mono.Addins;
35using log4net;
36using Nini.Config;
37using OpenMetaverse;
38using OpenMetaverse.StructuredData;
39using OpenMetaverse.Messages.Linden;
40using OpenSim.Framework;
41using OpenSim.Framework.Servers;
42using OpenSim.Framework.Servers.HttpServer;
43using OpenSim.Region.Framework.Interfaces;
44using OpenSim.Region.Framework.Scenes;
45using OpenSim.Services.Interfaces;
46using Caps = OpenSim.Framework.Capabilities.Caps;
47using OSD = OpenMetaverse.StructuredData.OSD;
48using OSDMap = OpenMetaverse.StructuredData.OSDMap;
49using OpenSim.Framework.Capabilities;
50using ExtraParamType = OpenMetaverse.ExtraParamType;
51
52namespace OpenSim.Region.ClientStack.Linden
53{
54 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UploadObjectAssetModule")]
55 public class UploadObjectAssetModule : INonSharedRegionModule
56 {
57 private static readonly ILog m_log =
58 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
59 private Scene m_scene;
60
61 #region Region Module interfaceBase Members
62
63
64 public Type ReplaceableInterface
65 {
66 get { return null; }
67 }
68
69 public void Initialise(IConfigSource source)
70 {
71
72 }
73
74 public void AddRegion(Scene pScene)
75 {
76 m_scene = pScene;
77 }
78
79 public void RemoveRegion(Scene scene)
80 {
81
82 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
83 m_scene = null;
84 }
85
86 public void RegionLoaded(Scene scene)
87 {
88
89 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
90 }
91
92 #endregion
93
94
95 #region Region Module interface
96
97
98
99 public void Close() { }
100
101 public string Name { get { return "UploadObjectAssetModuleModule"; } }
102
103
104 public void RegisterCaps(UUID agentID, Caps caps)
105 {
106 UUID capID = UUID.Random();
107
108// m_log.Debug("[UPLOAD OBJECT ASSET MODULE]: /CAPS/" + capID);
109 caps.RegisterHandler(
110 "UploadObjectAsset",
111 new RestHTTPHandler(
112 "POST",
113 "/CAPS/OA/" + capID + "/",
114 httpMethod => ProcessAdd(httpMethod, agentID, caps),
115 "UploadObjectAsset",
116 agentID.ToString()));
117
118 /*
119 caps.RegisterHandler("NewFileAgentInventoryVariablePrice",
120
121 new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDNewFileAngentInventoryVariablePriceReplyResponse>("POST",
122 "/CAPS/" + capID.ToString(),
123 delegate(LLSDAssetUploadRequest req)
124 {
125 return NewAgentInventoryRequest(req,agentID);
126 }));
127 */
128
129 }
130
131 #endregion
132
133
134 /// <summary>
135 /// Parses add request
136 /// </summary>
137 /// <param name="request"></param>
138 /// <param name="AgentId"></param>
139 /// <param name="cap"></param>
140 /// <returns></returns>
141 public Hashtable ProcessAdd(Hashtable request, UUID AgentId, Caps cap)
142 {
143 Hashtable responsedata = new Hashtable();
144 responsedata["int_response_code"] = 400; //501; //410; //404;
145 responsedata["content_type"] = "text/plain";
146 responsedata["keepalive"] = false;
147 responsedata["str_response_string"] = "Request wasn't what was expected";
148 ScenePresence avatar;
149
150 if (!m_scene.TryGetScenePresence(AgentId, out avatar))
151 return responsedata;
152
153 OSDMap r = (OSDMap)OSDParser.Deserialize((string)request["requestbody"]);
154 UploadObjectAssetMessage message = new UploadObjectAssetMessage();
155 try
156 {
157 message.Deserialize(r);
158
159 }
160 catch (Exception ex)
161 {
162 m_log.Error("[UPLOAD OBJECT ASSET MODULE]: Error deserializing message " + ex.ToString());
163 message = null;
164 }
165
166 if (message == null)
167 {
168 responsedata["int_response_code"] = 400; //501; //410; //404;
169 responsedata["content_type"] = "text/plain";
170 responsedata["keepalive"] = false;
171 responsedata["str_response_string"] =
172 "<llsd><map><key>error</key><string>Error parsing Object</string></map></llsd>";
173
174 return responsedata;
175 }
176
177 Vector3 pos = avatar.AbsolutePosition + (Vector3.UnitX * avatar.Rotation);
178 Quaternion rot = Quaternion.Identity;
179 Vector3 rootpos = Vector3.Zero;
180// Quaternion rootrot = Quaternion.Identity;
181
182 SceneObjectGroup rootGroup = null;
183 SceneObjectGroup[] allparts = new SceneObjectGroup[message.Objects.Length];
184 for (int i = 0; i < message.Objects.Length; i++)
185 {
186 UploadObjectAssetMessage.Object obj = message.Objects[i];
187 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox();
188
189 if (i == 0)
190 {
191 rootpos = obj.Position;
192// rootrot = obj.Rotation;
193 }
194
195 // Combine the extraparams data into it's ugly blob again....
196 //int bytelength = 0;
197 //for (int extparams = 0; extparams < obj.ExtraParams.Length; extparams++)
198 //{
199 // bytelength += obj.ExtraParams[extparams].ExtraParamData.Length;
200 //}
201 //byte[] extraparams = new byte[bytelength];
202 //int position = 0;
203
204
205
206 //for (int extparams = 0; extparams < obj.ExtraParams.Length; extparams++)
207 //{
208 // Buffer.BlockCopy(obj.ExtraParams[extparams].ExtraParamData, 0, extraparams, position,
209 // obj.ExtraParams[extparams].ExtraParamData.Length);
210 //
211 // position += obj.ExtraParams[extparams].ExtraParamData.Length;
212 // }
213
214 //pbs.ExtraParams = extraparams;
215 for (int extparams = 0; extparams < obj.ExtraParams.Length; extparams++)
216 {
217 UploadObjectAssetMessage.Object.ExtraParam extraParam = obj.ExtraParams[extparams];
218 switch ((ushort)extraParam.Type)
219 {
220 case (ushort)ExtraParamType.Sculpt:
221 Primitive.SculptData sculpt = new Primitive.SculptData(extraParam.ExtraParamData, 0);
222
223 pbs.SculptEntry = true;
224
225 pbs.SculptTexture = obj.SculptID;
226 pbs.SculptType = (byte)sculpt.Type;
227
228 break;
229 case (ushort)ExtraParamType.Flexible:
230 Primitive.FlexibleData flex = new Primitive.FlexibleData(extraParam.ExtraParamData, 0);
231 pbs.FlexiEntry = true;
232 pbs.FlexiDrag = flex.Drag;
233 pbs.FlexiForceX = flex.Force.X;
234 pbs.FlexiForceY = flex.Force.Y;
235 pbs.FlexiForceZ = flex.Force.Z;
236 pbs.FlexiGravity = flex.Gravity;
237 pbs.FlexiSoftness = flex.Softness;
238 pbs.FlexiTension = flex.Tension;
239 pbs.FlexiWind = flex.Wind;
240 break;
241 case (ushort)ExtraParamType.Light:
242 Primitive.LightData light = new Primitive.LightData(extraParam.ExtraParamData, 0);
243 pbs.LightColorA = light.Color.A;
244 pbs.LightColorB = light.Color.B;
245 pbs.LightColorG = light.Color.G;
246 pbs.LightColorR = light.Color.R;
247 pbs.LightCutoff = light.Cutoff;
248 pbs.LightEntry = true;
249 pbs.LightFalloff = light.Falloff;
250 pbs.LightIntensity = light.Intensity;
251 pbs.LightRadius = light.Radius;
252 break;
253 case 0x40:
254 pbs.ReadProjectionData(extraParam.ExtraParamData, 0);
255 break;
256 }
257 }
258
259 pbs.PathBegin = (ushort) obj.PathBegin;
260 pbs.PathCurve = (byte) obj.PathCurve;
261 pbs.PathEnd = (ushort) obj.PathEnd;
262 pbs.PathRadiusOffset = (sbyte) obj.RadiusOffset;
263 pbs.PathRevolutions = (byte) obj.Revolutions;
264 pbs.PathScaleX = (byte) obj.ScaleX;
265 pbs.PathScaleY = (byte) obj.ScaleY;
266 pbs.PathShearX = (byte) obj.ShearX;
267 pbs.PathShearY = (byte) obj.ShearY;
268 pbs.PathSkew = (sbyte) obj.Skew;
269 pbs.PathTaperX = (sbyte) obj.TaperX;
270 pbs.PathTaperY = (sbyte) obj.TaperY;
271 pbs.PathTwist = (sbyte) obj.Twist;
272 pbs.PathTwistBegin = (sbyte) obj.TwistBegin;
273 pbs.HollowShape = (HollowShape) obj.ProfileHollow;
274 pbs.PCode = (byte) PCode.Prim;
275 pbs.ProfileBegin = (ushort) obj.ProfileBegin;
276 pbs.ProfileCurve = (byte) obj.ProfileCurve;
277 pbs.ProfileEnd = (ushort) obj.ProfileEnd;
278 pbs.Scale = obj.Scale;
279 pbs.State = (byte) 0;
280 pbs.LastAttachPoint = (byte) 0;
281 SceneObjectPart prim = new SceneObjectPart();
282 prim.UUID = UUID.Random();
283 prim.CreatorID = AgentId;
284 prim.OwnerID = AgentId;
285 prim.GroupID = obj.GroupID;
286 prim.LastOwnerID = prim.OwnerID;
287 prim.RezzerID = AgentId;
288 prim.CreationDate = Util.UnixTimeSinceEpoch();
289 prim.Name = obj.Name;
290 prim.Description = "";
291
292 prim.PayPrice[0] = -2;
293 prim.PayPrice[1] = -2;
294 prim.PayPrice[2] = -2;
295 prim.PayPrice[3] = -2;
296 prim.PayPrice[4] = -2;
297 Primitive.TextureEntry tmp =
298 new Primitive.TextureEntry(UUID.Parse("89556747-24cb-43ed-920b-47caed15465f"));
299
300 for (int j = 0; j < obj.Faces.Length; j++)
301 {
302 UploadObjectAssetMessage.Object.Face face = obj.Faces[j];
303
304 Primitive.TextureEntryFace primFace = tmp.CreateFace((uint) j);
305
306 primFace.Bump = face.Bump;
307 primFace.RGBA = face.Color;
308 primFace.Fullbright = face.Fullbright;
309 primFace.Glow = face.Glow;
310 primFace.TextureID = face.ImageID;
311 primFace.Rotation = face.ImageRot;
312 primFace.MediaFlags = ((face.MediaFlags & 1) != 0);
313
314 primFace.OffsetU = face.OffsetS;
315 primFace.OffsetV = face.OffsetT;
316 primFace.RepeatU = face.ScaleS;
317 primFace.RepeatV = face.ScaleT;
318 primFace.TexMapType = (MappingType) (face.MediaFlags & 6);
319 }
320
321 pbs.TextureEntry = tmp.GetBytes();
322 prim.Shape = pbs;
323 prim.Scale = obj.Scale;
324
325 SceneObjectGroup grp = new SceneObjectGroup();
326
327 grp.SetRootPart(prim);
328 prim.ParentID = 0;
329 if (i == 0)
330 {
331 rootGroup = grp;
332
333 }
334 grp.AttachToScene(m_scene);
335 grp.AbsolutePosition = obj.Position;
336 prim.RotationOffset = obj.Rotation;
337
338
339 // Required for linking
340 grp.RootPart.ClearUpdateSchedule();
341
342 if (m_scene.Permissions.CanRezObject(1, avatar.UUID, pos))
343 {
344 m_scene.AddSceneObject(grp);
345 grp.AbsolutePosition = obj.Position;
346 }
347
348 allparts[i] = grp;
349 }
350
351 for (int j = 1; j < allparts.Length; j++)
352 {
353 // Required for linking
354 rootGroup.RootPart.ClearUpdateSchedule();
355 allparts[j].RootPart.ClearUpdateSchedule();
356 rootGroup.LinkToGroup(allparts[j]);
357 }
358
359 rootGroup.ScheduleGroupForFullUpdate();
360 pos
361 = m_scene.GetNewRezLocation(
362 Vector3.Zero, rootpos, UUID.Zero, rot, (byte)1, 1, true, allparts[0].GroupScale, false);
363
364 responsedata["int_response_code"] = 200; //501; //410; //404;
365 responsedata["content_type"] = "text/plain";
366 responsedata["keepalive"] = false;
367 responsedata["str_response_string"] = String.Format("<llsd><map><key>local_id</key>{0}</map></llsd>", ConvertUintToBytes(allparts[0].LocalId));
368
369 return responsedata;
370 }
371
372 private string ConvertUintToBytes(uint val)
373 {
374 byte[] resultbytes = Utils.UIntToBytes(val);
375 if (BitConverter.IsLittleEndian)
376 Array.Reverse(resultbytes);
377 return String.Format("<binary encoding=\"base64\">{0}</binary>", Convert.ToBase64String(resultbytes));
378 }
379 }
380} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs b/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..f36826b
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs
@@ -0,0 +1,33 @@
1using System.Reflection;
2using System.Runtime.CompilerServices;
3using System.Runtime.InteropServices;
4
5// General Information about an assembly is controlled through the following
6// set of attributes. Change these attribute values to modify the information
7// associated with an assembly.
8[assembly: AssemblyTitle("OpenSim.Region.ClientStack.LindenCaps")]
9[assembly: AssemblyDescription("")]
10[assembly: AssemblyConfiguration("")]
11[assembly: AssemblyCompany("http://opensimulator.org")]
12[assembly: AssemblyProduct("OpenSim")]
13[assembly: AssemblyCopyright("OpenSimulator developers")]
14[assembly: AssemblyTrademark("")]
15[assembly: AssemblyCulture("")]
16
17// Setting ComVisible to false makes the types in this assembly not visible
18// to COM components. If you need to access a type in this assembly from
19// COM, set the ComVisible attribute to true on that type.
20[assembly: ComVisible(false)]
21
22// The following GUID is for the ID of the typelib if this project is exposed to COM
23[assembly: Guid("1ae76353-f37f-4fe3-b6df-d11cedf01f2c")]
24
25// Version information for an assembly consists of the following four values:
26//
27// Major Version
28// Minor Version
29// Build Number
30// Revision
31//
32[assembly: AssemblyVersion(OpenSim.VersionInfo.AssemblyVersionNumber)]
33
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
new file mode 100644
index 0000000..e8387e3
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
@@ -0,0 +1,242 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Collections.Specialized;
32using System.Drawing;
33using System.Drawing.Imaging;
34using System.Reflection;
35using System.IO;
36using System.Web;
37using log4net;
38using Nini.Config;
39using Mono.Addins;
40using OpenMetaverse;
41using OpenMetaverse.StructuredData;
42using OpenMetaverse.Imaging;
43using OpenSim.Framework;
44using OpenSim.Framework.Console;
45using OpenSim.Framework.Servers;
46using OpenSim.Framework.Servers.HttpServer;
47using OpenSim.Region.Framework.Interfaces;
48using OpenSim.Region.Framework.Scenes;
49using OpenSim.Services.Interfaces;
50using Caps = OpenSim.Framework.Capabilities.Caps;
51using OpenSim.Capabilities.Handlers;
52
53namespace OpenSim.Region.ClientStack.Linden
54{
55
56 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "RegionConsoleModule")]
57 public class RegionConsoleModule : INonSharedRegionModule, IRegionConsole
58 {
59// private static readonly ILog m_log =
60// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
61
62 private Scene m_scene;
63 private IEventQueue m_eventQueue;
64 private Commands m_commands = new Commands();
65 public ICommands Commands { get { return m_commands; } }
66
67 public event ConsoleMessage OnConsoleMessage;
68
69 public void Initialise(IConfigSource source)
70 {
71 m_commands.AddCommand( "Help", false, "help", "help [<item>]", "Display help on a particular command or on a list of commands in a category", Help);
72 }
73
74 public void AddRegion(Scene s)
75 {
76 m_scene = s;
77 m_scene.RegisterModuleInterface<IRegionConsole>(this);
78 }
79
80 public void RemoveRegion(Scene s)
81 {
82 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
83 m_scene = null;
84 }
85
86 public void RegionLoaded(Scene s)
87 {
88 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
89 m_eventQueue = m_scene.RequestModuleInterface<IEventQueue>();
90 }
91
92 public void PostInitialise()
93 {
94 }
95
96 public void Close() { }
97
98 public string Name { get { return "RegionConsoleModule"; } }
99
100 public Type ReplaceableInterface
101 {
102 get { return null; }
103 }
104
105 public void RegisterCaps(UUID agentID, Caps caps)
106 {
107 if (!m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(agentID) && !m_scene.Permissions.IsGod(agentID))
108 return;
109
110 UUID capID = UUID.Random();
111
112// m_log.DebugFormat("[REGION CONSOLE]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName);
113 caps.RegisterHandler(
114 "SimConsoleAsync",
115 new ConsoleHandler("/CAPS/" + capID + "/", "SimConsoleAsync", agentID, this, m_scene));
116 }
117
118 public void SendConsoleOutput(UUID agentID, string message)
119 {
120 OSD osd = OSD.FromString(message);
121
122 m_eventQueue.Enqueue(EventQueueHelper.BuildEvent("SimConsoleResponse", osd), agentID);
123
124 ConsoleMessage handlerConsoleMessage = OnConsoleMessage;
125
126 if (handlerConsoleMessage != null)
127 handlerConsoleMessage( agentID, message);
128 }
129
130 public bool RunCommand(string command, UUID invokerID)
131 {
132 string[] parts = Parser.Parse(command);
133 Array.Resize(ref parts, parts.Length + 1);
134 parts[parts.Length - 1] = invokerID.ToString();
135
136 if (m_commands.Resolve(parts).Length == 0)
137 return false;
138
139 return true;
140 }
141
142 private void Help(string module, string[] cmd)
143 {
144 UUID agentID = new UUID(cmd[cmd.Length - 1]);
145 Array.Resize(ref cmd, cmd.Length - 1);
146
147 List<string> help = Commands.GetHelp(cmd);
148
149 string reply = String.Empty;
150
151 foreach (string s in help)
152 {
153 reply += s + "\n";
154 }
155
156 SendConsoleOutput(agentID, reply);
157 }
158
159 public void AddCommand(string module, bool shared, string command, string help, string longhelp, CommandDelegate fn)
160 {
161 m_commands.AddCommand(module, shared, command, help, longhelp, fn);
162 }
163 }
164
165 public class ConsoleHandler : BaseStreamHandler
166 {
167// private static readonly ILog m_log =
168// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
169
170 private RegionConsoleModule m_consoleModule;
171 private UUID m_agentID;
172 private bool m_isGod;
173 private Scene m_scene;
174 private bool m_consoleIsOn = false;
175
176 public ConsoleHandler(string path, string name, UUID agentID, RegionConsoleModule module, Scene scene)
177 :base("POST", path, name, agentID.ToString())
178 {
179 m_agentID = agentID;
180 m_consoleModule = module;
181 m_scene = scene;
182
183 m_isGod = m_scene.Permissions.IsGod(agentID);
184 }
185
186 protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
187 {
188 string message;
189 using(StreamReader reader = new StreamReader(request))
190 message = reader.ReadToEnd();
191
192 OSD osd = OSDParser.DeserializeLLSDXml(message);
193
194 string cmd = osd.AsString();
195 if (cmd == "set console on")
196 {
197 if (m_isGod)
198 {
199 MainConsole.Instance.OnOutput += ConsoleSender;
200 m_consoleIsOn = true;
201 m_consoleModule.SendConsoleOutput(m_agentID, "Console is now on");
202 }
203 return new byte[0];
204 }
205 else if (cmd == "set console off")
206 {
207 MainConsole.Instance.OnOutput -= ConsoleSender;
208 m_consoleIsOn = false;
209 m_consoleModule.SendConsoleOutput(m_agentID, "Console is now off");
210 return new byte[0];
211 }
212
213 if (m_consoleIsOn == false && m_consoleModule.RunCommand(osd.AsString().Trim(), m_agentID))
214 return new byte[0];
215
216 if (m_isGod && m_consoleIsOn)
217 {
218 MainConsole.Instance.RunCommand(osd.AsString().Trim());
219 }
220 else
221 {
222 m_consoleModule.SendConsoleOutput(m_agentID, "Unknown command");
223 }
224
225 return new byte[0];
226 }
227
228 private void ConsoleSender(string text)
229 {
230 m_consoleModule.SendConsoleOutput(m_agentID, text);
231 }
232
233 private void OnMakeChildAgent(ScenePresence presence)
234 {
235 if (presence.UUID == m_agentID)
236 {
237 MainConsole.Instance.OnOutput -= ConsoleSender;
238 m_consoleIsOn = false;
239 }
240 }
241 }
242}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs
new file mode 100644
index 0000000..39f5baf
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs
@@ -0,0 +1,304 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Reflection;
32using log4net;
33using Nini.Config;
34using Mono.Addins;
35using OpenMetaverse;
36using OpenMetaverse.StructuredData;
37using OpenSim.Framework;
38using OpenSim.Framework.Servers.HttpServer;
39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Region.Framework.Scenes;
41// using OpenSim.Services.Interfaces;
42using Caps = OpenSim.Framework.Capabilities.Caps;
43
44namespace OpenSim.Region.ClientStack.Linden
45{
46 /// <summary>
47 /// SimulatorFeatures capability.
48 /// </summary>
49 /// <remarks>
50 /// This is required for uploading Mesh.
51 /// Since is accepts an open-ended response, we also send more information
52 /// for viewers that care to interpret it.
53 ///
54 /// NOTE: Part of this code was adapted from the Aurora project, specifically
55 /// the normal part of the response in the capability handler.
56 /// </remarks>
57 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SimulatorFeaturesModule")]
58 public class SimulatorFeaturesModule : INonSharedRegionModule, ISimulatorFeaturesModule
59 {
60 private static readonly ILog m_log =
61 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
62
63 public event SimulatorFeaturesRequestDelegate OnSimulatorFeaturesRequest;
64
65 private Scene m_scene;
66
67 /// <summary>
68 /// Simulator features
69 /// </summary>
70 private OSDMap m_features = new OSDMap();
71
72 private string m_SearchURL = string.Empty;
73 private string m_DestinationGuideURL = string.Empty;
74 private bool m_ExportSupported = false;
75 private string m_GridName = string.Empty;
76 private string m_GridURL = string.Empty;
77
78 #region ISharedRegionModule Members
79
80 public void Initialise(IConfigSource source)
81 {
82 IConfig config = source.Configs["SimulatorFeatures"];
83
84 if (config != null)
85 {
86 //
87 // All this is obsolete since getting these features from the grid service!!
88 // Will be removed after the next release
89 //
90 m_SearchURL = config.GetString("SearchServerURI", m_SearchURL);
91
92 m_DestinationGuideURL = config.GetString ("DestinationGuideURI", m_DestinationGuideURL);
93
94 if (m_DestinationGuideURL == string.Empty) // Make this consistent with the variable in the LoginService config
95 m_DestinationGuideURL = config.GetString("DestinationGuide", m_DestinationGuideURL);
96
97 m_ExportSupported = config.GetBoolean("ExportSupported", m_ExportSupported);
98
99 m_GridURL = Util.GetConfigVarFromSections<string>(
100 source, "GatekeeperURI", new string[] { "Startup", "Hypergrid", "SimulatorFeatures" }, String.Empty);
101
102 m_GridName = config.GetString("GridName", string.Empty);
103 if (m_GridName == string.Empty)
104 m_GridName = Util.GetConfigVarFromSections<string>(
105 source, "gridname", new string[] { "GridInfo", "SimulatorFeatures" }, String.Empty);
106 }
107
108 AddDefaultFeatures();
109 }
110
111 public void AddRegion(Scene s)
112 {
113 m_scene = s;
114 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
115
116 m_scene.RegisterModuleInterface<ISimulatorFeaturesModule>(this);
117 }
118
119 public void RemoveRegion(Scene s)
120 {
121 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
122 }
123
124 public void RegionLoaded(Scene s)
125 {
126 GetGridExtraFeatures(s);
127 }
128
129 public void Close() { }
130
131 public string Name { get { return "SimulatorFeaturesModule"; } }
132
133 public Type ReplaceableInterface
134 {
135 get { return null; }
136 }
137
138 #endregion
139
140 /// <summary>
141 /// Add default features
142 /// </summary>
143 /// <remarks>
144 /// TODO: These should be added from other modules rather than hardcoded.
145 /// </remarks>
146 private void AddDefaultFeatures()
147 {
148
149 lock (m_features)
150 {
151 m_features["MeshRezEnabled"] = true;
152 m_features["MeshUploadEnabled"] = true;
153 m_features["MeshXferEnabled"] = true;
154
155 m_features["PhysicsMaterialsEnabled"] = true;
156
157 OSDMap typesMap = new OSDMap();
158 typesMap["convex"] = true;
159 typesMap["none"] = true;
160 typesMap["prim"] = true;
161 m_features["PhysicsShapeTypes"] = typesMap;
162
163 // Extra information for viewers that want to use it
164 // TODO: Take these out of here into their respective modules, like map-server-url
165 OSDMap extrasMap;
166 if(m_features.ContainsKey("OpenSimExtras"))
167 {
168 extrasMap = (OSDMap)m_features["OpenSimExtras"];
169 }
170 else
171 extrasMap = new OSDMap();
172
173 extrasMap["AvatarSkeleton"] = true;
174 extrasMap["AnimationSet"] = true;
175
176 // TODO: Take these out of here into their respective modules, like map-server-url
177 if (m_SearchURL != string.Empty)
178 extrasMap["search-server-url"] = m_SearchURL;
179 if (!string.IsNullOrEmpty(m_DestinationGuideURL))
180 extrasMap["destination-guide-url"] = m_DestinationGuideURL;
181 if (m_ExportSupported)
182 extrasMap["ExportSupported"] = true;
183 if (m_GridURL != string.Empty)
184 extrasMap["GridURL"] = m_GridURL;
185 if (m_GridName != string.Empty)
186 extrasMap["GridName"] = m_GridName;
187
188 if (extrasMap.Count > 0)
189 m_features["OpenSimExtras"] = extrasMap;
190 }
191 }
192
193 public void RegisterCaps(UUID agentID, Caps caps)
194 {
195 IRequestHandler reqHandler
196 = new RestHTTPHandler(
197 "GET", "/CAPS/" + UUID.Random(),
198 x => { return HandleSimulatorFeaturesRequest(x, agentID); }, "SimulatorFeatures", agentID.ToString());
199
200 caps.RegisterHandler("SimulatorFeatures", reqHandler);
201 }
202
203 public void AddFeature(string name, OSD value)
204 {
205 lock (m_features)
206 m_features[name] = value;
207 }
208
209 public bool RemoveFeature(string name)
210 {
211 lock (m_features)
212 return m_features.Remove(name);
213 }
214
215 public bool TryGetFeature(string name, out OSD value)
216 {
217 lock (m_features)
218 return m_features.TryGetValue(name, out value);
219 }
220
221 public OSDMap GetFeatures()
222 {
223 lock (m_features)
224 return new OSDMap(m_features);
225 }
226
227 private OSDMap DeepCopy()
228 {
229 // This isn't the cheapest way of doing this but the rate
230 // of occurrence is low (on sim entry only) and it's a sure
231 // way to get a true deep copy.
232 OSD copy = OSDParser.DeserializeLLSDXml(OSDParser.SerializeLLSDXmlString(m_features));
233
234 return (OSDMap)copy;
235 }
236
237 private Hashtable HandleSimulatorFeaturesRequest(Hashtable mDhttpMethod, UUID agentID)
238 {
239// m_log.DebugFormat("[SIMULATOR FEATURES MODULE]: SimulatorFeatures request");
240
241 OSDMap copy = DeepCopy();
242
243 // Let's add the agentID to the destination guide, if it is expecting that.
244 if (copy.ContainsKey("OpenSimExtras") && ((OSDMap)(copy["OpenSimExtras"])).ContainsKey("destination-guide-url"))
245 ((OSDMap)copy["OpenSimExtras"])["destination-guide-url"] = Replace(((OSDMap)copy["OpenSimExtras"])["destination-guide-url"], "[USERID]", agentID.ToString());
246
247 SimulatorFeaturesRequestDelegate handlerOnSimulatorFeaturesRequest = OnSimulatorFeaturesRequest;
248
249 if (handlerOnSimulatorFeaturesRequest != null)
250 handlerOnSimulatorFeaturesRequest(agentID, ref copy);
251
252 //Send back data
253 Hashtable responsedata = new Hashtable();
254 responsedata["int_response_code"] = 200;
255 responsedata["content_type"] = "text/plain";
256 responsedata["keepalive"] = false;
257
258 responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(copy);
259
260 return responsedata;
261 }
262
263 /// <summary>
264 /// Gets the grid extra features.
265 /// </summary>
266 /// <param name='featuresURI'>
267 /// The URI Robust uses to handle the get_extra_features request
268 /// </param>
269 private void GetGridExtraFeatures(Scene scene)
270 {
271 Dictionary<string, object> extraFeatures = scene.GridService.GetExtraFeatures();
272 if (extraFeatures.ContainsKey("Result") && extraFeatures["Result"] != null && extraFeatures["Result"].ToString() == "Failure")
273 {
274 m_log.WarnFormat("[SIMULATOR FEATURES MODULE]: Unable to retrieve grid-wide features");
275 return;
276 }
277
278 lock (m_features)
279 {
280 OSDMap extrasMap = new OSDMap();
281
282 foreach(string key in extraFeatures.Keys)
283 {
284 extrasMap[key] = (string)extraFeatures[key];
285
286 if (key == "ExportSupported")
287 {
288 bool.TryParse(extraFeatures[key].ToString(), out m_ExportSupported);
289 }
290 }
291 m_features["OpenSimExtras"] = extrasMap;
292
293 }
294 }
295
296 private string Replace(string url, string substring, string replacement)
297 {
298 if (!String.IsNullOrEmpty(url) && url.Contains(substring))
299 return url.Replace(substring, replacement);
300
301 return url;
302 }
303 }
304}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/Tests/WebFetchInvDescModuleTests.cs b/OpenSim/Region/ClientStack/Linden/Caps/Tests/WebFetchInvDescModuleTests.cs
new file mode 100644
index 0000000..6ffed4d
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/Tests/WebFetchInvDescModuleTests.cs
@@ -0,0 +1,161 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.IO;
32using System.Net;
33using System.Text;
34using HttpServer;
35using log4net.Config;
36using Nini.Config;
37using NUnit.Framework;
38using OpenMetaverse;
39using OpenMetaverse.Packets;
40using OpenMetaverse.StructuredData;
41using OpenSim.Framework;
42using OpenSim.Framework.Capabilities;
43using OpenSim.Framework.Servers;
44using OpenSim.Framework.Servers.HttpServer;
45using OpenSim.Region.ClientStack.Linden;
46using OpenSim.Region.CoreModules.Framework;
47using OpenSim.Region.Framework.Scenes;
48using OpenSim.Services.Interfaces;
49using OpenSim.Tests.Common;
50using OSDArray = OpenMetaverse.StructuredData.OSDArray;
51using OSDMap = OpenMetaverse.StructuredData.OSDMap;
52
53namespace OpenSim.Region.ClientStack.Linden.Caps.Tests
54{
55 /*
56 [TestFixture]
57 public class WebFetchInvDescModuleTests : OpenSimTestCase
58 {
59 [TestFixtureSetUp]
60 public void TestFixtureSetUp()
61 {
62 // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
63 Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest;
64 }
65
66 [TestFixtureTearDown]
67 public void TestFixureTearDown()
68 {
69 // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
70 // threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression
71 // tests really shouldn't).
72 Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
73 }
74
75 [SetUp]
76 public override void SetUp()
77 {
78 base.SetUp();
79
80 // This is an unfortunate bit of clean up we have to do because MainServer manages things through static
81 // variables and the VM is not restarted between tests.
82 uint port = 9999;
83 MainServer.RemoveHttpServer(port);
84
85 BaseHttpServer server = new BaseHttpServer(port, false, 0, "");
86 MainServer.AddHttpServer(server);
87 MainServer.Instance = server;
88
89 server.Start(false);
90 }
91
92 [Test]
93 public void TestInventoryDescendentsFetch()
94 {
95 TestHelpers.InMethod();
96 TestHelpers.EnableLogging();
97
98 BaseHttpServer httpServer = MainServer.Instance;
99 Scene scene = new SceneHelpers().SetupScene();
100
101 CapabilitiesModule capsModule = new CapabilitiesModule();
102 WebFetchInvDescModule wfidModule = new WebFetchInvDescModule(false);
103
104 IConfigSource config = new IniConfigSource();
105 config.AddConfig("ClientStack.LindenCaps");
106 config.Configs["ClientStack.LindenCaps"].Set("Cap_FetchInventoryDescendents2", "localhost");
107
108 SceneHelpers.SetupSceneModules(scene, config, capsModule, wfidModule);
109
110 UserAccount ua = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(0x1));
111
112 // We need a user present to have any capabilities set up
113 SceneHelpers.AddScenePresence(scene, ua.PrincipalID);
114
115 TestHttpRequest req = new TestHttpRequest();
116 OpenSim.Framework.Capabilities.Caps userCaps = capsModule.GetCapsForUser(ua.PrincipalID);
117 PollServiceEventArgs pseArgs;
118 userCaps.TryGetPollHandler("FetchInventoryDescendents2", out pseArgs);
119 req.UriPath = pseArgs.Url;
120 req.Uri = new Uri("file://" + req.UriPath);
121
122 // Retrieve root folder details directly so that we can request
123 InventoryFolderBase folder = scene.InventoryService.GetRootFolder(ua.PrincipalID);
124
125 OSDMap osdFolder = new OSDMap();
126 osdFolder["folder_id"] = folder.ID;
127 osdFolder["owner_id"] = ua.PrincipalID;
128 osdFolder["fetch_folders"] = true;
129 osdFolder["fetch_items"] = true;
130 osdFolder["sort_order"] = 0;
131
132 OSDArray osdFoldersArray = new OSDArray();
133 osdFoldersArray.Add(osdFolder);
134
135 OSDMap osdReqMap = new OSDMap();
136 osdReqMap["folders"] = osdFoldersArray;
137
138 req.Body = new MemoryStream(OSDParser.SerializeLLSDXmlBytes(osdReqMap));
139
140 TestHttpClientContext context = new TestHttpClientContext(false);
141
142 // WARNING: This results in a caught exception, because queryString is null
143 MainServer.Instance.OnRequest(context, new RequestEventArgs(req));
144
145 // Drive processing of the queued inventory request synchronously.
146 wfidModule.WaitProcessQueuedInventoryRequest();
147 MainServer.Instance.PollServiceRequestManager.WaitPerformResponse();
148
149// System.Threading.Thread.Sleep(10000);
150
151 OSDMap responseOsd = (OSDMap)OSDParser.DeserializeLLSDXml(context.ResponseBody);
152 OSDArray foldersOsd = (OSDArray)responseOsd["folders"];
153 OSDMap folderOsd = (OSDMap)foldersOsd[0];
154
155 // A sanity check that the response has the expected number of descendents for a default inventory
156 // TODO: Need a more thorough check.
157 Assert.That((int)folderOsd["descendents"], Is.EqualTo(16));
158 }
159 }
160 */
161} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs
new file mode 100644
index 0000000..b406b37
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs
@@ -0,0 +1,145 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Collections.Specialized;
32using System.Drawing;
33using System.Drawing.Imaging;
34using System.Reflection;
35using System.IO;
36using System.Web;
37using log4net;
38using Nini.Config;
39using Mono.Addins;
40using OpenMetaverse;
41using OpenMetaverse.StructuredData;
42using OpenMetaverse.Imaging;
43using OpenSim.Framework;
44using OpenSim.Framework.Servers;
45using OpenSim.Framework.Servers.HttpServer;
46using OpenSim.Region.Framework.Interfaces;
47using OpenSim.Region.Framework.Scenes;
48using OpenSim.Services.Interfaces;
49using Caps = OpenSim.Framework.Capabilities.Caps;
50using OpenSim.Capabilities.Handlers;
51
52namespace OpenSim.Region.ClientStack.Linden
53{
54 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UploadBakedTextureModule")]
55 public class UploadBakedTextureModule : INonSharedRegionModule
56 {
57 private static readonly ILog m_log =
58 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
59
60 /// <summary>
61 /// For historical reasons this is fixed, but there
62 /// </summary>
63 private static readonly string m_uploadBakedTexturePath = "0010/";// This is in the LandManagementModule.
64
65 private Scene m_scene;
66
67 private string m_URL;
68
69 public void Initialise(IConfigSource source)
70 {
71 IConfig config = source.Configs["ClientStack.LindenCaps"];
72 if (config == null)
73 return;
74
75 m_URL = config.GetString("Cap_UploadBakedTexture", string.Empty);
76
77// IConfig appearanceConfig = source.Configs["Appearance"];
78 }
79
80 public void AddRegion(Scene s)
81 {
82 m_scene = s;
83 }
84
85 public void RemoveRegion(Scene s)
86 {
87 s.EventManager.OnRegisterCaps -= RegisterCaps;
88 s.EventManager.OnNewPresence -= RegisterNewPresence;
89 s.EventManager.OnRemovePresence -= DeRegisterPresence;
90 m_scene = null;
91 }
92
93 public void RegionLoaded(Scene s)
94 {
95 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
96 m_scene.EventManager.OnNewPresence += RegisterNewPresence;
97 m_scene.EventManager.OnRemovePresence += DeRegisterPresence;
98 }
99
100 private void DeRegisterPresence(UUID agentId)
101 {
102 }
103
104 private void RegisterNewPresence(ScenePresence presence)
105 {
106 }
107
108 public void PostInitialise()
109 {
110 }
111
112 public void Close() { }
113
114 public string Name { get { return "UploadBakedTextureModule"; } }
115
116 public Type ReplaceableInterface
117 {
118 get { return null; }
119 }
120
121 public void RegisterCaps(UUID agentID, Caps caps)
122 {
123 //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture));
124 if (m_URL == "localhost")
125 {
126 UploadBakedTextureHandler avatarhandler = new UploadBakedTextureHandler(
127 caps, m_scene.AssetService);
128
129 caps.RegisterHandler(
130 "UploadBakedTexture",
131 new RestStreamHandler(
132 "POST",
133 "/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath,
134 avatarhandler.UploadBakedTexture,
135 "UploadBakedTexture",
136 agentID.ToString()));
137
138 }
139 else
140 {
141 caps.RegisterHandler("UploadBakedTexture", m_URL);
142 }
143 }
144 }
145}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
new file mode 100644
index 0000000..8d4e561
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
@@ -0,0 +1,465 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Reflection;
32using System.Threading;
33using log4net;
34using Nini.Config;
35using Mono.Addins;
36using OpenMetaverse;
37using OpenSim.Framework;
38using OpenSim.Framework.Servers;
39using OpenSim.Framework.Servers.HttpServer;
40using OpenSim.Region.Framework.Interfaces;
41using OpenSim.Region.Framework.Scenes;
42using OpenSim.Framework.Capabilities;
43using OpenSim.Services.Interfaces;
44using Caps = OpenSim.Framework.Capabilities.Caps;
45using OpenSim.Capabilities.Handlers;
46using OpenSim.Framework.Monitoring;
47
48using OpenMetaverse.StructuredData;
49
50namespace OpenSim.Region.ClientStack.Linden
51{
52 /// <summary>
53 /// This module implements both WebFetchInventoryDescendents and FetchInventoryDescendents2 capabilities.
54 /// </summary>
55 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "WebFetchInvDescModule")]
56 public class WebFetchInvDescModule : INonSharedRegionModule
57 {
58 class aPollRequest
59 {
60 public PollServiceInventoryEventArgs thepoll;
61 public UUID reqID;
62 public Hashtable request;
63 public ScenePresence presence;
64 public List<UUID> folders;
65 }
66
67 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
68
69 /// <summary>
70 /// Control whether requests will be processed asynchronously.
71 /// </summary>
72 /// <remarks>
73 /// Defaults to true. Can currently not be changed once a region has been added to the module.
74 /// </remarks>
75 public bool ProcessQueuedRequestsAsync { get; private set; }
76
77 /// <summary>
78 /// Number of inventory requests processed by this module.
79 /// </summary>
80 /// <remarks>
81 /// It's the PollServiceRequestManager that actually sends completed requests back to the requester.
82 /// </remarks>
83 public static int ProcessedRequestsCount { get; set; }
84
85 private static Stat s_queuedRequestsStat;
86 private static Stat s_processedRequestsStat;
87
88 public Scene Scene { get; private set; }
89
90 private IInventoryService m_InventoryService;
91 private ILibraryService m_LibraryService;
92
93 private bool m_Enabled;
94
95 private string m_fetchInventoryDescendents2Url;
96// private string m_webFetchInventoryDescendentsUrl;
97
98 private static FetchInvDescHandler m_webFetchHandler;
99
100 private static Thread[] m_workerThreads = null;
101
102 private static OpenSim.Framework.BlockingQueue<aPollRequest> m_queue =
103 new OpenSim.Framework.BlockingQueue<aPollRequest>();
104
105 private static int m_NumberScenes = 0;
106
107 #region ISharedRegionModule Members
108
109 public WebFetchInvDescModule() : this(true) {}
110
111 public WebFetchInvDescModule(bool processQueuedResultsAsync)
112 {
113 ProcessQueuedRequestsAsync = processQueuedResultsAsync;
114 }
115
116 public void Initialise(IConfigSource source)
117 {
118 IConfig config = source.Configs["ClientStack.LindenCaps"];
119 if (config == null)
120 return;
121
122 m_fetchInventoryDescendents2Url = config.GetString("Cap_FetchInventoryDescendents2", string.Empty);
123// m_webFetchInventoryDescendentsUrl = config.GetString("Cap_WebFetchInventoryDescendents", string.Empty);
124
125// if (m_fetchInventoryDescendents2Url != string.Empty || m_webFetchInventoryDescendentsUrl != string.Empty)
126 if (m_fetchInventoryDescendents2Url != string.Empty)
127 {
128 m_Enabled = true;
129 }
130 }
131
132 public void AddRegion(Scene s)
133 {
134 if (!m_Enabled)
135 return;
136
137 Scene = s;
138 }
139
140 public void RemoveRegion(Scene s)
141 {
142 if (!m_Enabled)
143 return;
144
145 Scene.EventManager.OnRegisterCaps -= RegisterCaps;
146
147 StatsManager.DeregisterStat(s_processedRequestsStat);
148 StatsManager.DeregisterStat(s_queuedRequestsStat);
149
150 m_NumberScenes--;
151 Scene = null;
152 }
153
154 public void RegionLoaded(Scene s)
155 {
156 if (!m_Enabled)
157 return;
158
159 if (s_processedRequestsStat == null)
160 s_processedRequestsStat =
161 new Stat(
162 "ProcessedFetchInventoryRequests",
163 "Number of processed fetch inventory requests",
164 "These have not necessarily yet been dispatched back to the requester.",
165 "",
166 "inventory",
167 "httpfetch",
168 StatType.Pull,
169 MeasuresOfInterest.AverageChangeOverTime,
170 stat => { stat.Value = ProcessedRequestsCount; },
171 StatVerbosity.Debug);
172
173 if (s_queuedRequestsStat == null)
174 s_queuedRequestsStat =
175 new Stat(
176 "QueuedFetchInventoryRequests",
177 "Number of fetch inventory requests queued for processing",
178 "",
179 "",
180 "inventory",
181 "httpfetch",
182 StatType.Pull,
183 MeasuresOfInterest.AverageChangeOverTime,
184 stat => { stat.Value = m_queue.Count(); },
185 StatVerbosity.Debug);
186
187 StatsManager.RegisterStat(s_processedRequestsStat);
188 StatsManager.RegisterStat(s_queuedRequestsStat);
189
190 m_InventoryService = Scene.InventoryService;
191 m_LibraryService = Scene.LibraryService;
192
193 // We'll reuse the same handler for all requests.
194 m_webFetchHandler = new FetchInvDescHandler(m_InventoryService, m_LibraryService, Scene);
195
196 Scene.EventManager.OnRegisterCaps += RegisterCaps;
197
198 m_NumberScenes++;
199
200 int nworkers = 2; // was 2
201 if (ProcessQueuedRequestsAsync && m_workerThreads == null)
202 {
203 m_workerThreads = new Thread[nworkers];
204
205 for (uint i = 0; i < nworkers; i++)
206 {
207 m_workerThreads[i] = WorkManager.StartThread(DoInventoryRequests,
208 String.Format("InventoryWorkerThread{0}", i),
209 ThreadPriority.Normal,
210 true,
211 true,
212 null,
213 int.MaxValue);
214 }
215 }
216 }
217
218 public void PostInitialise()
219 {
220 }
221
222 public void Close()
223 {
224 if (!m_Enabled)
225 return;
226
227 if (ProcessQueuedRequestsAsync)
228 {
229 if (m_NumberScenes <= 0 && m_workerThreads != null)
230 {
231 m_log.DebugFormat("[WebFetchInvDescModule] Closing");
232 foreach (Thread t in m_workerThreads)
233 Watchdog.AbortThread(t.ManagedThreadId);
234
235 m_workerThreads = null;
236 }
237 }
238 }
239
240 public string Name { get { return "WebFetchInvDescModule"; } }
241
242 public Type ReplaceableInterface
243 {
244 get { return null; }
245 }
246
247 #endregion
248
249 private class PollServiceInventoryEventArgs : PollServiceEventArgs
250 {
251 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
252
253 private Dictionary<UUID, Hashtable> responses =
254 new Dictionary<UUID, Hashtable>();
255
256 private WebFetchInvDescModule m_module;
257
258 public PollServiceInventoryEventArgs(WebFetchInvDescModule module, string url, UUID pId) :
259 base(null, url, null, null, null, pId, int.MaxValue)
260 {
261 m_module = module;
262
263 HasEvents = (x, y) => { lock (responses) return responses.ContainsKey(x); };
264 GetEvents = (x, y) =>
265 {
266 lock (responses)
267 {
268 try
269 {
270 return responses[x];
271 }
272 finally
273 {
274 responses.Remove(x);
275 }
276 }
277 };
278
279 Request = (x, y) =>
280 {
281 ScenePresence sp = m_module.Scene.GetScenePresence(Id);
282
283 aPollRequest reqinfo = new aPollRequest();
284 reqinfo.thepoll = this;
285 reqinfo.reqID = x;
286 reqinfo.request = y;
287 reqinfo.presence = sp;
288 reqinfo.folders = new List<UUID>();
289
290 // Decode the request here
291 string request = y["body"].ToString();
292
293 request = request.Replace("<string>00000000-0000-0000-0000-000000000000</string>", "<uuid>00000000-0000-0000-0000-000000000000</uuid>");
294
295 request = request.Replace("<key>fetch_folders</key><integer>0</integer>", "<key>fetch_folders</key><boolean>0</boolean>");
296 request = request.Replace("<key>fetch_folders</key><integer>1</integer>", "<key>fetch_folders</key><boolean>1</boolean>");
297
298 Hashtable hash = new Hashtable();
299 try
300 {
301 hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request));
302 }
303 catch (LLSD.LLSDParseException e)
304 {
305 m_log.ErrorFormat("[INVENTORY]: Fetch error: {0}{1}" + e.Message, e.StackTrace);
306 m_log.Error("Request: " + request);
307 return;
308 }
309 catch (System.Xml.XmlException)
310 {
311 m_log.ErrorFormat("[INVENTORY]: XML Format error");
312 }
313
314 ArrayList foldersrequested = (ArrayList)hash["folders"];
315
316 bool highPriority = false;
317
318 for (int i = 0; i < foldersrequested.Count; i++)
319 {
320 Hashtable inventoryhash = (Hashtable)foldersrequested[i];
321 string folder = inventoryhash["folder_id"].ToString();
322 UUID folderID;
323 if (UUID.TryParse(folder, out folderID))
324 {
325 if (!reqinfo.folders.Contains(folderID))
326 {
327 if (sp.COF != UUID.Zero && sp.COF == folderID)
328 highPriority = true;
329 reqinfo.folders.Add(folderID);
330 }
331 }
332 }
333
334 if (highPriority)
335 m_queue.PriorityEnqueue(reqinfo);
336 else
337 m_queue.Enqueue(reqinfo);
338 };
339
340 NoEvents = (x, y) =>
341 {
342/*
343 lock (requests)
344 {
345 Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString());
346 requests.Remove(request);
347 }
348*/
349 Hashtable response = new Hashtable();
350
351 response["int_response_code"] = 500;
352 response["str_response_string"] = "Script timeout";
353 response["content_type"] = "text/plain";
354 response["keepalive"] = false;
355 response["reusecontext"] = false;
356
357 return response;
358 };
359 }
360
361 public void Process(aPollRequest requestinfo)
362 {
363 if(m_module == null || m_module.Scene == null || m_module.Scene.ShuttingDown)
364 return;
365
366 UUID requestID = requestinfo.reqID;
367
368 Hashtable response = new Hashtable();
369
370 response["int_response_code"] = 200;
371 response["content_type"] = "text/plain";
372 response["keepalive"] = false;
373 response["reusecontext"] = false;
374
375 response["str_response_string"] = m_webFetchHandler.FetchInventoryDescendentsRequest(
376 requestinfo.request["body"].ToString(), String.Empty, String.Empty, null, null);
377
378 lock (responses)
379 {
380 if (responses.ContainsKey(requestID))
381 m_log.WarnFormat("[FETCH INVENTORY DESCENDENTS2 MODULE]: Caught in the act of loosing responses! Please report this on mantis #7054");
382 responses[requestID] = response;
383 }
384 requestinfo.folders.Clear();
385 requestinfo.request.Clear();
386 WebFetchInvDescModule.ProcessedRequestsCount++;
387 }
388 }
389
390 private void RegisterCaps(UUID agentID, Caps caps)
391 {
392 RegisterFetchDescendentsCap(agentID, caps, "FetchInventoryDescendents2", m_fetchInventoryDescendents2Url);
393 }
394
395 private void RegisterFetchDescendentsCap(UUID agentID, Caps caps, string capName, string url)
396 {
397 string capUrl;
398
399 // disable the cap clause
400 if (url == "")
401 {
402 return;
403 }
404 // handled by the simulator
405 else if (url == "localhost")
406 {
407 capUrl = "/CAPS/" + UUID.Random() + "/";
408
409 // Register this as a poll service
410 PollServiceInventoryEventArgs args = new PollServiceInventoryEventArgs(this, capUrl, agentID);
411 args.Type = PollServiceEventArgs.EventType.Inventory;
412
413 caps.RegisterPollHandler(capName, args);
414 }
415 // external handler
416 else
417 {
418 capUrl = url;
419 IExternalCapsModule handler = Scene.RequestModuleInterface<IExternalCapsModule>();
420 if (handler != null)
421 handler.RegisterExternalUserCapsHandler(agentID,caps,capName,capUrl);
422 else
423 caps.RegisterHandler(capName, capUrl);
424 }
425
426 // m_log.DebugFormat(
427 // "[FETCH INVENTORY DESCENDENTS2 MODULE]: Registered capability {0} at {1} in region {2} for {3}",
428 // capName, capUrl, m_scene.RegionInfo.RegionName, agentID);
429 }
430
431// private void DeregisterCaps(UUID agentID, Caps caps)
432// {
433// string capUrl;
434//
435// if (m_capsDict.TryGetValue(agentID, out capUrl))
436// {
437// MainServer.Instance.RemoveHTTPHandler("", capUrl);
438// m_capsDict.Remove(agentID);
439// }
440// }
441
442 private static void DoInventoryRequests()
443 {
444 while (true)
445 {
446 aPollRequest poolreq = m_queue.Dequeue(4500);
447 Watchdog.UpdateThread();
448
449 if (poolreq != null && poolreq.thepoll != null)
450 {
451 try
452 {
453 poolreq.thepoll.Process(poolreq);
454 }
455 catch (Exception e)
456 {
457 m_log.ErrorFormat(
458 "[INVENTORY]: Failed to process queued inventory request {0} for {1}. Exception {2}",
459 poolreq.reqID, poolreq.presence != null ? poolreq.presence.Name : "unknown", e);
460 }
461 }
462 }
463 }
464 }
465}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/IncomingPacket.cs b/OpenSim/Region/ClientStack/Linden/UDP/IncomingPacket.cs
new file mode 100644
index 0000000..e22670b
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/IncomingPacket.cs
@@ -0,0 +1,63 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using OpenSim.Framework;
30using OpenMetaverse;
31using OpenMetaverse.Packets;
32
33namespace OpenSim.Region.ClientStack.LindenUDP
34{
35 /// <summary>
36 /// Holds a reference to a <seealso cref="LLUDPClient"/> and a <seealso cref="Packet"/>
37 /// for incoming packets
38 /// </summary>
39 public sealed class IncomingPacket
40 {
41 /// <summary>Client this packet came from</summary>
42 public LLClientView Client;
43
44 /// <summary>Packet data that has been received</summary>
45 public Packet Packet;
46
47 /// <summary>
48 /// No arg constructor.
49 /// </summary>
50 public IncomingPacket() {}
51
52 /// <summary>
53 /// Constructor
54 /// </summary>
55 /// <param name="client">Reference to the client this packet came from</param>
56 /// <param name="packet">Packet data</param>
57 public IncomingPacket(LLClientView client, Packet packet)
58 {
59 Client = client;
60 Packet = packet;
61 }
62 }
63}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/IncomingPacketHistoryCollection.cs b/OpenSim/Region/ClientStack/Linden/UDP/IncomingPacketHistoryCollection.cs
new file mode 100644
index 0000000..1f73a1d
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/IncomingPacketHistoryCollection.cs
@@ -0,0 +1,73 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30
31namespace OpenSim.Region.ClientStack.LindenUDP
32{
33 /// <summary>
34 /// A circular buffer and hashset for tracking incoming packet sequence
35 /// numbers
36 /// </summary>
37 public sealed class IncomingPacketHistoryCollection
38 {
39 private readonly uint[] m_items;
40 private HashSet<uint> m_hashSet;
41 private int m_first;
42 private int m_next;
43 private int m_capacity;
44
45 public IncomingPacketHistoryCollection(int capacity)
46 {
47 this.m_capacity = capacity;
48 m_items = new uint[capacity];
49 m_hashSet = new HashSet<uint>();
50 }
51
52 public bool TryEnqueue(uint ack)
53 {
54 lock (m_hashSet)
55 {
56 if (m_hashSet.Add(ack))
57 {
58 m_items[m_next] = ack;
59 m_next = (m_next + 1) % m_capacity;
60 if (m_next == m_first)
61 {
62 m_hashSet.Remove(m_items[m_first]);
63 m_first = (m_first + 1) % m_capacity;
64 }
65
66 return true;
67 }
68 }
69
70 return false;
71 }
72 }
73}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
new file mode 100644
index 0000000..0a6785c
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
@@ -0,0 +1,441 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using OpenMetaverse;
31using OpenMetaverse.Imaging;
32using OpenSim.Framework;
33using OpenSim.Region.Framework.Interfaces;
34using OpenSim.Services.Interfaces;
35using log4net;
36using System.Reflection;
37
38namespace OpenSim.Region.ClientStack.LindenUDP
39{
40 /// <summary>
41 /// Stores information about a current texture download and a reference to the texture asset
42 /// </summary>
43 public class J2KImage
44 {
45 private const int IMAGE_PACKET_SIZE = 1000;
46 private const int FIRST_PACKET_SIZE = 600;
47
48 /// <summary>
49 /// If we've requested an asset but not received it in this ticks timeframe, then allow a duplicate
50 /// request from the client to trigger a fresh asset request.
51 /// </summary>
52 /// <remarks>
53 /// There are 10,000 ticks in a millisecond
54 /// </remarks>
55 private const int ASSET_REQUEST_TIMEOUT = 100000000;
56
57 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
58
59 public uint LastSequence;
60 public float Priority;
61 public uint StartPacket;
62 public sbyte DiscardLevel;
63 public UUID TextureID;
64 public IJ2KDecoder J2KDecoder;
65 public IAssetService AssetService;
66 public UUID AgentID;
67 public IInventoryAccessModule InventoryAccessModule;
68 private OpenJPEG.J2KLayerInfo[] m_layers;
69
70 /// <summary>
71 /// Has this request decoded the asset data?
72 /// </summary>
73 public bool IsDecoded { get; private set; }
74
75 /// <summary>
76 /// Has this request received the required asset data?
77 /// </summary>
78 public bool HasAsset { get; private set; }
79
80 /// <summary>
81 /// Time in milliseconds at which the asset was requested.
82 /// </summary>
83 public long AssetRequestTime { get; private set; }
84
85 public C5.IPriorityQueueHandle<J2KImage> PriorityQueueHandle;
86
87 private uint m_currentPacket;
88 private bool m_decodeRequested;
89 private bool m_assetRequested;
90 private bool m_sentInfo;
91 private uint m_stopPacket;
92 private byte[] m_asset;
93 private LLImageManager m_imageManager;
94
95 public J2KImage(LLImageManager imageManager)
96 {
97 m_imageManager = imageManager;
98 }
99
100 /// <summary>
101 /// Sends packets for this texture to a client until packetsToSend is
102 /// hit or the transfer completes
103 /// </summary>
104 /// <param name="client">Reference to the client that the packets are destined for</param>
105 /// <param name="packetsToSend">Maximum number of packets to send during this call</param>
106 /// <param name="packetsSent">Number of packets sent during this call</param>
107 /// <returns>True if the transfer completes at the current discard level, otherwise false</returns>
108 public bool SendPackets(IClientAPI client, int packetsToSend, out int packetsSent)
109 {
110 packetsSent = 0;
111
112 if (m_currentPacket <= m_stopPacket)
113 {
114 bool sendMore = true;
115
116 if (!m_sentInfo || (m_currentPacket == 0))
117 {
118 sendMore = !SendFirstPacket(client);
119
120 m_sentInfo = true;
121 ++m_currentPacket;
122 ++packetsSent;
123 }
124 if (m_currentPacket < 2)
125 {
126 m_currentPacket = 2;
127 }
128
129 while (sendMore && packetsSent < packetsToSend && m_currentPacket <= m_stopPacket)
130 {
131 sendMore = SendPacket(client);
132 ++m_currentPacket;
133 ++packetsSent;
134 }
135 }
136
137 return (m_currentPacket > m_stopPacket);
138 }
139
140 /// <summary>
141 /// This is where we decide what we need to update
142 /// and assign the real discardLevel and packetNumber
143 /// assuming of course that the connected client might be bonkers
144 /// </summary>
145 public void RunUpdate()
146 {
147 if (!HasAsset)
148 {
149 if (!m_assetRequested || DateTime.UtcNow.Ticks > AssetRequestTime + ASSET_REQUEST_TIMEOUT)
150 {
151// m_log.DebugFormat(
152// "[J2KIMAGE]: Requesting asset {0} from request in packet {1}, already requested? {2}, due to timeout? {3}",
153// TextureID, LastSequence, m_assetRequested, DateTime.UtcNow.Ticks > AssetRequestTime + ASSET_REQUEST_TIMEOUT);
154
155 m_assetRequested = true;
156 AssetRequestTime = DateTime.UtcNow.Ticks;
157
158 AssetService.Get(TextureID.ToString(), this, AssetReceived);
159 }
160 }
161 else
162 {
163 if (!IsDecoded)
164 {
165 //We need to decode the requested image first
166 if (!m_decodeRequested)
167 {
168 //Request decode
169 m_decodeRequested = true;
170
171// m_log.DebugFormat("[J2KIMAGE]: Requesting decode of asset {0}", TextureID);
172
173 // Do we have a jpeg decoder?
174 if (J2KDecoder != null)
175 {
176 if (m_asset == null)
177 {
178 J2KDecodedCallback(TextureID, new OpenJPEG.J2KLayerInfo[0]);
179 }
180 else
181 {
182 // Send it off to the jpeg decoder
183 J2KDecoder.BeginDecode(TextureID, m_asset, J2KDecodedCallback);
184 }
185 }
186 else
187 {
188 J2KDecodedCallback(TextureID, new OpenJPEG.J2KLayerInfo[0]);
189 }
190 }
191 }
192 else
193 {
194 // Check for missing image asset data
195 if (m_asset == null)
196 {
197 m_log.Warn("[J2KIMAGE]: RunUpdate() called with missing asset data (no missing image texture?). Canceling texture transfer");
198 m_currentPacket = m_stopPacket;
199 return;
200 }
201
202 if (DiscardLevel >= 0 || m_stopPacket == 0)
203 {
204 // This shouldn't happen, but if it does, we really can't proceed
205 if (m_layers == null)
206 {
207 m_log.Warn("[J2KIMAGE]: RunUpdate() called with missing Layers. Canceling texture transfer");
208 m_currentPacket = m_stopPacket;
209 return;
210 }
211
212 int maxDiscardLevel = Math.Max(0, m_layers.Length - 1);
213
214 // Treat initial texture downloads with a DiscardLevel of -1 a request for the highest DiscardLevel
215 if (DiscardLevel < 0 && m_stopPacket == 0)
216 DiscardLevel = (sbyte)maxDiscardLevel;
217
218 // Clamp at the highest discard level
219 DiscardLevel = (sbyte)Math.Min(DiscardLevel, maxDiscardLevel);
220
221 //Calculate the m_stopPacket
222 if (m_layers.Length > 0)
223 {
224 m_stopPacket = (uint)GetPacketForBytePosition(m_layers[(m_layers.Length - 1) - DiscardLevel].End);
225 //I don't know why, but the viewer seems to expect the final packet if the file
226 //is just one packet bigger.
227 if (TexturePacketCount() == m_stopPacket + 1)
228 {
229 m_stopPacket = TexturePacketCount();
230 }
231 }
232 else
233 {
234 m_stopPacket = TexturePacketCount();
235 }
236
237 //Give them at least two packets, to play nice with some broken viewers (SL also behaves this way)
238 if (m_stopPacket == 1 && m_layers[0].End > FIRST_PACKET_SIZE) m_stopPacket++;
239
240 m_currentPacket = StartPacket;
241 }
242 }
243 }
244 }
245
246 private bool SendFirstPacket(IClientAPI client)
247 {
248 if (client == null)
249 return false;
250
251 if (m_asset == null)
252 {
253 m_log.Warn("[J2KIMAGE]: Sending ImageNotInDatabase for texture " + TextureID);
254 client.SendImageNotFound(TextureID);
255 return true;
256 }
257 else if (m_asset.Length <= FIRST_PACKET_SIZE)
258 {
259 // We have less then one packet's worth of data
260 client.SendImageFirstPart(1, TextureID, (uint)m_asset.Length, m_asset, 2);
261 m_stopPacket = 0;
262 return true;
263 }
264 else
265 {
266 // This is going to be a multi-packet texture download
267 byte[] firstImageData = new byte[FIRST_PACKET_SIZE];
268
269 try { Buffer.BlockCopy(m_asset, 0, firstImageData, 0, FIRST_PACKET_SIZE); }
270 catch (Exception)
271 {
272 m_log.ErrorFormat("[J2KIMAGE]: Texture block copy for the first packet failed. textureid={0}, assetlength={1}", TextureID, m_asset.Length);
273 return true;
274 }
275
276 client.SendImageFirstPart(TexturePacketCount(), TextureID, (uint)m_asset.Length, firstImageData, (byte)ImageCodec.J2C);
277 }
278 return false;
279 }
280
281 private bool SendPacket(IClientAPI client)
282 {
283 if (client == null)
284 return false;
285
286 bool complete = false;
287 int imagePacketSize = ((int)m_currentPacket == (TexturePacketCount())) ? LastPacketSize() : IMAGE_PACKET_SIZE;
288
289 try
290 {
291 if ((CurrentBytePosition() + IMAGE_PACKET_SIZE) > m_asset.Length)
292 {
293 imagePacketSize = LastPacketSize();
294 complete = true;
295 if ((CurrentBytePosition() + imagePacketSize) > m_asset.Length)
296 {
297 imagePacketSize = m_asset.Length - CurrentBytePosition();
298 complete = true;
299 }
300 }
301
302 // It's concievable that the client might request packet one
303 // from a one packet image, which is really packet 0,
304 // which would leave us with a negative imagePacketSize..
305 if (imagePacketSize > 0)
306 {
307 byte[] imageData = new byte[imagePacketSize];
308 int currentPosition = CurrentBytePosition();
309
310 try { Buffer.BlockCopy(m_asset, currentPosition, imageData, 0, imagePacketSize); }
311 catch (Exception e)
312 {
313 m_log.ErrorFormat("[J2KIMAGE]: Texture block copy for the first packet failed. textureid={0}, assetlength={1}, currentposition={2}, imagepacketsize={3}, exception={4}",
314 TextureID, m_asset.Length, currentPosition, imagePacketSize, e.Message);
315 return false;
316 }
317
318 //Send the packet
319 client.SendImageNextPart((ushort)(m_currentPacket - 1), TextureID, imageData);
320 }
321
322 return !complete;
323 }
324 catch (Exception)
325 {
326 return false;
327 }
328 }
329
330 private ushort TexturePacketCount()
331 {
332 if (!IsDecoded)
333 return 0;
334
335 if (m_asset == null)
336 return 0;
337
338 if (m_asset.Length <= FIRST_PACKET_SIZE)
339 return 1;
340
341 return (ushort)(((m_asset.Length - FIRST_PACKET_SIZE + IMAGE_PACKET_SIZE - 1) / IMAGE_PACKET_SIZE) + 1);
342 }
343
344 private int GetPacketForBytePosition(int bytePosition)
345 {
346 return ((bytePosition - FIRST_PACKET_SIZE + IMAGE_PACKET_SIZE - 1) / IMAGE_PACKET_SIZE) + 1;
347 }
348
349 private int LastPacketSize()
350 {
351 if (m_currentPacket == 1)
352 return m_asset.Length;
353 int lastsize = (m_asset.Length - FIRST_PACKET_SIZE) % IMAGE_PACKET_SIZE;
354 //If the last packet size is zero, it's really cImagePacketSize, it sits on the boundary
355 if (lastsize == 0)
356 {
357 lastsize = IMAGE_PACKET_SIZE;
358 }
359 return lastsize;
360 }
361
362 private int CurrentBytePosition()
363 {
364 if (m_currentPacket == 0)
365 return 0;
366
367 if (m_currentPacket == 1)
368 return FIRST_PACKET_SIZE;
369
370 int result = FIRST_PACKET_SIZE + ((int)m_currentPacket - 2) * IMAGE_PACKET_SIZE;
371
372 if (result < 0)
373 result = FIRST_PACKET_SIZE;
374
375 return result;
376 }
377
378 private void J2KDecodedCallback(UUID AssetId, OpenJPEG.J2KLayerInfo[] layers)
379 {
380 m_layers = layers;
381 IsDecoded = true;
382 RunUpdate();
383 }
384
385 private void AssetDataCallback(UUID AssetID, AssetBase asset)
386 {
387 HasAsset = true;
388
389 if (asset == null || asset.Data == null)
390 {
391 if (m_imageManager.MissingImage != null)
392 {
393 m_asset = m_imageManager.MissingImage.Data;
394 }
395 else
396 {
397 m_asset = null;
398 IsDecoded = true;
399 }
400 }
401 else
402 {
403 m_asset = asset.Data;
404 }
405
406 RunUpdate();
407 }
408
409 private void AssetReceived(string id, Object sender, AssetBase asset)
410 {
411// m_log.DebugFormat(
412// "[J2KIMAGE]: Received asset {0} ({1} bytes)", id, asset != null ? asset.Data.Length.ToString() : "n/a");
413
414 UUID assetID = UUID.Zero;
415 if (asset != null)
416 {
417 assetID = asset.FullID;
418 }
419 else if ((InventoryAccessModule != null) && (sender != InventoryAccessModule))
420 {
421 // Unfortunately we need this here, there's no other way.
422 // This is due to the fact that textures opened directly from the agent's inventory
423 // don't have any distinguishing feature. As such, in order to serve those when the
424 // foreign user is visiting, we need to try again after the first fail to the local
425 // asset service.
426 string assetServerURL = string.Empty;
427 if (InventoryAccessModule.IsForeignUser(AgentID, out assetServerURL) && !string.IsNullOrEmpty(assetServerURL))
428 {
429 if (!assetServerURL.EndsWith("/") && !assetServerURL.EndsWith("="))
430 assetServerURL = assetServerURL + "/";
431
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);
434 return;
435 }
436 }
437
438 AssetDataCallback(assetID, asset);
439 }
440 }
441}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
new file mode 100644
index 0000000..c18f587
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -0,0 +1,13979 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Net;
32using System.Reflection;
33using System.Text;
34using System.Threading;
35using System.Timers;
36using System.Xml;
37
38using log4net;
39using OpenMetaverse;
40using OpenMetaverse.Packets;
41using OpenMetaverse.Messages.Linden;
42using OpenMetaverse.StructuredData;
43
44using OpenSim.Framework;
45using OpenSim.Framework.Client;
46using OpenSim.Framework.Monitoring;
47using OpenSim.Region.Framework.Interfaces;
48using OpenSim.Region.Framework.Scenes;
49using OpenSim.Services.Interfaces;
50using Timer = System.Timers.Timer;
51using AssetLandmark = OpenSim.Framework.AssetLandmark;
52using RegionFlags = OpenMetaverse.RegionFlags;
53
54using System.IO;
55using PermissionMask = OpenSim.Framework.PermissionMask;
56
57namespace OpenSim.Region.ClientStack.LindenUDP
58{
59 public delegate bool PacketMethod(IClientAPI simClient, Packet packet);
60
61 /// <summary>
62 /// Handles new client connections
63 /// Constructor takes a single Packet and authenticates everything
64 /// </summary>
65 public class LLClientView : IClientAPI, IClientCore, IClientIM, IClientChat, IClientInventory, IStatsCollector, IClientIPEndpoint
66 {
67 /// <value>
68 /// Debug packet level. See OpenSim.RegisterConsoleCommands() for more details.
69 /// </value>
70 public int DebugPacketLevel { get; set; }
71
72 #region Events
73
74 public event BinaryGenericMessage OnBinaryGenericMessage;
75 public event Action<IClientAPI> OnLogout;
76 public event ObjectPermissions OnObjectPermissions;
77 public event Action<IClientAPI> OnConnectionClosed;
78 public event ViewerEffectEventHandler OnViewerEffect;
79 public event ImprovedInstantMessage OnInstantMessage;
80 public event ChatMessage OnChatFromClient;
81 public event RezObject OnRezObject;
82 public event DeRezObject OnDeRezObject;
83 public event RezRestoreToWorld OnRezRestoreToWorld;
84 public event ModifyTerrain OnModifyTerrain;
85 public event Action<IClientAPI> OnRegionHandShakeReply;
86 public event GenericCall1 OnRequestWearables;
87 public event SetAppearance OnSetAppearance;
88 public event AvatarNowWearing OnAvatarNowWearing;
89 public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv;
90 public event RezMultipleAttachmentsFromInv OnRezMultipleAttachmentsFromInv;
91 public event UUIDNameRequest OnDetachAttachmentIntoInv;
92 public event ObjectAttach OnObjectAttach;
93 public event ObjectDeselect OnObjectDetach;
94 public event ObjectDrop OnObjectDrop;
95 public event Action<IClientAPI, bool> OnCompleteMovementToRegion;
96 public event UpdateAgent OnPreAgentUpdate;
97 public event UpdateAgent OnAgentUpdate;
98 public event UpdateAgent OnAgentCameraUpdate;
99 public event AgentRequestSit OnAgentRequestSit;
100 public event AgentSit OnAgentSit;
101 public event AvatarPickerRequest OnAvatarPickerRequest;
102 public event StartAnim OnStartAnim;
103 public event StopAnim OnStopAnim;
104 public event ChangeAnim OnChangeAnim;
105 public event Action<IClientAPI> OnRequestAvatarsData;
106 public event LinkObjects OnLinkObjects;
107 public event DelinkObjects OnDelinkObjects;
108 public event GrabObject OnGrabObject;
109 public event DeGrabObject OnDeGrabObject;
110 public event SpinStart OnSpinStart;
111 public event SpinStop OnSpinStop;
112 public event ObjectDuplicate OnObjectDuplicate;
113 public event ObjectDuplicateOnRay OnObjectDuplicateOnRay;
114 public event MoveObject OnGrabUpdate;
115 public event SpinObject OnSpinUpdate;
116 public event AddNewPrim OnAddPrim;
117 public event RequestGodlikePowers OnRequestGodlikePowers;
118 public event GodKickUser OnGodKickUser;
119 public event ObjectExtraParams OnUpdateExtraParams;
120 public event UpdateShape OnUpdatePrimShape;
121 public event ObjectRequest OnObjectRequest;
122 public event ObjectSelect OnObjectSelect;
123 public event ObjectDeselect OnObjectDeselect;
124 public event GenericCall7 OnObjectDescription;
125 public event GenericCall7 OnObjectName;
126 public event GenericCall7 OnObjectClickAction;
127 public event GenericCall7 OnObjectMaterial;
128 public event ObjectIncludeInSearch OnObjectIncludeInSearch;
129 public event RequestObjectPropertiesFamily OnRequestObjectPropertiesFamily;
130 public event UpdatePrimFlags OnUpdatePrimFlags;
131 public event UpdatePrimTexture OnUpdatePrimTexture;
132 public event ClientChangeObject onClientChangeObject;
133 public event UpdateVector OnUpdatePrimGroupPosition;
134 public event UpdateVector OnUpdatePrimSinglePosition;
135 public event UpdatePrimRotation OnUpdatePrimGroupRotation;
136 public event UpdatePrimSingleRotation OnUpdatePrimSingleRotation;
137 public event UpdatePrimSingleRotationPosition OnUpdatePrimSingleRotationPosition;
138 public event UpdatePrimGroupRotation OnUpdatePrimGroupMouseRotation;
139 public event UpdateVector OnUpdatePrimScale;
140 public event UpdateVector OnUpdatePrimGroupScale;
141 public event RequestMapBlocks OnRequestMapBlocks;
142 public event RequestMapName OnMapNameRequest;
143 public event TeleportLocationRequest OnTeleportLocationRequest;
144 public event TeleportLandmarkRequest OnTeleportLandmarkRequest;
145 public event TeleportCancel OnTeleportCancel;
146 public event RequestAvatarProperties OnRequestAvatarProperties;
147 public event SetAlwaysRun OnSetAlwaysRun;
148 public event FetchInventory OnAgentDataUpdateRequest;
149 public event TeleportLocationRequest OnSetStartLocationRequest;
150 public event UpdateAvatarProperties OnUpdateAvatarProperties;
151 public event CreateNewInventoryItem OnCreateNewInventoryItem;
152 public event LinkInventoryItem OnLinkInventoryItem;
153 public event CreateInventoryFolder OnCreateNewInventoryFolder;
154 public event UpdateInventoryFolder OnUpdateInventoryFolder;
155 public event MoveInventoryFolder OnMoveInventoryFolder;
156 public event FetchInventoryDescendents OnFetchInventoryDescendents;
157 public event PurgeInventoryDescendents OnPurgeInventoryDescendents;
158 public event FetchInventory OnFetchInventory;
159 public event RequestTaskInventory OnRequestTaskInventory;
160 public event UpdateInventoryItem OnUpdateInventoryItem;
161 public event CopyInventoryItem OnCopyInventoryItem;
162 public event MoveItemsAndLeaveCopy OnMoveItemsAndLeaveCopy;
163 public event MoveInventoryItem OnMoveInventoryItem;
164 public event RemoveInventoryItem OnRemoveInventoryItem;
165 public event RemoveInventoryFolder OnRemoveInventoryFolder;
166 public event UDPAssetUploadRequest OnAssetUploadRequest;
167 public event XferReceive OnXferReceive;
168 public event RequestXfer OnRequestXfer;
169 public event ConfirmXfer OnConfirmXfer;
170 public event AbortXfer OnAbortXfer;
171 public event RequestTerrain OnRequestTerrain;
172 public event RezScript OnRezScript;
173 public event UpdateTaskInventory OnUpdateTaskInventory;
174 public event MoveTaskInventory OnMoveTaskItem;
175 public event RemoveTaskInventory OnRemoveTaskItem;
176 public event UUIDNameRequest OnNameFromUUIDRequest;
177 public event ParcelAccessListRequest OnParcelAccessListRequest;
178 public event ParcelAccessListUpdateRequest OnParcelAccessListUpdateRequest;
179 public event ParcelPropertiesRequest OnParcelPropertiesRequest;
180 public event ParcelDivideRequest OnParcelDivideRequest;
181 public event ParcelJoinRequest OnParcelJoinRequest;
182 public event ParcelPropertiesUpdateRequest OnParcelPropertiesUpdateRequest;
183 public event ParcelSelectObjects OnParcelSelectObjects;
184 public event ParcelObjectOwnerRequest OnParcelObjectOwnerRequest;
185 public event ParcelAbandonRequest OnParcelAbandonRequest;
186 public event ParcelGodForceOwner OnParcelGodForceOwner;
187 public event ParcelReclaim OnParcelReclaim;
188 public event ParcelReturnObjectsRequest OnParcelReturnObjectsRequest;
189 public event ParcelDeedToGroup OnParcelDeedToGroup;
190 public event RegionInfoRequest OnRegionInfoRequest;
191 public event EstateCovenantRequest OnEstateCovenantRequest;
192 public event FriendActionDelegate OnApproveFriendRequest;
193 public event FriendActionDelegate OnDenyFriendRequest;
194 public event FriendshipTermination OnTerminateFriendship;
195 public event GrantUserFriendRights OnGrantUserRights;
196 public event MoneyTransferRequest OnMoneyTransferRequest;
197 public event EconomyDataRequest OnEconomyDataRequest;
198 public event MoneyBalanceRequest OnMoneyBalanceRequest;
199 public event ParcelBuy OnParcelBuy;
200 public event UUIDNameRequest OnTeleportHomeRequest;
201 public event UUIDNameRequest OnUUIDGroupNameRequest;
202 public event ScriptAnswer OnScriptAnswer;
203 public event RequestPayPrice OnRequestPayPrice;
204 public event ObjectSaleInfo OnObjectSaleInfo;
205 public event ObjectBuy OnObjectBuy;
206 public event AgentSit OnUndo;
207 public event AgentSit OnRedo;
208 public event LandUndo OnLandUndo;
209 public event ForceReleaseControls OnForceReleaseControls;
210 public event GodLandStatRequest OnLandStatRequest;
211 public event RequestObjectPropertiesFamily OnObjectGroupRequest;
212 public event DetailedEstateDataRequest OnDetailedEstateDataRequest;
213 public event SetEstateFlagsRequest OnSetEstateFlagsRequest;
214 public event SetEstateTerrainDetailTexture OnSetEstateTerrainDetailTexture;
215 public event SetEstateTerrainTextureHeights OnSetEstateTerrainTextureHeights;
216 public event CommitEstateTerrainTextureRequest OnCommitEstateTerrainTextureRequest;
217 public event SetRegionTerrainSettings OnSetRegionTerrainSettings;
218 public event BakeTerrain OnBakeTerrain;
219 public event RequestTerrain OnUploadTerrain;
220 public event EstateChangeInfo OnEstateChangeInfo;
221 public event EstateManageTelehub OnEstateManageTelehub;
222 public event EstateRestartSimRequest OnEstateRestartSimRequest;
223 public event EstateChangeCovenantRequest OnEstateChangeCovenantRequest;
224 public event UpdateEstateAccessDeltaRequest OnUpdateEstateAccessDeltaRequest;
225 public event SimulatorBlueBoxMessageRequest OnSimulatorBlueBoxMessageRequest;
226 public event EstateBlueBoxMessageRequest OnEstateBlueBoxMessageRequest;
227 public event EstateDebugRegionRequest OnEstateDebugRegionRequest;
228 public event EstateTeleportOneUserHomeRequest OnEstateTeleportOneUserHomeRequest;
229 public event EstateTeleportAllUsersHomeRequest OnEstateTeleportAllUsersHomeRequest;
230 public event RegionHandleRequest OnRegionHandleRequest;
231 public event ParcelInfoRequest OnParcelInfoRequest;
232 public event ScriptReset OnScriptReset;
233 public event GetScriptRunning OnGetScriptRunning;
234 public event SetScriptRunning OnSetScriptRunning;
235 public event Action<Vector3, bool, bool> OnAutoPilotGo;
236 public event ActivateGesture OnActivateGesture;
237 public event DeactivateGesture OnDeactivateGesture;
238 public event ObjectOwner OnObjectOwner;
239 public event DirPlacesQuery OnDirPlacesQuery;
240 public event DirFindQuery OnDirFindQuery;
241 public event DirLandQuery OnDirLandQuery;
242 public event DirPopularQuery OnDirPopularQuery;
243 public event DirClassifiedQuery OnDirClassifiedQuery;
244 public event EventInfoRequest OnEventInfoRequest;
245 public event ParcelSetOtherCleanTime OnParcelSetOtherCleanTime;
246 public event MapItemRequest OnMapItemRequest;
247 public event OfferCallingCard OnOfferCallingCard;
248 public event AcceptCallingCard OnAcceptCallingCard;
249 public event DeclineCallingCard OnDeclineCallingCard;
250 public event SoundTrigger OnSoundTrigger;
251 public event StartLure OnStartLure;
252 public event TeleportLureRequest OnTeleportLureRequest;
253 public event NetworkStats OnNetworkStatsUpdate;
254 public event ClassifiedInfoRequest OnClassifiedInfoRequest;
255 public event ClassifiedInfoUpdate OnClassifiedInfoUpdate;
256 public event ClassifiedDelete OnClassifiedDelete;
257 public event ClassifiedGodDelete OnClassifiedGodDelete;
258 public event EventNotificationAddRequest OnEventNotificationAddRequest;
259 public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest;
260 public event EventGodDelete OnEventGodDelete;
261 public event ParcelDwellRequest OnParcelDwellRequest;
262 public event UserInfoRequest OnUserInfoRequest;
263 public event UpdateUserInfo OnUpdateUserInfo;
264 public event RetrieveInstantMessages OnRetrieveInstantMessages;
265 public event PickDelete OnPickDelete;
266 public event PickGodDelete OnPickGodDelete;
267 public event PickInfoUpdate OnPickInfoUpdate;
268 public event AvatarNotesUpdate OnAvatarNotesUpdate;
269 public event MuteListRequest OnMuteListRequest;
270 public event AvatarInterestUpdate OnAvatarInterestUpdate;
271 public event PlacesQuery OnPlacesQuery;
272 public event AgentFOV OnAgentFOV;
273 public event FindAgentUpdate OnFindAgent;
274 public event TrackAgentUpdate OnTrackAgent;
275 public event NewUserReport OnUserReport;
276 public event SaveStateHandler OnSaveState;
277 public event GroupAccountSummaryRequest OnGroupAccountSummaryRequest;
278 public event GroupAccountDetailsRequest OnGroupAccountDetailsRequest;
279 public event GroupAccountTransactionsRequest OnGroupAccountTransactionsRequest;
280 public event FreezeUserUpdate OnParcelFreezeUser;
281 public event EjectUserUpdate OnParcelEjectUser;
282 public event ParcelBuyPass OnParcelBuyPass;
283 public event ParcelGodMark OnParcelGodMark;
284 public event GroupActiveProposalsRequest OnGroupActiveProposalsRequest;
285 public event GroupVoteHistoryRequest OnGroupVoteHistoryRequest;
286 public event SimWideDeletesDelegate OnSimWideDeletes;
287 public event SendPostcard OnSendPostcard;
288 public event ChangeInventoryItemFlags OnChangeInventoryItemFlags;
289 public event MuteListEntryUpdate OnUpdateMuteListEntry;
290 public event MuteListEntryRemove OnRemoveMuteListEntry;
291 public event GodlikeMessage onGodlikeMessage;
292 public event GodUpdateRegionInfoUpdate OnGodUpdateRegionInfoUpdate;
293 public event GenericCall2 OnUpdateThrottles;
294
295#pragma warning disable 0067
296 public event GenericMessage OnGenericMessage;
297 public event TextureRequest OnRequestTexture;
298 public event StatusChange OnChildAgentStatus;
299 public event GenericCall2 OnStopMovement;
300 public event Action<UUID> OnRemoveAvatar;
301 public event DisconnectUser OnDisconnectUser;
302 public event RequestAsset OnRequestAsset;
303 public event BuyObjectInventory OnBuyObjectInventory;
304 public event SetEstateTerrainBaseTexture OnSetEstateTerrainBaseTexture;
305 public event TerrainUnacked OnUnackedTerrain;
306 public event CachedTextureRequest OnCachedTextureRequest;
307#pragma warning restore 0067
308
309 #endregion Events
310
311 #region Class Members
312
313 // LLClientView Only
314 public delegate void BinaryGenericMessage(Object sender, string method, byte[][] args);
315
316 /// <summary>Used to adjust Sun Orbit values so Linden based viewers properly position sun</summary>
317 private const float m_sunPainDaHalfOrbitalCutoff = 4.712388980384689858f;
318
319 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
320 private static string LogHeader = "[LLCLIENTVIEW]";
321 protected static Dictionary<PacketType, PacketMethod> PacketHandlers = new Dictionary<PacketType, PacketMethod>(); //Global/static handlers for all clients
322
323 /// <summary>
324 /// Handles UDP texture download.
325 /// </summary>
326 public LLImageManager ImageManager { get; private set; }
327
328 public JobEngine m_asyncPacketProcess;
329 private readonly LLUDPServer m_udpServer;
330 private readonly LLUDPClient m_udpClient;
331 private readonly UUID m_sessionId;
332 private readonly UUID m_secureSessionId;
333 protected readonly UUID m_agentId;
334 private readonly uint m_circuitCode;
335 private readonly byte[] m_channelVersion = Utils.EmptyBytes;
336 private readonly IGroupsModule m_GroupsModule;
337
338// private int m_cachedTextureSerial;
339 private PriorityQueue m_entityUpdates;
340 private PriorityQueue m_entityProps;
341 private Prioritizer m_prioritizer;
342 private bool m_disableFacelights = false;
343
344 // needs optimazation
345 private HashSet<SceneObjectGroup> GroupsInView = new HashSet<SceneObjectGroup>();
346
347// private bool m_VelocityInterpolate = false;
348 private const uint MaxTransferBytesPerPacket = 600;
349
350 /// <value>
351 /// Maintain a record of all the objects killed. This allows us to stop an update being sent from the
352 /// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an
353 /// ownerless phantom.
354 ///
355 /// All manipulation of this set has to occur under an m_entityUpdates.SyncRoot lock
356 ///
357 /// </value>
358 protected List<uint> m_killRecord;
359
360// protected HashSet<uint> m_attachmentsSent;
361
362 private bool m_deliverPackets = true;
363
364 private bool m_SendLogoutPacketWhenClosing = true;
365
366 /// <summary>
367 /// We retain a single AgentUpdateArgs so that we can constantly reuse it rather than construct a new one for
368 /// every single incoming AgentUpdate. Every client sends 10 AgentUpdate UDP messages per second, even if it
369 /// is doing absolutely nothing.
370 /// </summary>
371 /// <remarks>
372 /// This does mean that agent updates must be processed synchronously, at least for each client, and called methods
373 /// cannot retain a reference to it outside of that method.
374 /// </remarks>
375 private AgentUpdateArgs m_thisAgentUpdateArgs = new AgentUpdateArgs();
376
377 protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>();
378 protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers
379 protected Scene m_scene;
380 protected string m_firstName;
381 protected string m_lastName;
382 protected Vector3 m_startpos;
383 protected UUID m_activeGroupID;
384 protected string m_activeGroupName = String.Empty;
385 protected ulong m_activeGroupPowers;
386 protected Dictionary<UUID, ulong> m_groupPowers = new Dictionary<UUID, ulong>();
387 protected int m_terrainCheckerCount;
388 protected uint m_agentFOVCounter;
389
390 protected IAssetService m_assetService;
391 private const bool m_checkPackets = true;
392
393 #endregion Class Members
394
395 #region Properties
396
397 public LLUDPClient UDPClient { get { return m_udpClient; } }
398 public LLUDPServer UDPServer { get { return m_udpServer; } }
399 public IPEndPoint RemoteEndPoint { get { return m_udpClient.RemoteEndPoint; } }
400 public UUID SecureSessionId { get { return m_secureSessionId; } }
401 public IScene Scene { get { return m_scene; } }
402 public UUID SessionId { get { return m_sessionId; } }
403 public Vector3 StartPos
404 {
405 get { return m_startpos; }
406 set { m_startpos = value; }
407 }
408 public bool DeliverPackets
409 {
410 get { return m_deliverPackets; }
411 set {
412 m_deliverPackets = value;
413 m_udpClient.m_deliverPackets = value;
414 }
415 }
416 public UUID AgentId { get { return m_agentId; } }
417 public ISceneAgent SceneAgent { get; set; }
418 public UUID ActiveGroupId { get { return m_activeGroupID; } set { m_activeGroupID = value; } }
419 public string ActiveGroupName { get { return m_activeGroupName; } set { m_activeGroupName = value; } }
420 public ulong ActiveGroupPowers { get { return m_activeGroupPowers; } set { m_activeGroupPowers = value; } }
421 public bool IsGroupMember(UUID groupID) { return m_groupPowers.ContainsKey(groupID); }
422
423 public int PingTimeMS
424 {
425 get
426 {
427 if (UDPClient != null)
428 return UDPClient.PingTimeMS;
429 return 0;
430 }
431 }
432
433 /// <summary>
434 /// Entity update queues
435 /// </summary>
436 public PriorityQueue EntityUpdateQueue { get { return m_entityUpdates; } }
437
438 /// <summary>
439 /// First name of the agent/avatar represented by the client
440 /// </summary>
441 public string FirstName { get { return m_firstName; } }
442
443 /// <summary>
444 /// Last name of the agent/avatar represented by the client
445 /// </summary>
446 public string LastName { get { return m_lastName; } }
447
448 /// <summary>
449 /// Full name of the client (first name and last name)
450 /// </summary>
451 public string Name { get { return FirstName + " " + LastName; } }
452
453 public uint CircuitCode { get { return m_circuitCode; } }
454 public int NextAnimationSequenceNumber
455 {
456 get { return m_udpServer.NextAnimationSequenceNumber; }
457 }
458
459 /// <summary>
460 /// As well as it's function in IClientAPI, in LLClientView we are locking on this property in order to
461 /// prevent race conditions by different threads calling Close().
462 /// </summary>
463 public bool IsActive { get; set; }
464
465 /// <summary>
466 /// Used to synchronise threads when client is being closed.
467 /// </summary>
468 public Object CloseSyncLock { get; private set; }
469
470 public bool IsLoggingOut { get; set; }
471
472 public bool DisableFacelights
473 {
474 get { return m_disableFacelights; }
475 set { m_disableFacelights = value; }
476 }
477
478 public List<uint> SelectedObjects {get; private set;}
479
480 public bool SendLogoutPacketWhenClosing { set { m_SendLogoutPacketWhenClosing = value; } }
481
482
483 #endregion Properties
484
485// ~LLClientView()
486// {
487// m_log.DebugFormat("{0} Destructor called for {1}, circuit code {2}", LogHeader, Name, CircuitCode);
488// }
489
490 /// <summary>
491 /// Constructor
492 /// </summary>
493 public LLClientView(Scene scene, LLUDPServer udpServer, LLUDPClient udpClient, AuthenticateResponse sessionInfo,
494 UUID agentId, UUID sessionId, uint circuitCode)
495 {
496// DebugPacketLevel = 1;
497
498 CloseSyncLock = new Object();
499 SelectedObjects = new List<uint>();
500
501 RegisterInterface<IClientIM>(this);
502 RegisterInterface<IClientInventory>(this);
503 RegisterInterface<IClientChat>(this);
504
505 m_scene = scene;
506 m_entityUpdates = new PriorityQueue(m_scene.Entities.Count);
507 m_entityProps = new PriorityQueue(m_scene.Entities.Count);
508 m_killRecord = new List<uint>();
509// m_attachmentsSent = new HashSet<uint>();
510
511 m_assetService = m_scene.RequestModuleInterface<IAssetService>();
512 m_GroupsModule = scene.RequestModuleInterface<IGroupsModule>();
513 ImageManager = new LLImageManager(this, m_assetService, Scene.RequestModuleInterface<IJ2KDecoder>());
514 m_channelVersion = Util.StringToBytes256(scene.GetSimulatorVersion());
515 m_agentId = agentId;
516 m_sessionId = sessionId;
517 m_secureSessionId = sessionInfo.LoginInfo.SecureSession;
518 m_circuitCode = circuitCode;
519 m_firstName = sessionInfo.LoginInfo.First;
520 m_lastName = sessionInfo.LoginInfo.Last;
521 m_startpos = sessionInfo.LoginInfo.StartPos;
522
523 m_udpServer = udpServer;
524 m_udpClient = udpClient;
525 m_udpClient.OnQueueEmpty += HandleQueueEmpty;
526 m_udpClient.HasUpdates += HandleHasUpdates;
527 m_udpClient.OnPacketStats += PopulateStats;
528
529 m_prioritizer = new Prioritizer(m_scene);
530
531 RegisterLocalPacketHandlers();
532 string name = string.Format("AsyncInUDP-{0}",m_agentId.ToString());
533 m_asyncPacketProcess = new JobEngine(name, name, 10000);
534 IsActive = true;
535 }
536
537 #region Client Methods
538
539
540 /// <summary>
541 /// Close down the client view
542 /// </summary>
543 public void Close()
544 {
545 Close(true, false);
546 }
547
548 public void Close(bool sendStop, bool force)
549 {
550 // We lock here to prevent race conditions between two threads calling close simultaneously (e.g.
551 // a simultaneous relog just as a client is being closed out due to no packet ack from the old connection.
552 lock (CloseSyncLock)
553 {
554 // We still perform a force close inside the sync lock since this is intended to attempt close where
555 // there is some unidentified connection problem, not where we have issues due to deadlock
556 if (!IsActive && !force)
557 {
558 m_log.DebugFormat( "{0} Not attempting to close inactive client {1} in {2} since force flag is not set",
559 LogHeader, Name, m_scene.Name);
560
561 return;
562 }
563
564 IsActive = false;
565 CloseWithoutChecks(sendStop);
566 }
567 }
568
569 /// <summary>
570 /// Closes down the client view without first checking whether it is active.
571 /// </summary>
572 /// <remarks>
573 /// This exists because LLUDPServer has to set IsActive = false in earlier synchronous code before calling
574 /// CloseWithoutIsActiveCheck asynchronously.
575 ///
576 /// Callers must lock ClosingSyncLock before calling.
577 /// </remarks>
578 public void CloseWithoutChecks(bool sendStop)
579 {
580 m_log.DebugFormat(
581 "[CLIENT]: Close has been called for {0} attached to scene {1}",
582 Name, m_scene.RegionInfo.RegionName);
583
584 if (sendStop)
585 {
586 // Send the STOP packet
587 DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator);
588 OutPacket(disable, ThrottleOutPacketType.Unknown);
589 }
590
591
592 // Fire the callback for this connection closing
593 if (OnConnectionClosed != null)
594 OnConnectionClosed(this);
595
596 m_asyncPacketProcess.Stop();
597
598 // Flush all of the packets out of the UDP server for this client
599 if (m_udpServer != null)
600 m_udpServer.Flush(m_udpClient);
601
602 // Remove ourselves from the scene
603 m_scene.RemoveClient(AgentId, true);
604 SceneAgent = null;
605
606 // We can't reach into other scenes and close the connection
607 // We need to do this over grid communications
608 //m_scene.CloseAllAgents(CircuitCode);
609
610 // Disable UDP handling for this client
611 m_udpClient.OnQueueEmpty -= HandleQueueEmpty;
612 m_udpClient.HasUpdates -= HandleHasUpdates;
613 m_udpClient.OnPacketStats -= PopulateStats;
614 m_udpClient.Shutdown();
615
616 // Shutdown the image manager
617 ImageManager.Close();
618 ImageManager = null;
619
620 m_entityUpdates = new PriorityQueue(1);
621 m_entityProps = new PriorityQueue(1);
622 m_killRecord.Clear();
623 GroupsInView.Clear();
624
625 if(m_scene.GetNumberOfClients() == 0)
626 {
627 GC.Collect();
628 GC.WaitForPendingFinalizers();
629 GC.Collect();
630 }
631 }
632
633 public void Kick(string message)
634 {
635 if (!SceneAgent.IsChildAgent)
636 {
637 KickUserPacket kupack = (KickUserPacket)PacketPool.Instance.GetPacket(PacketType.KickUser);
638 kupack.UserInfo.AgentID = AgentId;
639 kupack.UserInfo.SessionID = SessionId;
640 kupack.TargetBlock.TargetIP = 0;
641 kupack.TargetBlock.TargetPort = 0;
642 kupack.UserInfo.Reason = Util.StringToBytes256(message);
643 OutPacket(kupack, ThrottleOutPacketType.Task);
644 // You must sleep here or users get no message!
645 Thread.Sleep(500);
646 }
647 }
648
649 public void Stop()
650 {
651
652 }
653
654 #endregion Client Methods
655
656 #region Packet Handling
657
658 public void PopulateStats(int inPackets, int outPackets, int unAckedBytes)
659 {
660 NetworkStats handlerNetworkStatsUpdate = OnNetworkStatsUpdate;
661 if (handlerNetworkStatsUpdate != null)
662 {
663 handlerNetworkStatsUpdate(inPackets, outPackets, unAckedBytes);
664 }
665 }
666
667 public static bool AddPacketHandler(PacketType packetType, PacketMethod handler)
668 {
669 bool result = false;
670 lock (PacketHandlers)
671 {
672 if (!PacketHandlers.ContainsKey(packetType))
673 {
674 PacketHandlers.Add(packetType, handler);
675 result = true;
676 }
677 }
678 return result;
679 }
680
681 /// <summary>
682 /// Add a handler for the given packet type.
683 /// </summary>
684 /// <remarks>
685 /// The packet is handled on its own thread. If packets must be handled in the order in which they
686 /// are received then please use the synchronous version of this method.
687 /// </remarks>
688 /// <param name="packetType"></param>
689 /// <param name="handler"></param>
690 /// <returns>true if the handler was added. This is currently always the case.</returns>
691 public bool AddLocalPacketHandler(PacketType packetType, PacketMethod handler)
692 {
693 return AddLocalPacketHandler(packetType, handler, true);
694 }
695
696 /// <summary>
697 /// Add a handler for the given packet type.
698 /// </summary>
699 /// <param name="packetType"></param>
700 /// <param name="handler"></param>
701 /// <param name="doAsync">
702 /// If true, when the packet is received it is handled on its own thread rather than on the main inward bound
703 /// packet handler thread. This vastly increases respnosiveness but some packets need to be handled
704 /// synchronously.
705 /// </param>
706 /// <returns>true if the handler was added. This is currently always the case.</returns>
707 public bool AddLocalPacketHandler(PacketType packetType, PacketMethod handler, bool doAsync)
708 {
709 bool result = false;
710 lock (m_packetHandlers)
711 {
712 if (!m_packetHandlers.ContainsKey(packetType))
713 {
714 m_packetHandlers.Add(
715 packetType, new PacketProcessor() { method = handler, Async = doAsync});
716 result = true;
717 }
718 }
719
720 return result;
721 }
722
723 public bool AddGenericPacketHandler(string MethodName, GenericMessage handler)
724 {
725 MethodName = MethodName.ToLower().Trim();
726
727 bool result = false;
728 lock (m_genericPacketHandlers)
729 {
730 if (!m_genericPacketHandlers.ContainsKey(MethodName))
731 {
732 m_genericPacketHandlers.Add(MethodName, handler);
733 result = true;
734 }
735 }
736 return result;
737 }
738
739 /// <summary>
740 /// Try to process a packet using registered packet handlers
741 /// </summary>
742 /// <param name="packet"></param>
743 /// <returns>True if a handler was found which successfully processed the packet.</returns>
744 protected virtual bool ProcessPacketMethod(Packet packet)
745 {
746 bool result = false;
747 PacketProcessor pprocessor;
748 if (m_packetHandlers.TryGetValue(packet.Type, out pprocessor))
749 {
750
751 //there is a local handler for this packet type
752 if (pprocessor.Async)
753 {
754 object obj = new AsyncPacketProcess(this, pprocessor.method, packet);
755 m_asyncPacketProcess.QueueJob(packet.Type.ToString(), () => ProcessSpecificPacketAsync(obj));
756 result = true;
757 }
758 else
759 {
760 result = pprocessor.method(this, packet);
761 }
762 }
763 else
764 {
765 //there is not a local handler so see if there is a Global handler
766 PacketMethod method = null;
767 bool found;
768 lock (PacketHandlers)
769 {
770 found = PacketHandlers.TryGetValue(packet.Type, out method);
771 }
772 if (found)
773 {
774 result = method(this, packet);
775 }
776 }
777 return result;
778 }
779
780 public void ProcessSpecificPacketAsync(object state)
781 {
782 AsyncPacketProcess packetObject = (AsyncPacketProcess)state;
783
784 try
785 {
786 packetObject.result = packetObject.Method(packetObject.ClientView, packetObject.Pack);
787 }
788 catch (Exception e)
789 {
790 // Make sure that we see any exception caused by the asynchronous operation.
791 m_log.Error(
792 string.Format(
793 "[LLCLIENTVIEW]: Caught exception while processing {0} for {1} ", packetObject.Pack, Name),
794 e);
795 }
796 }
797
798 #endregion Packet Handling
799
800 # region Setup
801
802 public virtual void Start()
803 {
804 m_asyncPacketProcess.Start();
805 m_scene.AddNewAgent(this, PresenceType.User);
806
807// RefreshGroupMembership();
808 }
809
810 # endregion
811
812 public void ActivateGesture(UUID assetId, UUID gestureId)
813 {
814 }
815
816 public void DeactivateGesture(UUID assetId, UUID gestureId)
817 {
818 }
819
820 // Sound
821 public void SoundTrigger(UUID soundId, UUID owerid, UUID Objectid, UUID ParentId, float Gain, Vector3 Position, UInt64 Handle)
822 {
823 }
824
825 #region Scene/Avatar to Client
826
827 public void SendRegionHandshake(RegionInfo regionInfo, RegionHandshakeArgs args)
828 {
829 RegionHandshakePacket handshake = (RegionHandshakePacket)PacketPool.Instance.GetPacket(PacketType.RegionHandshake);
830 handshake.RegionInfo = new RegionHandshakePacket.RegionInfoBlock();
831 handshake.RegionInfo.BillableFactor = args.billableFactor;
832 handshake.RegionInfo.IsEstateManager = args.isEstateManager;
833 handshake.RegionInfo.TerrainHeightRange00 = args.terrainHeightRange0;
834 handshake.RegionInfo.TerrainHeightRange01 = args.terrainHeightRange1;
835 handshake.RegionInfo.TerrainHeightRange10 = args.terrainHeightRange2;
836 handshake.RegionInfo.TerrainHeightRange11 = args.terrainHeightRange3;
837 handshake.RegionInfo.TerrainStartHeight00 = args.terrainStartHeight0;
838 handshake.RegionInfo.TerrainStartHeight01 = args.terrainStartHeight1;
839 handshake.RegionInfo.TerrainStartHeight10 = args.terrainStartHeight2;
840 handshake.RegionInfo.TerrainStartHeight11 = args.terrainStartHeight3;
841 handshake.RegionInfo.SimAccess = args.simAccess;
842 handshake.RegionInfo.WaterHeight = args.waterHeight;
843
844 handshake.RegionInfo.RegionFlags = args.regionFlags;
845 handshake.RegionInfo.SimName = Util.StringToBytes256(args.regionName);
846 handshake.RegionInfo.SimOwner = args.SimOwner;
847 handshake.RegionInfo.TerrainBase0 = args.terrainBase0;
848 handshake.RegionInfo.TerrainBase1 = args.terrainBase1;
849 handshake.RegionInfo.TerrainBase2 = args.terrainBase2;
850 handshake.RegionInfo.TerrainBase3 = args.terrainBase3;
851 handshake.RegionInfo.TerrainDetail0 = args.terrainDetail0;
852 handshake.RegionInfo.TerrainDetail1 = args.terrainDetail1;
853 handshake.RegionInfo.TerrainDetail2 = args.terrainDetail2;
854 handshake.RegionInfo.TerrainDetail3 = args.terrainDetail3;
855 handshake.RegionInfo.CacheID = UUID.Random(); //I guess this is for the client to remember an old setting?
856 handshake.RegionInfo2 = new RegionHandshakePacket.RegionInfo2Block();
857 handshake.RegionInfo2.RegionID = regionInfo.RegionID;
858
859 handshake.RegionInfo3 = new RegionHandshakePacket.RegionInfo3Block();
860 handshake.RegionInfo3.CPUClassID = 9;
861 handshake.RegionInfo3.CPURatio = 1;
862
863 handshake.RegionInfo3.ColoName = Utils.EmptyBytes;
864 handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType);
865 handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes;
866
867 handshake.RegionInfo4 = new RegionHandshakePacket.RegionInfo4Block[1];
868 handshake.RegionInfo4[0] = new RegionHandshakePacket.RegionInfo4Block();
869 handshake.RegionInfo4[0].RegionFlagsExtended = args.regionFlags;
870 handshake.RegionInfo4[0].RegionProtocols = 0; // 1 here would indicate that SSB is supported
871
872 OutPacket(handshake, ThrottleOutPacketType.Unknown);
873 }
874
875
876 public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look)
877 {
878 m_thisAgentUpdateArgs.CameraAtAxis.X = float.MinValue;
879// m_thisAgentUpdateArgs.ControlFlags = uint.MaxValue;
880 m_thisAgentUpdateArgs.ControlFlags = 0;
881
882 AgentMovementCompletePacket mov = (AgentMovementCompletePacket)PacketPool.Instance.GetPacket(PacketType.AgentMovementComplete);
883 mov.SimData.ChannelVersion = m_channelVersion;
884 mov.AgentData.SessionID = m_sessionId;
885 mov.AgentData.AgentID = AgentId;
886 mov.Data.RegionHandle = regInfo.RegionHandle;
887 mov.Data.Timestamp = (uint)Util.UnixTimeSinceEpoch();
888
889 if ((pos.X == 0) && (pos.Y == 0) && (pos.Z == 0))
890 {
891 mov.Data.Position = m_startpos;
892 }
893 else
894 {
895 mov.Data.Position = pos;
896 }
897 mov.Data.LookAt = look;
898
899 // Hack to get this out immediately and skip the throttles
900 OutPacket(mov, ThrottleOutPacketType.Unknown);
901 }
902
903 public void SendChatMessage(
904 string message, byte type, Vector3 fromPos, string fromName,
905 UUID fromAgentID, UUID ownerID, byte source, byte audible)
906 {
907 ChatFromSimulatorPacket reply = (ChatFromSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.ChatFromSimulator);
908 reply.ChatData.Audible = audible;
909 reply.ChatData.Message = Util.StringToBytes1024(message);
910 reply.ChatData.ChatType = type;
911 reply.ChatData.SourceType = source;
912 reply.ChatData.Position = fromPos;
913 reply.ChatData.FromName = Util.StringToBytes256(fromName);
914 reply.ChatData.OwnerID = ownerID;
915 reply.ChatData.SourceID = fromAgentID;
916
917 OutPacket(reply, ThrottleOutPacketType.Unknown);
918 }
919
920 /// <summary>
921 /// Send an instant message to this client
922 /// </summary>
923 //
924 public void SendInstantMessage(GridInstantMessage im)
925 {
926 if (((Scene)(m_scene)).Permissions.CanInstantMessage(new UUID(im.fromAgentID), new UUID(im.toAgentID)))
927 {
928 ImprovedInstantMessagePacket msg
929 = (ImprovedInstantMessagePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedInstantMessage);
930
931 msg.AgentData.AgentID = new UUID(im.fromAgentID);
932 msg.AgentData.SessionID = UUID.Zero;
933 msg.MessageBlock.FromAgentName = Util.StringToBytes256(im.fromAgentName);
934 msg.MessageBlock.Dialog = im.dialog;
935 msg.MessageBlock.FromGroup = im.fromGroup;
936 // this is odd
937 if (im.imSessionID == UUID.Zero.Guid)
938 msg.MessageBlock.ID = new UUID(im.fromAgentID) ^ new UUID(im.toAgentID);
939 else
940 msg.MessageBlock.ID = new UUID(im.imSessionID);
941 msg.MessageBlock.Offline = im.offline;
942 msg.MessageBlock.ParentEstateID = im.ParentEstateID;
943 msg.MessageBlock.Position = im.Position;
944 msg.MessageBlock.RegionID = new UUID(im.RegionID);
945 msg.MessageBlock.Timestamp = im.timestamp;
946 msg.MessageBlock.ToAgentID = new UUID(im.toAgentID);
947 msg.MessageBlock.Message = Util.StringToBytes1024(im.message);
948 msg.MessageBlock.BinaryBucket = im.binaryBucket;
949
950 OutPacket(msg, ThrottleOutPacketType.Task);
951 }
952 }
953
954 public void SendGenericMessage(string method, UUID invoice, List<string> message)
955 {
956 GenericMessagePacket gmp = new GenericMessagePacket();
957
958 gmp.AgentData.AgentID = AgentId;
959 gmp.AgentData.SessionID = m_sessionId;
960 gmp.AgentData.TransactionID = invoice;
961
962 gmp.MethodData.Method = Util.StringToBytes256(method);
963 gmp.ParamList = new GenericMessagePacket.ParamListBlock[message.Count];
964 int i = 0;
965 foreach (string val in message)
966 {
967 gmp.ParamList[i] = new GenericMessagePacket.ParamListBlock();
968 gmp.ParamList[i++].Parameter = Util.StringToBytes256(val);
969 }
970
971 OutPacket(gmp, ThrottleOutPacketType.Task);
972 }
973
974 public void SendGenericMessage(string method, UUID invoice, List<byte[]> message)
975 {
976 GenericMessagePacket gmp = new GenericMessagePacket();
977
978 gmp.AgentData.AgentID = AgentId;
979 gmp.AgentData.SessionID = m_sessionId;
980 gmp.AgentData.TransactionID = invoice;
981
982 gmp.MethodData.Method = Util.StringToBytes256(method);
983 gmp.ParamList = new GenericMessagePacket.ParamListBlock[message.Count];
984 int i = 0;
985 foreach (byte[] val in message)
986 {
987 gmp.ParamList[i] = new GenericMessagePacket.ParamListBlock();
988 gmp.ParamList[i++].Parameter = val;
989 }
990
991 OutPacket(gmp, ThrottleOutPacketType.Task);
992 }
993
994 public void SendGroupActiveProposals(UUID groupID, UUID transactionID, GroupActiveProposals[] Proposals)
995 {
996 int i = 0;
997 foreach (GroupActiveProposals Proposal in Proposals)
998 {
999 GroupActiveProposalItemReplyPacket GAPIRP = new GroupActiveProposalItemReplyPacket();
1000
1001 GAPIRP.AgentData.AgentID = AgentId;
1002 GAPIRP.AgentData.GroupID = groupID;
1003 GAPIRP.TransactionData.TransactionID = transactionID;
1004 GAPIRP.TransactionData.TotalNumItems = ((uint)i+1);
1005 GroupActiveProposalItemReplyPacket.ProposalDataBlock ProposalData = new GroupActiveProposalItemReplyPacket.ProposalDataBlock();
1006 GAPIRP.ProposalData = new GroupActiveProposalItemReplyPacket.ProposalDataBlock[1];
1007 ProposalData.VoteCast = Utils.StringToBytes("false");
1008 ProposalData.VoteID = new UUID(Proposal.VoteID);
1009 ProposalData.VoteInitiator = new UUID(Proposal.VoteInitiator);
1010 ProposalData.Majority = (float)Convert.ToInt32(Proposal.Majority);
1011 ProposalData.Quorum = Convert.ToInt32(Proposal.Quorum);
1012 ProposalData.TerseDateID = Utils.StringToBytes(Proposal.TerseDateID);
1013 ProposalData.StartDateTime = Utils.StringToBytes(Proposal.StartDateTime);
1014 ProposalData.EndDateTime = Utils.StringToBytes(Proposal.EndDateTime);
1015 ProposalData.ProposalText = Utils.StringToBytes(Proposal.ProposalText);
1016 ProposalData.AlreadyVoted = false;
1017 GAPIRP.ProposalData[i] = ProposalData;
1018 OutPacket(GAPIRP, ThrottleOutPacketType.Task);
1019 i++;
1020 }
1021 if (Proposals.Length == 0)
1022 {
1023 GroupActiveProposalItemReplyPacket GAPIRP = new GroupActiveProposalItemReplyPacket();
1024
1025 GAPIRP.AgentData.AgentID = AgentId;
1026 GAPIRP.AgentData.GroupID = groupID;
1027 GAPIRP.TransactionData.TransactionID = transactionID;
1028 GAPIRP.TransactionData.TotalNumItems = 1;
1029 GroupActiveProposalItemReplyPacket.ProposalDataBlock ProposalData = new GroupActiveProposalItemReplyPacket.ProposalDataBlock();
1030 GAPIRP.ProposalData = new GroupActiveProposalItemReplyPacket.ProposalDataBlock[1];
1031 ProposalData.VoteCast = Utils.StringToBytes("false");
1032 ProposalData.VoteID = UUID.Zero;
1033 ProposalData.VoteInitiator = UUID.Zero;
1034 ProposalData.Majority = 0;
1035 ProposalData.Quorum = 0;
1036 ProposalData.TerseDateID = Utils.StringToBytes("");
1037 ProposalData.StartDateTime = Utils.StringToBytes("");
1038 ProposalData.EndDateTime = Utils.StringToBytes("");
1039 ProposalData.ProposalText = Utils.StringToBytes("");
1040 ProposalData.AlreadyVoted = false;
1041 GAPIRP.ProposalData[0] = ProposalData;
1042 OutPacket(GAPIRP, ThrottleOutPacketType.Task);
1043 }
1044 }
1045
1046 public void SendGroupVoteHistory(UUID groupID, UUID transactionID, GroupVoteHistory[] Votes)
1047 {
1048 int i = 0;
1049 foreach (GroupVoteHistory Vote in Votes)
1050 {
1051 GroupVoteHistoryItemReplyPacket GVHIRP = new GroupVoteHistoryItemReplyPacket();
1052
1053 GVHIRP.AgentData.AgentID = AgentId;
1054 GVHIRP.AgentData.GroupID = groupID;
1055 GVHIRP.TransactionData.TransactionID = transactionID;
1056 GVHIRP.TransactionData.TotalNumItems = ((uint)i+1);
1057 GVHIRP.HistoryItemData.VoteID = new UUID(Vote.VoteID);
1058 GVHIRP.HistoryItemData.VoteInitiator = new UUID(Vote.VoteInitiator);
1059 GVHIRP.HistoryItemData.Majority = (float)Convert.ToInt32(Vote.Majority);
1060 GVHIRP.HistoryItemData.Quorum = Convert.ToInt32(Vote.Quorum);
1061 GVHIRP.HistoryItemData.TerseDateID = Utils.StringToBytes(Vote.TerseDateID);
1062 GVHIRP.HistoryItemData.StartDateTime = Utils.StringToBytes(Vote.StartDateTime);
1063 GVHIRP.HistoryItemData.EndDateTime = Utils.StringToBytes(Vote.EndDateTime);
1064 GVHIRP.HistoryItemData.VoteType = Utils.StringToBytes(Vote.VoteType);
1065 GVHIRP.HistoryItemData.VoteResult = Utils.StringToBytes(Vote.VoteResult);
1066 GVHIRP.HistoryItemData.ProposalText = Utils.StringToBytes(Vote.ProposalText);
1067 GroupVoteHistoryItemReplyPacket.VoteItemBlock VoteItem = new GroupVoteHistoryItemReplyPacket.VoteItemBlock();
1068 GVHIRP.VoteItem = new GroupVoteHistoryItemReplyPacket.VoteItemBlock[1];
1069 VoteItem.CandidateID = UUID.Zero;
1070 VoteItem.NumVotes = 0; //TODO: FIX THIS!!!
1071 VoteItem.VoteCast = Utils.StringToBytes("Yes");
1072 GVHIRP.VoteItem[i] = VoteItem;
1073 OutPacket(GVHIRP, ThrottleOutPacketType.Task);
1074 i++;
1075 }
1076 if (Votes.Length == 0)
1077 {
1078 GroupVoteHistoryItemReplyPacket GVHIRP = new GroupVoteHistoryItemReplyPacket();
1079
1080 GVHIRP.AgentData.AgentID = AgentId;
1081 GVHIRP.AgentData.GroupID = groupID;
1082 GVHIRP.TransactionData.TransactionID = transactionID;
1083 GVHIRP.TransactionData.TotalNumItems = 0;
1084 GVHIRP.HistoryItemData.VoteID = UUID.Zero;
1085 GVHIRP.HistoryItemData.VoteInitiator = UUID.Zero;
1086 GVHIRP.HistoryItemData.Majority = 0;
1087 GVHIRP.HistoryItemData.Quorum = 0;
1088 GVHIRP.HistoryItemData.TerseDateID = Utils.StringToBytes("");
1089 GVHIRP.HistoryItemData.StartDateTime = Utils.StringToBytes("");
1090 GVHIRP.HistoryItemData.EndDateTime = Utils.StringToBytes("");
1091 GVHIRP.HistoryItemData.VoteType = Utils.StringToBytes("");
1092 GVHIRP.HistoryItemData.VoteResult = Utils.StringToBytes("");
1093 GVHIRP.HistoryItemData.ProposalText = Utils.StringToBytes("");
1094 GroupVoteHistoryItemReplyPacket.VoteItemBlock VoteItem = new GroupVoteHistoryItemReplyPacket.VoteItemBlock();
1095 GVHIRP.VoteItem = new GroupVoteHistoryItemReplyPacket.VoteItemBlock[1];
1096 VoteItem.CandidateID = UUID.Zero;
1097 VoteItem.NumVotes = 0; //TODO: FIX THIS!!!
1098 VoteItem.VoteCast = Utils.StringToBytes("No");
1099 GVHIRP.VoteItem[0] = VoteItem;
1100 OutPacket(GVHIRP, ThrottleOutPacketType.Task);
1101 }
1102 }
1103
1104 public void SendGroupAccountingDetails(IClientAPI sender,UUID groupID, UUID transactionID, UUID sessionID, int amt)
1105 {
1106 GroupAccountDetailsReplyPacket GADRP = new GroupAccountDetailsReplyPacket();
1107 GADRP.AgentData = new GroupAccountDetailsReplyPacket.AgentDataBlock();
1108 GADRP.AgentData.AgentID = sender.AgentId;
1109 GADRP.AgentData.GroupID = groupID;
1110 GADRP.HistoryData = new GroupAccountDetailsReplyPacket.HistoryDataBlock[1];
1111 GroupAccountDetailsReplyPacket.HistoryDataBlock History = new GroupAccountDetailsReplyPacket.HistoryDataBlock();
1112 GADRP.MoneyData = new GroupAccountDetailsReplyPacket.MoneyDataBlock();
1113 GADRP.MoneyData.CurrentInterval = 0;
1114 GADRP.MoneyData.IntervalDays = 7;
1115 GADRP.MoneyData.RequestID = transactionID;
1116 GADRP.MoneyData.StartDate = Utils.StringToBytes(DateTime.Today.ToString());
1117 History.Amount = amt;
1118 History.Description = Utils.StringToBytes("");
1119 GADRP.HistoryData[0] = History;
1120 OutPacket(GADRP, ThrottleOutPacketType.Task);
1121 }
1122
1123 public void SendGroupAccountingSummary(IClientAPI sender,UUID groupID, uint moneyAmt, int totalTier, int usedTier)
1124 {
1125 GroupAccountSummaryReplyPacket GASRP =
1126 (GroupAccountSummaryReplyPacket)PacketPool.Instance.GetPacket(
1127 PacketType.GroupAccountSummaryReply);
1128
1129 GASRP.AgentData = new GroupAccountSummaryReplyPacket.AgentDataBlock();
1130 GASRP.AgentData.AgentID = sender.AgentId;
1131 GASRP.AgentData.GroupID = groupID;
1132 GASRP.MoneyData = new GroupAccountSummaryReplyPacket.MoneyDataBlock();
1133 GASRP.MoneyData.Balance = (int)moneyAmt;
1134 GASRP.MoneyData.TotalCredits = totalTier;
1135 GASRP.MoneyData.TotalDebits = usedTier;
1136 GASRP.MoneyData.StartDate = new byte[1];
1137 GASRP.MoneyData.CurrentInterval = 1;
1138 GASRP.MoneyData.GroupTaxCurrent = 0;
1139 GASRP.MoneyData.GroupTaxEstimate = 0;
1140 GASRP.MoneyData.IntervalDays = 0;
1141 GASRP.MoneyData.LandTaxCurrent = 0;
1142 GASRP.MoneyData.LandTaxEstimate = 0;
1143 GASRP.MoneyData.LastTaxDate = new byte[1];
1144 GASRP.MoneyData.LightTaxCurrent = 0;
1145 GASRP.MoneyData.TaxDate = new byte[1];
1146 GASRP.MoneyData.RequestID = sender.AgentId;
1147 GASRP.MoneyData.ParcelDirFeeEstimate = 0;
1148 GASRP.MoneyData.ParcelDirFeeCurrent = 0;
1149 GASRP.MoneyData.ObjectTaxEstimate = 0;
1150 GASRP.MoneyData.NonExemptMembers = 0;
1151 GASRP.MoneyData.ObjectTaxCurrent = 0;
1152 GASRP.MoneyData.LightTaxEstimate = 0;
1153 OutPacket(GASRP, ThrottleOutPacketType.Task);
1154 }
1155
1156 public void SendGroupTransactionsSummaryDetails(IClientAPI sender,UUID groupID, UUID transactionID, UUID sessionID, int amt)
1157 {
1158 GroupAccountTransactionsReplyPacket GATRP =
1159 (GroupAccountTransactionsReplyPacket)PacketPool.Instance.GetPacket(
1160 PacketType.GroupAccountTransactionsReply);
1161
1162 GATRP.AgentData = new GroupAccountTransactionsReplyPacket.AgentDataBlock();
1163 GATRP.AgentData.AgentID = sender.AgentId;
1164 GATRP.AgentData.GroupID = groupID;
1165 GATRP.MoneyData = new GroupAccountTransactionsReplyPacket.MoneyDataBlock();
1166 GATRP.MoneyData.CurrentInterval = 0;
1167 GATRP.MoneyData.IntervalDays = 7;
1168 GATRP.MoneyData.RequestID = transactionID;
1169 GATRP.MoneyData.StartDate = Utils.StringToBytes(DateTime.Today.ToString());
1170 GATRP.HistoryData = new GroupAccountTransactionsReplyPacket.HistoryDataBlock[1];
1171 GroupAccountTransactionsReplyPacket.HistoryDataBlock History = new GroupAccountTransactionsReplyPacket.HistoryDataBlock();
1172 History.Amount = 0;
1173 History.Item = Utils.StringToBytes("");
1174 History.Time = Utils.StringToBytes("");
1175 History.Type = 0;
1176 History.User = Utils.StringToBytes("");
1177 GATRP.HistoryData[0] = History;
1178 OutPacket(GATRP, ThrottleOutPacketType.Task);
1179 }
1180
1181
1182 public virtual bool CanSendLayerData()
1183 {
1184 int n = m_udpClient.GetPacketsQueuedCount(ThrottleOutPacketType.Land);
1185 if ( n > 128)
1186 return false;
1187 return true;
1188 }
1189
1190 /// <summary>
1191 /// Send the region heightmap to the client
1192 /// This method is only called when not doing intellegent terrain patch sending and
1193 /// is only called when the scene presence is initially created and sends all of the
1194 /// region's patches to the client.
1195 /// </summary>
1196 /// <param name="map">heightmap</param>
1197 public virtual void SendLayerData(float[] map)
1198 {
1199 Util.FireAndForget(DoSendLayerData, m_scene.Heightmap.GetTerrainData(), "LLClientView.DoSendLayerData");
1200
1201 // Send it sync, and async. It's not that much data
1202 // and it improves user experience just so much!
1203// DoSendLayerData(map);
1204 }
1205
1206 /// <summary>
1207 /// Send terrain layer information to the client.
1208 /// </summary>
1209 /// <param name="o"></param>
1210 private void DoSendLayerData(object o)
1211 {
1212 TerrainData map = (TerrainData)o;
1213
1214 try
1215 {
1216 // Send LayerData in typerwriter pattern
1217 //for (int y = 0; y < 16; y++)
1218 //{
1219 // for (int x = 0; x < 16; x++)
1220 // {
1221 // SendLayerData(x, y, map);
1222 // }
1223 //}
1224
1225 // Send LayerData in a spiral pattern. Fun!
1226 SendLayerTopRight(map, 0, 0, map.SizeX / Constants.TerrainPatchSize - 1, map.SizeY / Constants.TerrainPatchSize - 1);
1227 }
1228 catch (Exception e)
1229 {
1230 m_log.Error("[CLIENT]: SendLayerData() Failed with exception: " + e.Message, e);
1231 }
1232 }
1233
1234 private void SendLayerTopRight(TerrainData map, int x1, int y1, int x2, int y2)
1235 {
1236 // Row
1237 for (int i = x1; i <= x2; i++)
1238 SendLayerData(i, y1, map);
1239
1240 // Column
1241 for (int j = y1 + 1; j <= y2; j++)
1242 SendLayerData(x2, j, map);
1243
1244 if (x2 - x1 > 0 && y2 - y1 > 0)
1245 SendLayerBottomLeft(map, x1, y1 + 1, x2 - 1, y2);
1246 }
1247
1248 void SendLayerBottomLeft(TerrainData map, int x1, int y1, int x2, int y2)
1249 {
1250 // Row in reverse
1251 for (int i = x2; i >= x1; i--)
1252 SendLayerData(i, y2, map);
1253
1254 // Column in reverse
1255 for (int j = y2 - 1; j >= y1; j--)
1256 SendLayerData(x1, j, map);
1257
1258 if (x2 - x1 > 0 && y2 - y1 > 0)
1259 SendLayerTopRight(map, x1 + 1, y1, x2, y2 - 1);
1260 }
1261
1262
1263 // Legacy form of invocation that passes around a bare data array.
1264 // Just ignore what was passed and use the real terrain info that is part of the scene.
1265 // As a HORRIBLE kludge in an attempt to not change the definition of IClientAPI,
1266 // there is a special form for specifying multiple terrain patches to send.
1267 // The form is to pass 'px' as negative the number of patches to send and to
1268 // pass the float array as pairs of patch X and Y coordinates. So, passing 'px'
1269 // as -2 and map= [3, 5, 8, 4] would mean to send two terrain heightmap patches
1270 // and the patches to send are <3,5> and <8,4>.
1271 public void SendLayerData(int px, int py, float[] map)
1272 {
1273 if (px >= 0)
1274 {
1275 SendLayerData(px, py, m_scene.Heightmap.GetTerrainData());
1276 }
1277 else
1278 {
1279 int numPatches = -px;
1280 int[] xPatches = new int[numPatches];
1281 int[] yPatches = new int[numPatches];
1282 for (int pp = 0; pp < numPatches; pp++)
1283 {
1284 xPatches[pp] = (int)map[pp * 2];
1285 yPatches[pp] = (int)map[pp * 2 + 1];
1286 }
1287
1288 // DebugSendingPatches("SendLayerData", xPatches, yPatches);
1289
1290 SendLayerData(xPatches, yPatches, m_scene.Heightmap.GetTerrainData());
1291 }
1292 }
1293
1294 private void DebugSendingPatches(string pWho, int[] pX, int[] pY)
1295 {
1296 if (m_log.IsDebugEnabled)
1297 {
1298 int numPatches = pX.Length;
1299 string Xs = "";
1300 string Ys = "";
1301 for (int pp = 0; pp < numPatches; pp++)
1302 {
1303 Xs += String.Format("{0}", (int)pX[pp]) + ",";
1304 Ys += String.Format("{0}", (int)pY[pp]) + ",";
1305 }
1306 m_log.DebugFormat("{0} {1}: numPatches={2}, X={3}, Y={4}", LogHeader, pWho, numPatches, Xs, Ys);
1307 }
1308 }
1309
1310 /// <summary>
1311
1312 /// Sends a terrain packet for the point specified.
1313 /// This is a legacy call that has refarbed the terrain into a flat map of floats.
1314 /// We just use the terrain from the region we know about.
1315 /// </summary>
1316 /// <param name="px">Patch coordinate (x) 0..15</param>
1317 /// <param name="py">Patch coordinate (y) 0..15</param>
1318 /// <param name="map">heightmap</param>
1319 public void SendLayerData(int px, int py, TerrainData terrData)
1320 {
1321 int[] xPatches = new[] { px };
1322 int[] yPatches = new[] { py };
1323 SendLayerData(xPatches, yPatches, terrData);
1324 }
1325
1326 private void SendLayerData(int[] px, int[] py, TerrainData terrData)
1327 {
1328 try
1329 {
1330 byte landPacketType;
1331 if (terrData.SizeX > Constants.RegionSize || terrData.SizeY > Constants.RegionSize)
1332 landPacketType = (byte)TerrainPatch.LayerType.LandExtended;
1333 else
1334 landPacketType = (byte)TerrainPatch.LayerType.Land;
1335
1336 List<LayerDataPacket> packets = OpenSimTerrainCompressor.CreateLayerDataPackets(terrData, px, py, landPacketType);
1337 foreach(LayerDataPacket pkt in packets)
1338 OutPacket(pkt, ThrottleOutPacketType.Land);
1339 }
1340 catch (Exception e)
1341 {
1342 m_log.Error("[CLIENT]: SendLayerData() Failed with exception: " + e.Message, e);
1343 }
1344 }
1345
1346
1347 // wind caching
1348 private static Dictionary<ulong,int> lastWindVersion = new Dictionary<ulong,int>();
1349 private static Dictionary<ulong,List<LayerDataPacket>> lastWindPackets =
1350 new Dictionary<ulong,List<LayerDataPacket>>();
1351
1352
1353 /// <summary>
1354 /// Send the wind matrix to the client
1355 /// </summary>
1356 /// <param name="windSpeeds">16x16 array of wind speeds</param>
1357 public virtual void SendWindData(int version, Vector2[] windSpeeds)
1358 {
1359// Vector2[] windSpeeds = (Vector2[])o;
1360
1361 ulong handle = this.Scene.RegionInfo.RegionHandle;
1362 bool isNewData;
1363 lock(lastWindPackets)
1364 {
1365 if(!lastWindVersion.ContainsKey(handle) ||
1366 !lastWindPackets.ContainsKey(handle))
1367 {
1368 lastWindVersion[handle] = 0;
1369 lastWindPackets[handle] = new List<LayerDataPacket>();
1370 isNewData = true;
1371 }
1372 else
1373 isNewData = lastWindVersion[handle] != version;
1374 }
1375
1376 if(isNewData)
1377 {
1378 TerrainPatch[] patches = new TerrainPatch[2];
1379 patches[0] = new TerrainPatch { Data = new float[16 * 16] };
1380 patches[1] = new TerrainPatch { Data = new float[16 * 16] };
1381
1382 for (int x = 0; x < 16 * 16; x++)
1383 {
1384 patches[0].Data[x] = windSpeeds[x].X;
1385 patches[1].Data[x] = windSpeeds[x].Y;
1386 }
1387
1388 // neither we or viewers have extended wind
1389 byte layerType = (byte)TerrainPatch.LayerType.Wind;
1390
1391 LayerDataPacket layerpack =
1392 OpenSimTerrainCompressor.CreateLayerDataPacketStandardSize(
1393 patches, layerType);
1394 layerpack.Header.Zerocoded = true;
1395 lock(lastWindPackets)
1396 {
1397 lastWindPackets[handle].Clear();
1398 lastWindPackets[handle].Add(layerpack);
1399 lastWindVersion[handle] = version;
1400 }
1401 }
1402
1403 lock(lastWindPackets)
1404 foreach(LayerDataPacket pkt in lastWindPackets[handle])
1405 OutPacket(pkt, ThrottleOutPacketType.Wind);
1406 }
1407
1408 // cloud caching
1409 private static Dictionary<ulong,int> lastCloudVersion = new Dictionary<ulong,int>();
1410 private static Dictionary<ulong,List<LayerDataPacket>> lastCloudPackets =
1411 new Dictionary<ulong,List<LayerDataPacket>>();
1412
1413 /// <summary>
1414 /// Send the cloud matrix to the client
1415 /// </summary>
1416 /// <param name="windSpeeds">16x16 array of cloud densities</param>
1417 public virtual void SendCloudData(int version, float[] cloudDensity)
1418 {
1419 ulong handle = this.Scene.RegionInfo.RegionHandle;
1420 bool isNewData;
1421 lock(lastWindPackets)
1422 {
1423 if(!lastCloudVersion.ContainsKey(handle) ||
1424 !lastCloudPackets.ContainsKey(handle))
1425 {
1426 lastCloudVersion[handle] = 0;
1427 lastCloudPackets[handle] = new List<LayerDataPacket>();
1428 isNewData = true;
1429 }
1430 else
1431 isNewData = lastCloudVersion[handle] != version;
1432 }
1433
1434 if(isNewData)
1435 {
1436 TerrainPatch[] patches = new TerrainPatch[1];
1437 patches[0] = new TerrainPatch();
1438 patches[0].Data = new float[16 * 16];
1439
1440 for (int y = 0; y < 16; y++)
1441 {
1442 for (int x = 0; x < 16; x++)
1443 {
1444 patches[0].Data[y * 16 + x] = cloudDensity[y * 16 + x];
1445 }
1446 }
1447 // neither we or viewers have extended clouds
1448 byte layerType = (byte)TerrainPatch.LayerType.Cloud;
1449
1450 LayerDataPacket layerpack =
1451 OpenSimTerrainCompressor.CreateLayerDataPacketStandardSize(
1452 patches, layerType);
1453 layerpack.Header.Zerocoded = true;
1454 lock(lastCloudPackets)
1455 {
1456 lastCloudPackets[handle].Clear();
1457 lastCloudPackets[handle].Add(layerpack);
1458 lastCloudVersion[handle] = version;
1459 }
1460 }
1461
1462 lock(lastCloudPackets)
1463 foreach(LayerDataPacket pkt in lastCloudPackets[handle])
1464 OutPacket(pkt, ThrottleOutPacketType.Cloud);
1465 }
1466
1467 /// <summary>
1468 /// Tell the client that the given neighbour region is ready to receive a child agent.
1469 /// </summary>
1470 public virtual void InformClientOfNeighbour(ulong neighbourHandle, IPEndPoint neighbourEndPoint)
1471 {
1472 IPAddress neighbourIP = neighbourEndPoint.Address;
1473 ushort neighbourPort = (ushort)neighbourEndPoint.Port;
1474
1475 EnableSimulatorPacket enablesimpacket = (EnableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.EnableSimulator);
1476 // TODO: don't create new blocks if recycling an old packet
1477 enablesimpacket.SimulatorInfo = new EnableSimulatorPacket.SimulatorInfoBlock();
1478 enablesimpacket.SimulatorInfo.Handle = neighbourHandle;
1479
1480 byte[] byteIP = neighbourIP.GetAddressBytes();
1481 enablesimpacket.SimulatorInfo.IP = (uint)byteIP[3] << 24;
1482 enablesimpacket.SimulatorInfo.IP += (uint)byteIP[2] << 16;
1483 enablesimpacket.SimulatorInfo.IP += (uint)byteIP[1] << 8;
1484 enablesimpacket.SimulatorInfo.IP += (uint)byteIP[0];
1485 enablesimpacket.SimulatorInfo.Port = neighbourPort;
1486
1487 enablesimpacket.Header.Reliable = true; // ESP's should be reliable.
1488
1489 OutPacket(enablesimpacket, ThrottleOutPacketType.Task);
1490 }
1491
1492 public AgentCircuitData RequestClientInfo()
1493 {
1494 AgentCircuitData agentData = new AgentCircuitData();
1495 agentData.AgentID = AgentId;
1496 agentData.SessionID = m_sessionId;
1497 agentData.SecureSessionID = SecureSessionId;
1498 agentData.circuitcode = m_circuitCode;
1499 agentData.child = false;
1500 agentData.firstname = m_firstName;
1501 agentData.lastname = m_lastName;
1502
1503 ICapabilitiesModule capsModule = m_scene.RequestModuleInterface<ICapabilitiesModule>();
1504
1505 if (capsModule == null) // can happen when shutting down.
1506 return agentData;
1507
1508 agentData.CapsPath = capsModule.GetCapsPath(m_agentId);
1509 agentData.ChildrenCapSeeds = new Dictionary<ulong, string>(capsModule.GetChildrenSeeds(m_agentId));
1510
1511 return agentData;
1512 }
1513
1514 public virtual void CrossRegion(ulong newRegionHandle, Vector3 pos, Vector3 lookAt, IPEndPoint externalIPEndPoint,
1515 string capsURL)
1516 {
1517 Vector3 look = new Vector3(lookAt.X * 10, lookAt.Y * 10, lookAt.Z * 10);
1518
1519 //CrossedRegionPacket newSimPack = (CrossedRegionPacket)PacketPool.Instance.GetPacket(PacketType.CrossedRegion);
1520 CrossedRegionPacket newSimPack = new CrossedRegionPacket();
1521 // TODO: don't create new blocks if recycling an old packet
1522 newSimPack.AgentData = new CrossedRegionPacket.AgentDataBlock();
1523 newSimPack.AgentData.AgentID = AgentId;
1524 newSimPack.AgentData.SessionID = m_sessionId;
1525 newSimPack.Info = new CrossedRegionPacket.InfoBlock();
1526 newSimPack.Info.Position = pos;
1527 newSimPack.Info.LookAt = look;
1528 newSimPack.RegionData = new CrossedRegionPacket.RegionDataBlock();
1529 newSimPack.RegionData.RegionHandle = newRegionHandle;
1530 byte[] byteIP = externalIPEndPoint.Address.GetAddressBytes();
1531 newSimPack.RegionData.SimIP = (uint)byteIP[3] << 24;
1532 newSimPack.RegionData.SimIP += (uint)byteIP[2] << 16;
1533 newSimPack.RegionData.SimIP += (uint)byteIP[1] << 8;
1534 newSimPack.RegionData.SimIP += (uint)byteIP[0];
1535 newSimPack.RegionData.SimPort = (ushort)externalIPEndPoint.Port;
1536 newSimPack.RegionData.SeedCapability = Util.StringToBytes256(capsURL);
1537
1538 // Hack to get this out immediately and skip throttles
1539 OutPacket(newSimPack, ThrottleOutPacketType.Unknown);
1540 }
1541
1542 internal void SendMapBlockSplit(List<MapBlockData> mapBlocks, uint flag)
1543 {
1544 MapBlockReplyPacket mapReply = (MapBlockReplyPacket)PacketPool.Instance.GetPacket(PacketType.MapBlockReply);
1545 // TODO: don't create new blocks if recycling an old packet
1546
1547 MapBlockData[] mapBlocks2 = mapBlocks.ToArray();
1548
1549 mapReply.AgentData.AgentID = AgentId;
1550 mapReply.Data = new MapBlockReplyPacket.DataBlock[mapBlocks2.Length];
1551 mapReply.Size = new MapBlockReplyPacket.SizeBlock[mapBlocks2.Length];
1552 mapReply.AgentData.Flags = flag;
1553
1554 for (int i = 0; i < mapBlocks2.Length; i++)
1555 {
1556 mapReply.Data[i] = new MapBlockReplyPacket.DataBlock();
1557 mapReply.Data[i].MapImageID = mapBlocks2[i].MapImageId;
1558 //m_log.Warn(mapBlocks2[i].MapImageId.ToString());
1559 mapReply.Data[i].X = mapBlocks2[i].X;
1560 mapReply.Data[i].Y = mapBlocks2[i].Y;
1561 mapReply.Data[i].WaterHeight = mapBlocks2[i].WaterHeight;
1562 mapReply.Data[i].Name = Utils.StringToBytes(mapBlocks2[i].Name);
1563 mapReply.Data[i].RegionFlags = mapBlocks2[i].RegionFlags;
1564 mapReply.Data[i].Access = mapBlocks2[i].Access;
1565 mapReply.Data[i].Agents = mapBlocks2[i].Agents;
1566
1567 mapReply.Size[i] = new MapBlockReplyPacket.SizeBlock();
1568 mapReply.Size[i].SizeX = mapBlocks2[i].SizeX;
1569 mapReply.Size[i].SizeY = mapBlocks2[i].SizeY;
1570 }
1571 OutPacket(mapReply, ThrottleOutPacketType.Land);
1572 }
1573
1574 public void SendMapBlock(List<MapBlockData> mapBlocks, uint flag)
1575 {
1576 MapBlockData[] mapBlocks2 = mapBlocks.ToArray();
1577
1578 int maxsend = 10;
1579
1580 //int packets = Math.Ceiling(mapBlocks2.Length / maxsend);
1581
1582 List<MapBlockData> sendingBlocks = new List<MapBlockData>();
1583
1584 for (int i = 0; i < mapBlocks2.Length; i++)
1585 {
1586 sendingBlocks.Add(mapBlocks2[i]);
1587 if (((i + 1) == mapBlocks2.Length) || (((i + 1) % maxsend) == 0))
1588 {
1589 SendMapBlockSplit(sendingBlocks, flag);
1590 sendingBlocks = new List<MapBlockData>();
1591 }
1592 }
1593 }
1594
1595 public void SendLocalTeleport(Vector3 position, Vector3 lookAt, uint flags)
1596 {
1597 TeleportLocalPacket tpLocal = (TeleportLocalPacket)PacketPool.Instance.GetPacket(PacketType.TeleportLocal);
1598 tpLocal.Info.AgentID = AgentId;
1599 tpLocal.Info.TeleportFlags = flags;
1600 tpLocal.Info.LocationID = 2;
1601 tpLocal.Info.LookAt = lookAt;
1602 tpLocal.Info.Position = position;
1603
1604 // Hack to get this out immediately and skip throttles
1605 OutPacket(tpLocal, ThrottleOutPacketType.Unknown);
1606 }
1607
1608 public virtual void SendRegionTeleport(ulong regionHandle, byte simAccess, IPEndPoint newRegionEndPoint, uint locationID,
1609 uint flags, string capsURL)
1610 {
1611 //TeleportFinishPacket teleport = (TeleportFinishPacket)PacketPool.Instance.GetPacket(PacketType.TeleportFinish);
1612
1613 TeleportFinishPacket teleport = new TeleportFinishPacket();
1614 teleport.Info.AgentID = AgentId;
1615 teleport.Info.RegionHandle = regionHandle;
1616 teleport.Info.SimAccess = simAccess;
1617
1618 teleport.Info.SeedCapability = Util.StringToBytes256(capsURL);
1619
1620 IPAddress oIP = newRegionEndPoint.Address;
1621 byte[] byteIP = oIP.GetAddressBytes();
1622 uint ip = (uint)byteIP[3] << 24;
1623 ip += (uint)byteIP[2] << 16;
1624 ip += (uint)byteIP[1] << 8;
1625 ip += (uint)byteIP[0];
1626
1627 teleport.Info.SimIP = ip;
1628 teleport.Info.SimPort = (ushort)newRegionEndPoint.Port;
1629 teleport.Info.LocationID = 4;
1630 teleport.Info.TeleportFlags = 1 << 4;
1631
1632 // Hack to get this out immediately and skip throttles.
1633 OutPacket(teleport, ThrottleOutPacketType.Unknown);
1634 }
1635
1636 /// <summary>
1637 /// Inform the client that a teleport attempt has failed
1638 /// </summary>
1639 public void SendTeleportFailed(string reason)
1640 {
1641 TeleportFailedPacket tpFailed = (TeleportFailedPacket)PacketPool.Instance.GetPacket(PacketType.TeleportFailed);
1642 tpFailed.Info.AgentID = AgentId;
1643 tpFailed.Info.Reason = Util.StringToBytes256(reason);
1644 tpFailed.AlertInfo = new TeleportFailedPacket.AlertInfoBlock[0];
1645
1646 // Hack to get this out immediately and skip throttles
1647 OutPacket(tpFailed, ThrottleOutPacketType.Unknown);
1648 }
1649
1650 /// <summary>
1651 ///
1652 /// </summary>
1653 public void SendTeleportStart(uint flags)
1654 {
1655 TeleportStartPacket tpStart = (TeleportStartPacket)PacketPool.Instance.GetPacket(PacketType.TeleportStart);
1656 //TeleportStartPacket tpStart = new TeleportStartPacket();
1657 tpStart.Info.TeleportFlags = flags; //16; // Teleport via location
1658
1659 // Hack to get this out immediately and skip throttles
1660 OutPacket(tpStart, ThrottleOutPacketType.Unknown);
1661 }
1662
1663 public void SendTeleportProgress(uint flags, string message)
1664 {
1665 TeleportProgressPacket tpProgress = (TeleportProgressPacket)PacketPool.Instance.GetPacket(PacketType.TeleportProgress);
1666 tpProgress.AgentData.AgentID = this.AgentId;
1667 tpProgress.Info.TeleportFlags = flags;
1668 tpProgress.Info.Message = Util.StringToBytes256(message);
1669
1670 // Hack to get this out immediately and skip throttles
1671 OutPacket(tpProgress, ThrottleOutPacketType.Unknown);
1672 }
1673
1674 public void SendMoneyBalance(UUID transaction, bool success, byte[] description, int balance, int transactionType, UUID sourceID, bool sourceIsGroup, UUID destID, bool destIsGroup, int amount, string item)
1675 {
1676 MoneyBalanceReplyPacket money = (MoneyBalanceReplyPacket)PacketPool.Instance.GetPacket(PacketType.MoneyBalanceReply);
1677 money.MoneyData.AgentID = AgentId;
1678 money.MoneyData.TransactionID = transaction;
1679 money.MoneyData.TransactionSuccess = success;
1680 money.MoneyData.Description = description;
1681 money.MoneyData.MoneyBalance = balance;
1682 money.TransactionInfo.TransactionType = transactionType;
1683 money.TransactionInfo.SourceID = sourceID;
1684 money.TransactionInfo.IsSourceGroup = sourceIsGroup;
1685 money.TransactionInfo.DestID = destID;
1686 money.TransactionInfo.IsDestGroup = destIsGroup;
1687 money.TransactionInfo.Amount = amount;
1688 money.TransactionInfo.ItemDescription = Util.StringToBytes256(item);
1689
1690 OutPacket(money, ThrottleOutPacketType.Task);
1691 }
1692
1693 public void SendPayPrice(UUID objectID, int[] payPrice)
1694 {
1695 if (payPrice[0] == 0 &&
1696 payPrice[1] == 0 &&
1697 payPrice[2] == 0 &&
1698 payPrice[3] == 0 &&
1699 payPrice[4] == 0)
1700 return;
1701
1702 PayPriceReplyPacket payPriceReply = (PayPriceReplyPacket)PacketPool.Instance.GetPacket(PacketType.PayPriceReply);
1703 payPriceReply.ObjectData.ObjectID = objectID;
1704 payPriceReply.ObjectData.DefaultPayPrice = payPrice[0];
1705
1706 payPriceReply.ButtonData = new PayPriceReplyPacket.ButtonDataBlock[4];
1707 payPriceReply.ButtonData[0] = new PayPriceReplyPacket.ButtonDataBlock();
1708 payPriceReply.ButtonData[0].PayButton = payPrice[1];
1709 payPriceReply.ButtonData[1] = new PayPriceReplyPacket.ButtonDataBlock();
1710 payPriceReply.ButtonData[1].PayButton = payPrice[2];
1711 payPriceReply.ButtonData[2] = new PayPriceReplyPacket.ButtonDataBlock();
1712 payPriceReply.ButtonData[2].PayButton = payPrice[3];
1713 payPriceReply.ButtonData[3] = new PayPriceReplyPacket.ButtonDataBlock();
1714 payPriceReply.ButtonData[3].PayButton = payPrice[4];
1715
1716 OutPacket(payPriceReply, ThrottleOutPacketType.Task);
1717 }
1718
1719 public void SendStartPingCheck(byte seq)
1720 {
1721 StartPingCheckPacket pc = (StartPingCheckPacket)PacketPool.Instance.GetPacket(PacketType.StartPingCheck);
1722 pc.Header.Reliable = false;
1723
1724 pc.PingID.PingID = seq;
1725 // We *could* get OldestUnacked, but it would hurt performance and not provide any benefit
1726 pc.PingID.OldestUnacked = 0;
1727
1728 OutPacket(pc, ThrottleOutPacketType.Unknown);
1729 UDPClient.m_lastStartpingTimeMS = Util.EnvironmentTickCount();
1730 }
1731
1732 public void SendKillObject(List<uint> localIDs)
1733 {
1734 // foreach (uint id in localIDs)
1735 // m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle);
1736
1737 // remove pending entities to reduce looping chances.
1738 lock (m_entityProps.SyncRoot)
1739 m_entityProps.Remove(localIDs);
1740 lock (m_entityUpdates.SyncRoot)
1741 m_entityUpdates.Remove(localIDs);
1742
1743 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject);
1744
1745 int perpacket = localIDs.Count;
1746 if(perpacket > 200)
1747 perpacket = 200;
1748
1749 int nsent = 0;
1750
1751 kill.ObjectData = new KillObjectPacket.ObjectDataBlock[perpacket];
1752 for (int i = 0 ; i < localIDs.Count ; i++ )
1753 {
1754 kill.ObjectData[nsent] = new KillObjectPacket.ObjectDataBlock();
1755 kill.ObjectData[nsent].ID = localIDs[i];
1756
1757 if(++nsent >= 200)
1758 {
1759 kill.Header.Reliable = true;
1760 kill.Header.Zerocoded = true;
1761 OutPacket(kill, ThrottleOutPacketType.Task);
1762
1763 perpacket = localIDs.Count - i - 1;
1764 if(perpacket == 0)
1765 break;
1766 if(perpacket > 200)
1767 perpacket = 200;
1768
1769 kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject);
1770 kill.ObjectData = new KillObjectPacket.ObjectDataBlock[perpacket];
1771 nsent = 0;
1772 }
1773 }
1774
1775 if(nsent != 0)
1776 {
1777 kill.Header.Reliable = true;
1778 kill.Header.Zerocoded = true;
1779 OutPacket(kill, ThrottleOutPacketType.Task);
1780 }
1781 }
1782
1783 /// <summary>
1784 /// Send information about the items contained in a folder to the client.
1785 /// </summary>
1786 /// <remarks>
1787 /// XXX This method needs some refactoring loving
1788 /// </remarks>
1789 /// <param name="ownerID">The owner of the folder</param>
1790 /// <param name="folderID">The id of the folder</param>
1791 /// <param name="items">The items contained in the folder identified by folderID</param>
1792 /// <param name="folders"></param>
1793 /// <param name="fetchFolders">Do we need to send folder information?</param>
1794 /// <param name="fetchItems">Do we need to send item information?</param>
1795 public void SendInventoryFolderDetails(UUID ownerID, UUID folderID, List<InventoryItemBase> items,
1796 List<InventoryFolderBase> folders, int version,
1797 bool fetchFolders, bool fetchItems)
1798 {
1799 // An inventory descendents packet consists of a single agent section and an inventory details
1800 // section for each inventory item. The size of each inventory item is approximately 550 bytes.
1801 // In theory, UDP has a maximum packet size of 64k, so it should be possible to send descendent
1802 // packets containing metadata for in excess of 100 items. But in practice, there may be other
1803 // factors (e.g. firewalls) restraining the maximum UDP packet size. See,
1804 //
1805 // http://opensimulator.org/mantis/view.php?id=226
1806 //
1807 // for one example of this kind of thing. In fact, the Linden servers appear to only send about
1808 // 6 to 7 items at a time, so let's stick with 6
1809 int MAX_ITEMS_PER_PACKET = 5;
1810 int MAX_FOLDERS_PER_PACKET = 6;
1811
1812 int totalItems = fetchItems ? items.Count : 0;
1813 int totalFolders = fetchFolders ? folders.Count : 0;
1814 int itemsSent = 0;
1815 int foldersSent = 0;
1816 int foldersToSend = 0;
1817 int itemsToSend = 0;
1818
1819 InventoryDescendentsPacket currentPacket = null;
1820
1821 // Handle empty folders
1822 //
1823 if (totalItems == 0 && totalFolders == 0)
1824 currentPacket = CreateInventoryDescendentsPacket(ownerID, folderID, version, items.Count + folders.Count, 0, 0);
1825
1826 // To preserve SL compatibility, we will NOT combine folders and items in one packet
1827 //
1828 while (itemsSent < totalItems || foldersSent < totalFolders)
1829 {
1830 if (currentPacket == null) // Start a new packet
1831 {
1832 foldersToSend = totalFolders - foldersSent;
1833 if (foldersToSend > MAX_FOLDERS_PER_PACKET)
1834 foldersToSend = MAX_FOLDERS_PER_PACKET;
1835
1836 if (foldersToSend == 0)
1837 {
1838 itemsToSend = totalItems - itemsSent;
1839 if (itemsToSend > MAX_ITEMS_PER_PACKET)
1840 itemsToSend = MAX_ITEMS_PER_PACKET;
1841 }
1842
1843 currentPacket = CreateInventoryDescendentsPacket(ownerID, folderID, version, items.Count + folders.Count, foldersToSend, itemsToSend);
1844 }
1845
1846 if (foldersToSend-- > 0)
1847 currentPacket.FolderData[foldersSent % MAX_FOLDERS_PER_PACKET] = CreateFolderDataBlock(folders[foldersSent++]);
1848 else if (itemsToSend-- > 0)
1849 currentPacket.ItemData[itemsSent % MAX_ITEMS_PER_PACKET] = CreateItemDataBlock(items[itemsSent++]);
1850 else
1851 {
1852// m_log.DebugFormat(
1853// "[LLCLIENTVIEW]: Sending inventory folder details packet to {0} for folder {1}", Name, folderID);
1854 OutPacket(currentPacket, ThrottleOutPacketType.Asset, false);
1855 currentPacket = null;
1856 }
1857 }
1858
1859 if (currentPacket != null)
1860 {
1861// m_log.DebugFormat(
1862// "[LLCLIENTVIEW]: Sending inventory folder details packet to {0} for folder {1}", Name, folderID);
1863 OutPacket(currentPacket, ThrottleOutPacketType.Asset, false);
1864 }
1865 }
1866
1867 private InventoryDescendentsPacket.FolderDataBlock CreateFolderDataBlock(InventoryFolderBase folder)
1868 {
1869 InventoryDescendentsPacket.FolderDataBlock newBlock = new InventoryDescendentsPacket.FolderDataBlock();
1870 newBlock.FolderID = folder.ID;
1871 newBlock.Name = Util.StringToBytes256(folder.Name);
1872 newBlock.ParentID = folder.ParentID;
1873 newBlock.Type = (sbyte)folder.Type;
1874 //if (newBlock.Type == InventoryItemBase.SUITCASE_FOLDER_TYPE)
1875 // newBlock.Type = InventoryItemBase.SUITCASE_FOLDER_FAKE_TYPE;
1876
1877 return newBlock;
1878 }
1879
1880 private InventoryDescendentsPacket.ItemDataBlock CreateItemDataBlock(InventoryItemBase item)
1881 {
1882 InventoryDescendentsPacket.ItemDataBlock newBlock = new InventoryDescendentsPacket.ItemDataBlock();
1883 newBlock.ItemID = item.ID;
1884 newBlock.AssetID = item.AssetID;
1885 newBlock.CreatorID = item.CreatorIdAsUuid;
1886 newBlock.BaseMask = item.BasePermissions;
1887 newBlock.Description = Util.StringToBytes256(item.Description);
1888 newBlock.EveryoneMask = item.EveryOnePermissions;
1889 newBlock.OwnerMask = item.CurrentPermissions;
1890 newBlock.FolderID = item.Folder;
1891 newBlock.InvType = (sbyte)item.InvType;
1892 newBlock.Name = Util.StringToBytes256(item.Name);
1893 newBlock.NextOwnerMask = item.NextPermissions;
1894 newBlock.OwnerID = item.Owner;
1895 newBlock.Type = (sbyte)item.AssetType;
1896
1897 newBlock.GroupID = item.GroupID;
1898 newBlock.GroupOwned = item.GroupOwned;
1899 newBlock.GroupMask = item.GroupPermissions;
1900 newBlock.CreationDate = item.CreationDate;
1901 newBlock.SalePrice = item.SalePrice;
1902 newBlock.SaleType = item.SaleType;
1903 newBlock.Flags = item.Flags & 0x2000ff;
1904
1905 newBlock.CRC =
1906 Helpers.InventoryCRC(newBlock.CreationDate, newBlock.SaleType,
1907 newBlock.InvType, newBlock.Type,
1908 newBlock.AssetID, newBlock.GroupID,
1909 newBlock.SalePrice,
1910 newBlock.OwnerID, newBlock.CreatorID,
1911 newBlock.ItemID, newBlock.FolderID,
1912 newBlock.EveryoneMask,
1913 newBlock.Flags, newBlock.OwnerMask,
1914 newBlock.GroupMask, newBlock.NextOwnerMask);
1915
1916 return newBlock;
1917 }
1918
1919 private void AddNullFolderBlockToDecendentsPacket(ref InventoryDescendentsPacket packet)
1920 {
1921 packet.FolderData = new InventoryDescendentsPacket.FolderDataBlock[1];
1922 packet.FolderData[0] = new InventoryDescendentsPacket.FolderDataBlock();
1923 packet.FolderData[0].FolderID = UUID.Zero;
1924 packet.FolderData[0].ParentID = UUID.Zero;
1925 packet.FolderData[0].Type = -1;
1926 packet.FolderData[0].Name = new byte[0];
1927 }
1928
1929 private void AddNullItemBlockToDescendentsPacket(ref InventoryDescendentsPacket packet)
1930 {
1931 packet.ItemData = new InventoryDescendentsPacket.ItemDataBlock[1];
1932 packet.ItemData[0] = new InventoryDescendentsPacket.ItemDataBlock();
1933 packet.ItemData[0].ItemID = UUID.Zero;
1934 packet.ItemData[0].AssetID = UUID.Zero;
1935 packet.ItemData[0].CreatorID = UUID.Zero;
1936 packet.ItemData[0].BaseMask = 0;
1937 packet.ItemData[0].Description = new byte[0];
1938 packet.ItemData[0].EveryoneMask = 0;
1939 packet.ItemData[0].OwnerMask = 0;
1940 packet.ItemData[0].FolderID = UUID.Zero;
1941 packet.ItemData[0].InvType = (sbyte)0;
1942 packet.ItemData[0].Name = new byte[0];
1943 packet.ItemData[0].NextOwnerMask = 0;
1944 packet.ItemData[0].OwnerID = UUID.Zero;
1945 packet.ItemData[0].Type = -1;
1946
1947 packet.ItemData[0].GroupID = UUID.Zero;
1948 packet.ItemData[0].GroupOwned = false;
1949 packet.ItemData[0].GroupMask = 0;
1950 packet.ItemData[0].CreationDate = 0;
1951 packet.ItemData[0].SalePrice = 0;
1952 packet.ItemData[0].SaleType = 0;
1953 packet.ItemData[0].Flags = 0;
1954
1955 // No need to add CRC
1956 }
1957
1958 private InventoryDescendentsPacket CreateInventoryDescendentsPacket(UUID ownerID, UUID folderID, int version, int descendents, int folders, int items)
1959 {
1960 InventoryDescendentsPacket descend = (InventoryDescendentsPacket)PacketPool.Instance.GetPacket(PacketType.InventoryDescendents);
1961 descend.Header.Zerocoded = true;
1962 descend.AgentData.AgentID = AgentId;
1963 descend.AgentData.OwnerID = ownerID;
1964 descend.AgentData.FolderID = folderID;
1965 descend.AgentData.Version = version;
1966 descend.AgentData.Descendents = descendents;
1967
1968 if (folders > 0)
1969 descend.FolderData = new InventoryDescendentsPacket.FolderDataBlock[folders];
1970 else
1971 AddNullFolderBlockToDecendentsPacket(ref descend);
1972
1973 if (items > 0)
1974 descend.ItemData = new InventoryDescendentsPacket.ItemDataBlock[items];
1975 else
1976 AddNullItemBlockToDescendentsPacket(ref descend);
1977
1978 return descend;
1979 }
1980
1981 public void SendInventoryItemDetails(UUID ownerID, InventoryItemBase item)
1982 {
1983 // Fudge this value. It's only needed to make the CRC anyway
1984 const uint FULL_MASK_PERMISSIONS = (uint)0x7fffffff;
1985
1986 FetchInventoryReplyPacket inventoryReply = (FetchInventoryReplyPacket)PacketPool.Instance.GetPacket(PacketType.FetchInventoryReply);
1987 // TODO: don't create new blocks if recycling an old packet
1988 inventoryReply.AgentData.AgentID = AgentId;
1989 inventoryReply.InventoryData = new FetchInventoryReplyPacket.InventoryDataBlock[1];
1990 inventoryReply.InventoryData[0] = new FetchInventoryReplyPacket.InventoryDataBlock();
1991 inventoryReply.InventoryData[0].ItemID = item.ID;
1992 inventoryReply.InventoryData[0].AssetID = item.AssetID;
1993 inventoryReply.InventoryData[0].CreatorID = item.CreatorIdAsUuid;
1994 inventoryReply.InventoryData[0].BaseMask = item.BasePermissions;
1995 inventoryReply.InventoryData[0].CreationDate = item.CreationDate;
1996
1997 inventoryReply.InventoryData[0].Description = Util.StringToBytes256(item.Description);
1998 inventoryReply.InventoryData[0].EveryoneMask = item.EveryOnePermissions;
1999 inventoryReply.InventoryData[0].FolderID = item.Folder;
2000 inventoryReply.InventoryData[0].InvType = (sbyte)item.InvType;
2001 inventoryReply.InventoryData[0].Name = Util.StringToBytes256(item.Name);
2002 inventoryReply.InventoryData[0].NextOwnerMask = item.NextPermissions;
2003 inventoryReply.InventoryData[0].OwnerID = item.Owner;
2004 inventoryReply.InventoryData[0].OwnerMask = item.CurrentPermissions;
2005 inventoryReply.InventoryData[0].Type = (sbyte)item.AssetType;
2006
2007 inventoryReply.InventoryData[0].GroupID = item.GroupID;
2008 inventoryReply.InventoryData[0].GroupOwned = item.GroupOwned;
2009 inventoryReply.InventoryData[0].GroupMask = item.GroupPermissions;
2010 inventoryReply.InventoryData[0].Flags = item.Flags;
2011 inventoryReply.InventoryData[0].SalePrice = item.SalePrice;
2012 inventoryReply.InventoryData[0].SaleType = item.SaleType;
2013
2014 inventoryReply.InventoryData[0].CRC =
2015 Helpers.InventoryCRC(
2016 1000, 0, inventoryReply.InventoryData[0].InvType,
2017 inventoryReply.InventoryData[0].Type, inventoryReply.InventoryData[0].AssetID,
2018 inventoryReply.InventoryData[0].GroupID, 100,
2019 inventoryReply.InventoryData[0].OwnerID, inventoryReply.InventoryData[0].CreatorID,
2020 inventoryReply.InventoryData[0].ItemID, inventoryReply.InventoryData[0].FolderID,
2021 FULL_MASK_PERMISSIONS, 1, FULL_MASK_PERMISSIONS, FULL_MASK_PERMISSIONS,
2022 FULL_MASK_PERMISSIONS);
2023 inventoryReply.Header.Zerocoded = true;
2024 OutPacket(inventoryReply, ThrottleOutPacketType.Asset);
2025 }
2026
2027 protected void SendBulkUpdateInventoryFolder(InventoryFolderBase folderBase)
2028 {
2029 // We will use the same transaction id for all the separate packets to be sent out in this update.
2030 UUID transactionId = UUID.Random();
2031
2032 List<BulkUpdateInventoryPacket.FolderDataBlock> folderDataBlocks
2033 = new List<BulkUpdateInventoryPacket.FolderDataBlock>();
2034
2035 SendBulkUpdateInventoryFolderRecursive(folderBase, ref folderDataBlocks, transactionId);
2036
2037 if (folderDataBlocks.Count > 0)
2038 {
2039 // We'll end up with some unsent folder blocks if there were some empty folders at the end of the list
2040 // Send these now
2041 BulkUpdateInventoryPacket bulkUpdate
2042 = (BulkUpdateInventoryPacket)PacketPool.Instance.GetPacket(PacketType.BulkUpdateInventory);
2043 bulkUpdate.Header.Zerocoded = true;
2044
2045 bulkUpdate.AgentData.AgentID = AgentId;
2046 bulkUpdate.AgentData.TransactionID = transactionId;
2047 bulkUpdate.FolderData = folderDataBlocks.ToArray();
2048 List<BulkUpdateInventoryPacket.ItemDataBlock> foo = new List<BulkUpdateInventoryPacket.ItemDataBlock>();
2049 bulkUpdate.ItemData = foo.ToArray();
2050
2051 //m_log.Debug("SendBulkUpdateInventory :" + bulkUpdate);
2052 OutPacket(bulkUpdate, ThrottleOutPacketType.Asset);
2053 }
2054 }
2055
2056 /// <summary>
2057 /// Recursively construct bulk update packets to send folders and items
2058 /// </summary>
2059 /// <param name="folder"></param>
2060 /// <param name="folderDataBlocks"></param>
2061 /// <param name="transactionId"></param>
2062 private void SendBulkUpdateInventoryFolderRecursive(
2063 InventoryFolderBase folder, ref List<BulkUpdateInventoryPacket.FolderDataBlock> folderDataBlocks,
2064 UUID transactionId)
2065 {
2066 folderDataBlocks.Add(GenerateBulkUpdateFolderDataBlock(folder));
2067
2068 const int MAX_ITEMS_PER_PACKET = 5;
2069
2070 IInventoryService invService = m_scene.RequestModuleInterface<IInventoryService>();
2071 // If there are any items then we have to start sending them off in this packet - the next folder will have
2072 // to be in its own bulk update packet. Also, we can only fit 5 items in a packet (at least this was the limit
2073 // being used on the Linden grid at 20081203).
2074 InventoryCollection contents = invService.GetFolderContent(AgentId, folder.ID); // folder.RequestListOfItems();
2075 List<InventoryItemBase> items = contents.Items;
2076 while (items.Count > 0)
2077 {
2078 BulkUpdateInventoryPacket bulkUpdate
2079 = (BulkUpdateInventoryPacket)PacketPool.Instance.GetPacket(PacketType.BulkUpdateInventory);
2080 bulkUpdate.Header.Zerocoded = true;
2081
2082 bulkUpdate.AgentData.AgentID = AgentId;
2083 bulkUpdate.AgentData.TransactionID = transactionId;
2084 bulkUpdate.FolderData = folderDataBlocks.ToArray();
2085
2086 int itemsToSend = (items.Count > MAX_ITEMS_PER_PACKET ? MAX_ITEMS_PER_PACKET : items.Count);
2087 bulkUpdate.ItemData = new BulkUpdateInventoryPacket.ItemDataBlock[itemsToSend];
2088
2089 for (int i = 0; i < itemsToSend; i++)
2090 {
2091 // Remove from the end of the list so that we don't incur a performance penalty
2092 bulkUpdate.ItemData[i] = GenerateBulkUpdateItemDataBlock(items[items.Count - 1]);
2093 items.RemoveAt(items.Count - 1);
2094 }
2095
2096 //m_log.Debug("SendBulkUpdateInventoryRecursive :" + bulkUpdate);
2097 OutPacket(bulkUpdate, ThrottleOutPacketType.Asset);
2098
2099 folderDataBlocks = new List<BulkUpdateInventoryPacket.FolderDataBlock>();
2100
2101 // If we're going to be sending another items packet then it needs to contain just the folder to which those
2102 // items belong.
2103 if (items.Count > 0)
2104 folderDataBlocks.Add(GenerateBulkUpdateFolderDataBlock(folder));
2105 }
2106
2107 List<InventoryFolderBase> subFolders = contents.Folders;
2108 foreach (InventoryFolderBase subFolder in subFolders)
2109 {
2110 SendBulkUpdateInventoryFolderRecursive(subFolder, ref folderDataBlocks, transactionId);
2111 }
2112 }
2113
2114 /// <summary>
2115 /// Generate a bulk update inventory data block for the given folder
2116 /// </summary>
2117 /// <param name="folder"></param>
2118 /// <returns></returns>
2119 private BulkUpdateInventoryPacket.FolderDataBlock GenerateBulkUpdateFolderDataBlock(InventoryFolderBase folder)
2120 {
2121 BulkUpdateInventoryPacket.FolderDataBlock folderBlock = new BulkUpdateInventoryPacket.FolderDataBlock();
2122
2123 folderBlock.FolderID = folder.ID;
2124 folderBlock.ParentID = folder.ParentID;
2125 folderBlock.Type = (sbyte)folder.Type;
2126 // Leaving this here for now, just in case we need to do this for a while
2127 //if (folderBlock.Type == InventoryItemBase.SUITCASE_FOLDER_TYPE)
2128 // folderBlock.Type = InventoryItemBase.SUITCASE_FOLDER_FAKE_TYPE;
2129 folderBlock.Name = Util.StringToBytes256(folder.Name);
2130
2131 return folderBlock;
2132 }
2133
2134 /// <summary>
2135 /// Generate a bulk update inventory data block for the given item
2136 /// </summary>
2137 /// <param name="item"></param>
2138 /// <returns></returns>
2139 private BulkUpdateInventoryPacket.ItemDataBlock GenerateBulkUpdateItemDataBlock(InventoryItemBase item)
2140 {
2141 BulkUpdateInventoryPacket.ItemDataBlock itemBlock = new BulkUpdateInventoryPacket.ItemDataBlock();
2142
2143 itemBlock.ItemID = item.ID;
2144 itemBlock.AssetID = item.AssetID;
2145 itemBlock.CreatorID = item.CreatorIdAsUuid;
2146 itemBlock.BaseMask = item.BasePermissions;
2147 itemBlock.Description = Util.StringToBytes256(item.Description);
2148 itemBlock.EveryoneMask = item.EveryOnePermissions;
2149 itemBlock.FolderID = item.Folder;
2150 itemBlock.InvType = (sbyte)item.InvType;
2151 itemBlock.Name = Util.StringToBytes256(item.Name);
2152 itemBlock.NextOwnerMask = item.NextPermissions;
2153 itemBlock.OwnerID = item.Owner;
2154 itemBlock.OwnerMask = item.CurrentPermissions;
2155 itemBlock.Type = (sbyte)item.AssetType;
2156 itemBlock.GroupID = item.GroupID;
2157 itemBlock.GroupOwned = item.GroupOwned;
2158 itemBlock.GroupMask = item.GroupPermissions;
2159 itemBlock.Flags = item.Flags & 0x2000ff;
2160 itemBlock.SalePrice = item.SalePrice;
2161 itemBlock.SaleType = item.SaleType;
2162 itemBlock.CreationDate = item.CreationDate;
2163
2164 itemBlock.CRC =
2165 Helpers.InventoryCRC(
2166 1000, 0, itemBlock.InvType,
2167 itemBlock.Type, itemBlock.AssetID,
2168 itemBlock.GroupID, 100,
2169 itemBlock.OwnerID, itemBlock.CreatorID,
2170 itemBlock.ItemID, itemBlock.FolderID,
2171 (uint)PermissionMask.All, 1, (uint)PermissionMask.All, (uint)PermissionMask.All,
2172 (uint)PermissionMask.All);
2173
2174 return itemBlock;
2175 }
2176
2177 public void SendBulkUpdateInventory(InventoryNodeBase node)
2178 {
2179 if (node is InventoryItemBase)
2180 SendBulkUpdateInventoryItem((InventoryItemBase)node);
2181 else if (node is InventoryFolderBase)
2182 SendBulkUpdateInventoryFolder((InventoryFolderBase)node);
2183 else if (node != null)
2184 m_log.ErrorFormat("[CLIENT]: {0} sent unknown inventory node named {1}", Name, node.Name);
2185 else
2186 m_log.ErrorFormat("[CLIENT]: {0} sent null inventory node", Name);
2187 }
2188
2189 protected void SendBulkUpdateInventoryItem(InventoryItemBase item)
2190 {
2191 const uint FULL_MASK_PERMISSIONS = (uint)0x7ffffff;
2192
2193 BulkUpdateInventoryPacket bulkUpdate
2194 = (BulkUpdateInventoryPacket)PacketPool.Instance.GetPacket(PacketType.BulkUpdateInventory);
2195
2196 bulkUpdate.AgentData.AgentID = AgentId;
2197 bulkUpdate.AgentData.TransactionID = UUID.Random();
2198
2199 bulkUpdate.FolderData = new BulkUpdateInventoryPacket.FolderDataBlock[1];
2200 bulkUpdate.FolderData[0] = new BulkUpdateInventoryPacket.FolderDataBlock();
2201 bulkUpdate.FolderData[0].FolderID = UUID.Zero;
2202 bulkUpdate.FolderData[0].ParentID = UUID.Zero;
2203 bulkUpdate.FolderData[0].Type = -1;
2204 bulkUpdate.FolderData[0].Name = new byte[0];
2205
2206 bulkUpdate.ItemData = new BulkUpdateInventoryPacket.ItemDataBlock[1];
2207 bulkUpdate.ItemData[0] = new BulkUpdateInventoryPacket.ItemDataBlock();
2208 bulkUpdate.ItemData[0].ItemID = item.ID;
2209 bulkUpdate.ItemData[0].AssetID = item.AssetID;
2210 bulkUpdate.ItemData[0].CreatorID = item.CreatorIdAsUuid;
2211 bulkUpdate.ItemData[0].BaseMask = item.BasePermissions;
2212 bulkUpdate.ItemData[0].CreationDate = item.CreationDate;
2213 bulkUpdate.ItemData[0].Description = Util.StringToBytes256(item.Description);
2214 bulkUpdate.ItemData[0].EveryoneMask = item.EveryOnePermissions;
2215 bulkUpdate.ItemData[0].FolderID = item.Folder;
2216 bulkUpdate.ItemData[0].InvType = (sbyte)item.InvType;
2217 bulkUpdate.ItemData[0].Name = Util.StringToBytes256(item.Name);
2218 bulkUpdate.ItemData[0].NextOwnerMask = item.NextPermissions;
2219 bulkUpdate.ItemData[0].OwnerID = item.Owner;
2220 bulkUpdate.ItemData[0].OwnerMask = item.CurrentPermissions;
2221 bulkUpdate.ItemData[0].Type = (sbyte)item.AssetType;
2222
2223 bulkUpdate.ItemData[0].GroupID = item.GroupID;
2224 bulkUpdate.ItemData[0].GroupOwned = item.GroupOwned;
2225 bulkUpdate.ItemData[0].GroupMask = item.GroupPermissions;
2226 bulkUpdate.ItemData[0].Flags = item.Flags & 0x2000ff;
2227 bulkUpdate.ItemData[0].SalePrice = item.SalePrice;
2228 bulkUpdate.ItemData[0].SaleType = item.SaleType;
2229
2230 bulkUpdate.ItemData[0].CRC =
2231 Helpers.InventoryCRC(1000, 0, bulkUpdate.ItemData[0].InvType,
2232 bulkUpdate.ItemData[0].Type, bulkUpdate.ItemData[0].AssetID,
2233 bulkUpdate.ItemData[0].GroupID, 100,
2234 bulkUpdate.ItemData[0].OwnerID, bulkUpdate.ItemData[0].CreatorID,
2235 bulkUpdate.ItemData[0].ItemID, bulkUpdate.ItemData[0].FolderID,
2236 FULL_MASK_PERMISSIONS, 1, FULL_MASK_PERMISSIONS, FULL_MASK_PERMISSIONS,
2237 FULL_MASK_PERMISSIONS);
2238 bulkUpdate.Header.Zerocoded = true;
2239 OutPacket(bulkUpdate, ThrottleOutPacketType.Asset);
2240 }
2241
2242 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, uint callbackId)
2243 {
2244 SendInventoryItemCreateUpdate(Item, UUID.Zero, callbackId);
2245 }
2246
2247 /// <see>IClientAPI.SendInventoryItemCreateUpdate(InventoryItemBase)</see>
2248 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, UUID transactionID, uint callbackId)
2249 {
2250 const uint FULL_MASK_PERMISSIONS = (uint)0x7fffffff;
2251
2252 UpdateCreateInventoryItemPacket InventoryReply
2253 = (UpdateCreateInventoryItemPacket)PacketPool.Instance.GetPacket(
2254 PacketType.UpdateCreateInventoryItem);
2255
2256 // TODO: don't create new blocks if recycling an old packet
2257 InventoryReply.AgentData.AgentID = AgentId;
2258 InventoryReply.AgentData.SimApproved = true;
2259 InventoryReply.AgentData.TransactionID = transactionID;
2260 InventoryReply.InventoryData = new UpdateCreateInventoryItemPacket.InventoryDataBlock[1];
2261 InventoryReply.InventoryData[0] = new UpdateCreateInventoryItemPacket.InventoryDataBlock();
2262 InventoryReply.InventoryData[0].ItemID = Item.ID;
2263 InventoryReply.InventoryData[0].AssetID = Item.AssetID;
2264 InventoryReply.InventoryData[0].CreatorID = Item.CreatorIdAsUuid;
2265 InventoryReply.InventoryData[0].BaseMask = Item.BasePermissions;
2266 InventoryReply.InventoryData[0].Description = Util.StringToBytes256(Item.Description);
2267 InventoryReply.InventoryData[0].EveryoneMask = Item.EveryOnePermissions;
2268 InventoryReply.InventoryData[0].FolderID = Item.Folder;
2269 InventoryReply.InventoryData[0].InvType = (sbyte)Item.InvType;
2270 InventoryReply.InventoryData[0].Name = Util.StringToBytes256(Item.Name);
2271 InventoryReply.InventoryData[0].NextOwnerMask = Item.NextPermissions;
2272 InventoryReply.InventoryData[0].OwnerID = Item.Owner;
2273 InventoryReply.InventoryData[0].OwnerMask = Item.CurrentPermissions;
2274 InventoryReply.InventoryData[0].Type = (sbyte)Item.AssetType;
2275 InventoryReply.InventoryData[0].CallbackID = callbackId;
2276
2277 InventoryReply.InventoryData[0].GroupID = Item.GroupID;
2278 InventoryReply.InventoryData[0].GroupOwned = Item.GroupOwned;
2279 InventoryReply.InventoryData[0].GroupMask = Item.GroupPermissions;
2280 InventoryReply.InventoryData[0].Flags = Item.Flags & 0x2000ff;
2281 InventoryReply.InventoryData[0].SalePrice = Item.SalePrice;
2282 InventoryReply.InventoryData[0].SaleType = Item.SaleType;
2283 InventoryReply.InventoryData[0].CreationDate = Item.CreationDate;
2284
2285 InventoryReply.InventoryData[0].CRC =
2286 Helpers.InventoryCRC(1000, 0, InventoryReply.InventoryData[0].InvType,
2287 InventoryReply.InventoryData[0].Type, InventoryReply.InventoryData[0].AssetID,
2288 InventoryReply.InventoryData[0].GroupID, 100,
2289 InventoryReply.InventoryData[0].OwnerID, InventoryReply.InventoryData[0].CreatorID,
2290 InventoryReply.InventoryData[0].ItemID, InventoryReply.InventoryData[0].FolderID,
2291 FULL_MASK_PERMISSIONS, 1, FULL_MASK_PERMISSIONS, FULL_MASK_PERMISSIONS,
2292 FULL_MASK_PERMISSIONS);
2293 InventoryReply.Header.Zerocoded = true;
2294 OutPacket(InventoryReply, ThrottleOutPacketType.Asset);
2295 }
2296
2297 public void SendRemoveInventoryItem(UUID itemID)
2298 {
2299 RemoveInventoryItemPacket remove = (RemoveInventoryItemPacket)PacketPool.Instance.GetPacket(PacketType.RemoveInventoryItem);
2300 // TODO: don't create new blocks if recycling an old packet
2301 remove.AgentData.AgentID = AgentId;
2302 remove.AgentData.SessionID = m_sessionId;
2303 remove.InventoryData = new RemoveInventoryItemPacket.InventoryDataBlock[1];
2304 remove.InventoryData[0] = new RemoveInventoryItemPacket.InventoryDataBlock();
2305 remove.InventoryData[0].ItemID = itemID;
2306 remove.Header.Zerocoded = true;
2307 OutPacket(remove, ThrottleOutPacketType.Asset);
2308 }
2309
2310/*
2311 private uint adjustControls(int input)
2312 {
2313 uint ret = (uint)input;
2314 uint masked = ret & 0x0f;
2315 masked <<= 19;
2316 ret |= masked;
2317 return ret;
2318 }
2319*/
2320
2321 public void SendTakeControls(int controls, bool passToAgent, bool TakeControls)
2322 {
2323 ScriptControlChangePacket scriptcontrol = (ScriptControlChangePacket)PacketPool.Instance.GetPacket(PacketType.ScriptControlChange);
2324 ScriptControlChangePacket.DataBlock[] data = new ScriptControlChangePacket.DataBlock[1];
2325 ScriptControlChangePacket.DataBlock ddata = new ScriptControlChangePacket.DataBlock();
2326// ddata.Controls = adjustControls(controls);
2327 ddata.Controls = (uint)controls;
2328 ddata.PassToAgent = passToAgent;
2329 ddata.TakeControls = TakeControls;
2330 data[0] = ddata;
2331 scriptcontrol.Data = data;
2332 OutPacket(scriptcontrol, ThrottleOutPacketType.Task);
2333 }
2334
2335 public void SendTaskInventory(UUID taskID, short serial, byte[] fileName)
2336 {
2337 ReplyTaskInventoryPacket replytask = (ReplyTaskInventoryPacket)PacketPool.Instance.GetPacket(PacketType.ReplyTaskInventory);
2338 replytask.InventoryData.TaskID = taskID;
2339 replytask.InventoryData.Serial = serial;
2340 replytask.InventoryData.Filename = fileName;
2341// OutPacket(replytask, ThrottleOutPacketType.Task);
2342 OutPacket(replytask, ThrottleOutPacketType.Asset);
2343 }
2344
2345 public void SendXferPacket(ulong xferID, uint packet, byte[] data, bool isTaskInventory)
2346 {
2347 ThrottleOutPacketType type = ThrottleOutPacketType.Asset;
2348// if (isTaskInventory)
2349// type = ThrottleOutPacketType.Task;
2350
2351 SendXferPacketPacket sendXfer = (SendXferPacketPacket)PacketPool.Instance.GetPacket(PacketType.SendXferPacket);
2352 sendXfer.XferID.ID = xferID;
2353 sendXfer.XferID.Packet = packet;
2354 sendXfer.DataPacket.Data = data;
2355 OutPacket(sendXfer, type);
2356 }
2357
2358 public void SendAbortXferPacket(ulong xferID)
2359 {
2360 AbortXferPacket xferItem = (AbortXferPacket)PacketPool.Instance.GetPacket(PacketType.AbortXfer);
2361 xferItem.XferID.ID = xferID;
2362 OutPacket(xferItem, ThrottleOutPacketType.Asset);
2363 }
2364
2365 public void SendEconomyData(float EnergyEfficiency, int ObjectCapacity, int ObjectCount, int PriceEnergyUnit,
2366 int PriceGroupCreate, int PriceObjectClaim, float PriceObjectRent, float PriceObjectScaleFactor,
2367 int PriceParcelClaim, float PriceParcelClaimFactor, int PriceParcelRent, int PricePublicObjectDecay,
2368 int PricePublicObjectDelete, int PriceRentLight, int PriceUpload, int TeleportMinPrice, float TeleportPriceExponent)
2369 {
2370 EconomyDataPacket economyData = (EconomyDataPacket)PacketPool.Instance.GetPacket(PacketType.EconomyData);
2371 economyData.Info.EnergyEfficiency = EnergyEfficiency;
2372 economyData.Info.ObjectCapacity = ObjectCapacity;
2373 economyData.Info.ObjectCount = ObjectCount;
2374 economyData.Info.PriceEnergyUnit = PriceEnergyUnit;
2375 economyData.Info.PriceGroupCreate = PriceGroupCreate;
2376 economyData.Info.PriceObjectClaim = PriceObjectClaim;
2377 economyData.Info.PriceObjectRent = PriceObjectRent;
2378 economyData.Info.PriceObjectScaleFactor = PriceObjectScaleFactor;
2379 economyData.Info.PriceParcelClaim = PriceParcelClaim;
2380 economyData.Info.PriceParcelClaimFactor = PriceParcelClaimFactor;
2381 economyData.Info.PriceParcelRent = PriceParcelRent;
2382 economyData.Info.PricePublicObjectDecay = PricePublicObjectDecay;
2383 economyData.Info.PricePublicObjectDelete = PricePublicObjectDelete;
2384 economyData.Info.PriceRentLight = PriceRentLight;
2385 economyData.Info.PriceUpload = PriceUpload;
2386 economyData.Info.TeleportMinPrice = TeleportMinPrice;
2387 economyData.Info.TeleportPriceExponent = TeleportPriceExponent;
2388 economyData.Header.Reliable = true;
2389 OutPacket(economyData, ThrottleOutPacketType.Task);
2390 }
2391
2392 public void SendAvatarPickerReply(AvatarPickerReplyAgentDataArgs AgentData, List<AvatarPickerReplyDataArgs> Data)
2393 {
2394 //construct the AvatarPickerReply packet.
2395 AvatarPickerReplyPacket replyPacket = new AvatarPickerReplyPacket();
2396 replyPacket.AgentData.AgentID = AgentData.AgentID;
2397 replyPacket.AgentData.QueryID = AgentData.QueryID;
2398 //int i = 0;
2399 List<AvatarPickerReplyPacket.DataBlock> data_block = new List<AvatarPickerReplyPacket.DataBlock>();
2400 foreach (AvatarPickerReplyDataArgs arg in Data)
2401 {
2402 AvatarPickerReplyPacket.DataBlock db = new AvatarPickerReplyPacket.DataBlock();
2403 db.AvatarID = arg.AvatarID;
2404 db.FirstName = arg.FirstName;
2405 db.LastName = arg.LastName;
2406 data_block.Add(db);
2407 }
2408 replyPacket.Data = data_block.ToArray();
2409 OutPacket(replyPacket, ThrottleOutPacketType.Task);
2410 }
2411
2412 public void SendAgentDataUpdate(UUID agentid, UUID activegroupid, string firstname, string lastname, ulong grouppowers, string groupname, string grouptitle)
2413 {
2414 if (agentid == AgentId)
2415 {
2416 ActiveGroupId = activegroupid;
2417 ActiveGroupName = groupname;
2418 ActiveGroupPowers = grouppowers;
2419 }
2420
2421 AgentDataUpdatePacket sendAgentDataUpdate = (AgentDataUpdatePacket)PacketPool.Instance.GetPacket(PacketType.AgentDataUpdate);
2422 sendAgentDataUpdate.AgentData.ActiveGroupID = activegroupid;
2423 sendAgentDataUpdate.AgentData.AgentID = agentid;
2424 sendAgentDataUpdate.AgentData.FirstName = Util.StringToBytes256(firstname);
2425 sendAgentDataUpdate.AgentData.GroupName = Util.StringToBytes256(groupname);
2426 sendAgentDataUpdate.AgentData.GroupPowers = grouppowers;
2427 sendAgentDataUpdate.AgentData.GroupTitle = Util.StringToBytes256(grouptitle);
2428 sendAgentDataUpdate.AgentData.LastName = Util.StringToBytes256(lastname);
2429 OutPacket(sendAgentDataUpdate, ThrottleOutPacketType.Task);
2430 }
2431
2432 /// <summary>
2433 /// Send an alert message to the client. On the Linden client (tested 1.19.1.4), this pops up a brief duration
2434 /// blue information box in the bottom right hand corner.
2435 /// </summary>
2436 /// <param name="message"></param>
2437 public void SendAlertMessage(string message)
2438 {
2439 AlertMessagePacket alertPack = (AlertMessagePacket)PacketPool.Instance.GetPacket(PacketType.AlertMessage);
2440 alertPack.AlertData = new AlertMessagePacket.AlertDataBlock();
2441 alertPack.AlertData.Message = Util.StringToBytes256(message);
2442 alertPack.AlertInfo = new AlertMessagePacket.AlertInfoBlock[0];
2443 OutPacket(alertPack, ThrottleOutPacketType.Task);
2444 }
2445
2446 public void SendAlertMessage(string message, string info)
2447 {
2448 AlertMessagePacket alertPack = (AlertMessagePacket)PacketPool.Instance.GetPacket(PacketType.AlertMessage);
2449 alertPack.AlertData = new AlertMessagePacket.AlertDataBlock();
2450 alertPack.AlertData.Message = Util.StringToBytes256(message);
2451 alertPack.AlertInfo = new AlertMessagePacket.AlertInfoBlock[1];
2452 alertPack.AlertInfo[0] = new AlertMessagePacket.AlertInfoBlock();
2453 alertPack.AlertInfo[0].Message = Util.StringToBytes256(info);
2454 alertPack.AlertInfo[0].ExtraParams = new Byte[0];
2455 OutPacket(alertPack, ThrottleOutPacketType.Task);
2456 }
2457
2458 /// <summary>
2459 /// Send an agent alert message to the client.
2460 /// </summary>
2461 /// <param name="message"></param>
2462 /// <param name="modal">On the linden client, if this true then it displays a one button text box placed in the
2463 /// middle of the window. If false, the message is displayed in a brief duration blue information box (as for
2464 /// the AlertMessage packet).</param>
2465 public void SendAgentAlertMessage(string message, bool modal)
2466 {
2467 OutPacket(BuildAgentAlertPacket(message, modal), ThrottleOutPacketType.Task);
2468 }
2469
2470 /// <summary>
2471 /// Construct an agent alert packet
2472 /// </summary>
2473 /// <param name="message"></param>
2474 /// <param name="modal"></param>
2475 /// <returns></returns>
2476 public AgentAlertMessagePacket BuildAgentAlertPacket(string message, bool modal)
2477 {
2478 // Prepend a slash to make the message come up in the top right
2479 // again.
2480 // Allow special formats to be sent from aware modules.
2481 if (!modal && !message.StartsWith("ALERT: ") && !message.StartsWith("NOTIFY: ") && message != "Home position set." && message != "You died and have been teleported to your home location")
2482 message = "/" + message;
2483 AgentAlertMessagePacket alertPack = (AgentAlertMessagePacket)PacketPool.Instance.GetPacket(PacketType.AgentAlertMessage);
2484 alertPack.AgentData.AgentID = AgentId;
2485 alertPack.AlertData.Message = Util.StringToBytes256(message);
2486 alertPack.AlertData.Modal = modal;
2487
2488 return alertPack;
2489 }
2490
2491 public void SendLoadURL(string objectname, UUID objectID, UUID ownerID, bool groupOwned, string message,
2492 string url)
2493 {
2494 LoadURLPacket loadURL = (LoadURLPacket)PacketPool.Instance.GetPacket(PacketType.LoadURL);
2495 loadURL.Data.ObjectName = Util.StringToBytes256(objectname);
2496 loadURL.Data.ObjectID = objectID;
2497 loadURL.Data.OwnerID = ownerID;
2498 loadURL.Data.OwnerIsGroup = groupOwned;
2499 loadURL.Data.Message = Util.StringToBytes256(message);
2500 loadURL.Data.URL = Util.StringToBytes256(url);
2501 OutPacket(loadURL, ThrottleOutPacketType.Task);
2502 }
2503
2504 public void SendDialog(
2505 string objectname, UUID objectID, UUID ownerID, string ownerFirstName, string ownerLastName, string msg,
2506 UUID textureID, int ch, string[] buttonlabels)
2507 {
2508 ScriptDialogPacket dialog = (ScriptDialogPacket)PacketPool.Instance.GetPacket(PacketType.ScriptDialog);
2509 dialog.Data.ObjectID = objectID;
2510 dialog.Data.ObjectName = Util.StringToBytes256(objectname);
2511 // this is the username of the *owner*
2512 dialog.Data.FirstName = Util.StringToBytes256(ownerFirstName);
2513 dialog.Data.LastName = Util.StringToBytes256(ownerLastName);
2514 dialog.Data.Message = Util.StringToBytes(msg,512);
2515 dialog.Data.ImageID = textureID;
2516 dialog.Data.ChatChannel = ch;
2517 ScriptDialogPacket.ButtonsBlock[] buttons = new ScriptDialogPacket.ButtonsBlock[buttonlabels.Length];
2518 for (int i = 0; i < buttonlabels.Length; i++)
2519 {
2520 buttons[i] = new ScriptDialogPacket.ButtonsBlock();
2521 buttons[i].ButtonLabel = Util.StringToBytes256(buttonlabels[i]);
2522 }
2523 dialog.Buttons = buttons;
2524
2525 dialog.OwnerData = new ScriptDialogPacket.OwnerDataBlock[1];
2526 dialog.OwnerData[0] = new ScriptDialogPacket.OwnerDataBlock();
2527 dialog.OwnerData[0].OwnerID = ownerID;
2528
2529 OutPacket(dialog, ThrottleOutPacketType.Task);
2530 }
2531
2532 public void SendPreLoadSound(UUID objectID, UUID ownerID, UUID soundID)
2533 {
2534 PreloadSoundPacket preSound = (PreloadSoundPacket)PacketPool.Instance.GetPacket(PacketType.PreloadSound);
2535 // TODO: don't create new blocks if recycling an old packet
2536 preSound.DataBlock = new PreloadSoundPacket.DataBlockBlock[1];
2537 preSound.DataBlock[0] = new PreloadSoundPacket.DataBlockBlock();
2538 preSound.DataBlock[0].ObjectID = objectID;
2539 preSound.DataBlock[0].OwnerID = ownerID;
2540 preSound.DataBlock[0].SoundID = soundID;
2541 preSound.Header.Zerocoded = true;
2542 OutPacket(preSound, ThrottleOutPacketType.Task);
2543 }
2544
2545 public void SendPlayAttachedSound(UUID soundID, UUID objectID, UUID ownerID, float gain, byte flags)
2546 {
2547 AttachedSoundPacket sound = (AttachedSoundPacket)PacketPool.Instance.GetPacket(PacketType.AttachedSound);
2548 sound.DataBlock.SoundID = soundID;
2549 sound.DataBlock.ObjectID = objectID;
2550 sound.DataBlock.OwnerID = ownerID;
2551 sound.DataBlock.Gain = gain;
2552 sound.DataBlock.Flags = flags;
2553
2554 OutPacket(sound, ThrottleOutPacketType.Task);
2555 }
2556
2557 public void SendTransferAbort(TransferRequestPacket transferRequest)
2558 {
2559 TransferAbortPacket abort = (TransferAbortPacket)PacketPool.Instance.GetPacket(PacketType.TransferAbort);
2560 abort.TransferInfo.TransferID = transferRequest.TransferInfo.TransferID;
2561 abort.TransferInfo.ChannelType = transferRequest.TransferInfo.ChannelType;
2562 m_log.Debug("[Assets] Aborting transfer; asset request failed");
2563 OutPacket(abort, ThrottleOutPacketType.Task);
2564 }
2565
2566 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain)
2567 {
2568 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger);
2569 sound.SoundData.SoundID = soundID;
2570 sound.SoundData.OwnerID = ownerID;
2571 sound.SoundData.ObjectID = objectID;
2572 sound.SoundData.ParentID = parentID;
2573 sound.SoundData.Handle = handle;
2574 sound.SoundData.Position = position;
2575 sound.SoundData.Gain = gain;
2576
2577 OutPacket(sound, ThrottleOutPacketType.Task);
2578 }
2579
2580 public void SendAttachedSoundGainChange(UUID objectID, float gain)
2581 {
2582 AttachedSoundGainChangePacket sound = (AttachedSoundGainChangePacket)PacketPool.Instance.GetPacket(PacketType.AttachedSoundGainChange);
2583 sound.DataBlock.ObjectID = objectID;
2584 sound.DataBlock.Gain = gain;
2585
2586 OutPacket(sound, ThrottleOutPacketType.Task);
2587 }
2588
2589 public void SendSunPos(Vector3 Position, Vector3 Velocity, ulong CurrentTime, uint SecondsPerSunCycle, uint SecondsPerYear, float OrbitalPosition)
2590 {
2591 // Viewers based on the Linden viwer code, do wacky things for oribital positions from Midnight to Sunrise
2592 // So adjust for that
2593 // Contributed by: Godfrey
2594
2595 if (OrbitalPosition > m_sunPainDaHalfOrbitalCutoff) // things get weird from midnight to sunrise
2596 {
2597 OrbitalPosition = (OrbitalPosition - m_sunPainDaHalfOrbitalCutoff) * 0.6666666667f + m_sunPainDaHalfOrbitalCutoff;
2598 }
2599
2600 SimulatorViewerTimeMessagePacket viewertime = (SimulatorViewerTimeMessagePacket)PacketPool.Instance.GetPacket(PacketType.SimulatorViewerTimeMessage);
2601 viewertime.TimeInfo.SunDirection = Position;
2602 viewertime.TimeInfo.SunAngVelocity = Velocity;
2603
2604 // Sun module used to add 6 hours to adjust for linden sun hour, adding here
2605 // to prevent existing code from breaking if it assumed that 6 hours were included.
2606 // 21600 == 6 hours * 60 minutes * 60 Seconds
2607 viewertime.TimeInfo.UsecSinceStart = CurrentTime + 21600;
2608
2609 viewertime.TimeInfo.SecPerDay = SecondsPerSunCycle;
2610 viewertime.TimeInfo.SecPerYear = SecondsPerYear;
2611 viewertime.TimeInfo.SunPhase = OrbitalPosition;
2612 viewertime.Header.Reliable = false;
2613 viewertime.Header.Zerocoded = true;
2614 OutPacket(viewertime, ThrottleOutPacketType.Task);
2615 }
2616
2617 // Currently Deprecated
2618 public void SendViewerTime(int phase)
2619 {
2620 /*
2621 Console.WriteLine("SunPhase: {0}", phase);
2622 SimulatorViewerTimeMessagePacket viewertime = (SimulatorViewerTimeMessagePacket)PacketPool.Instance.GetPacket(PacketType.SimulatorViewerTimeMessage);
2623 //viewertime.TimeInfo.SecPerDay = 86400;
2624 //viewertime.TimeInfo.SecPerYear = 31536000;
2625 viewertime.TimeInfo.SecPerDay = 1000;
2626 viewertime.TimeInfo.SecPerYear = 365000;
2627 viewertime.TimeInfo.SunPhase = 1;
2628 int sunPhase = (phase + 2) / 2;
2629 if ((sunPhase < 6) || (sunPhase > 36))
2630 {
2631 viewertime.TimeInfo.SunDirection = new Vector3(0f, 0.8f, -0.8f);
2632 Console.WriteLine("sending night");
2633 }
2634 else
2635 {
2636 if (sunPhase < 12)
2637 {
2638 sunPhase = 12;
2639 }
2640 sunPhase = sunPhase - 12;
2641
2642 float yValue = 0.1f * (sunPhase);
2643 Console.WriteLine("Computed SunPhase: {0}, yValue: {1}", sunPhase, yValue);
2644 if (yValue > 1.2f)
2645 {
2646 yValue = yValue - 1.2f;
2647 }
2648
2649 yValue = Util.Clip(yValue, 0, 1);
2650
2651 if (sunPhase < 14)
2652 {
2653 yValue = 1 - yValue;
2654 }
2655 if (sunPhase < 12)
2656 {
2657 yValue *= -1;
2658 }
2659 viewertime.TimeInfo.SunDirection = new Vector3(0f, yValue, 0.3f);
2660 Console.WriteLine("sending sun update " + yValue);
2661 }
2662 viewertime.TimeInfo.SunAngVelocity = new Vector3(0, 0.0f, 10.0f);
2663 viewertime.TimeInfo.UsecSinceStart = (ulong)Util.UnixTimeSinceEpoch();
2664 viewertime.Header.Reliable = false;
2665 OutPacket(viewertime, ThrottleOutPacketType.Task);
2666 */
2667 }
2668
2669 public void SendViewerEffect(ViewerEffectPacket.EffectBlock[] effectBlocks)
2670 {
2671 ViewerEffectPacket packet = (ViewerEffectPacket)PacketPool.Instance.GetPacket(PacketType.ViewerEffect);
2672 packet.Header.Reliable = false;
2673 packet.Header.Zerocoded = true;
2674
2675 packet.AgentData.AgentID = AgentId;
2676 packet.AgentData.SessionID = SessionId;
2677
2678 packet.Effect = effectBlocks;
2679
2680 // OutPacket(packet, ThrottleOutPacketType.State);
2681 OutPacket(packet, ThrottleOutPacketType.Task);
2682 }
2683
2684 public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] membershipType,
2685 string flAbout, uint flags, UUID flImageID, UUID imageID, string profileURL,
2686 UUID partnerID)
2687 {
2688 AvatarPropertiesReplyPacket avatarReply = (AvatarPropertiesReplyPacket)PacketPool.Instance.GetPacket(PacketType.AvatarPropertiesReply);
2689 avatarReply.AgentData.AgentID = AgentId;
2690 avatarReply.AgentData.AvatarID = avatarID;
2691 if (aboutText != null)
2692 avatarReply.PropertiesData.AboutText = Util.StringToBytes1024(aboutText);
2693 else
2694 avatarReply.PropertiesData.AboutText = Utils.EmptyBytes;
2695 avatarReply.PropertiesData.BornOn = Util.StringToBytes256(bornOn);
2696 avatarReply.PropertiesData.CharterMember = membershipType;
2697 if (flAbout != null)
2698 avatarReply.PropertiesData.FLAboutText = Util.StringToBytes256(flAbout);
2699 else
2700 avatarReply.PropertiesData.FLAboutText = Utils.EmptyBytes;
2701 avatarReply.PropertiesData.Flags = flags;
2702 avatarReply.PropertiesData.FLImageID = flImageID;
2703 avatarReply.PropertiesData.ImageID = imageID;
2704 avatarReply.PropertiesData.ProfileURL = Util.StringToBytes256(profileURL);
2705 avatarReply.PropertiesData.PartnerID = partnerID;
2706 OutPacket(avatarReply, ThrottleOutPacketType.Task);
2707 }
2708
2709 /// <summary>
2710 /// Send the client an Estate message blue box pop-down with a single OK button
2711 /// </summary>
2712 /// <param name="FromAvatarID"></param>
2713 /// <param name="fromSessionID"></param>
2714 /// <param name="FromAvatarName"></param>
2715 /// <param name="Message"></param>
2716 public void SendBlueBoxMessage(UUID FromAvatarID, String FromAvatarName, String Message)
2717 {
2718 if (!SceneAgent.IsChildAgent)
2719 SendInstantMessage(new GridInstantMessage(null, FromAvatarID, FromAvatarName, AgentId, 1, Message, false, new Vector3()));
2720
2721 //SendInstantMessage(FromAvatarID, fromSessionID, Message, AgentId, SessionId, FromAvatarName, (byte)21,(uint) Util.UnixTimeSinceEpoch());
2722 }
2723
2724 public void SendLogoutPacket()
2725 {
2726 // I know this is a bit of a hack, however there are times when you don't
2727 // want to send this, but still need to do the rest of the shutdown process
2728 // this method gets called from the packet server.. which makes it practically
2729 // impossible to do any other way.
2730
2731 if (m_SendLogoutPacketWhenClosing)
2732 {
2733 LogoutReplyPacket logReply = (LogoutReplyPacket)PacketPool.Instance.GetPacket(PacketType.LogoutReply);
2734 // TODO: don't create new blocks if recycling an old packet
2735 logReply.AgentData.AgentID = AgentId;
2736 logReply.AgentData.SessionID = SessionId;
2737 logReply.InventoryData = new LogoutReplyPacket.InventoryDataBlock[1];
2738 logReply.InventoryData[0] = new LogoutReplyPacket.InventoryDataBlock();
2739 logReply.InventoryData[0].ItemID = UUID.Zero;
2740
2741 OutPacket(logReply, ThrottleOutPacketType.Task);
2742 }
2743 }
2744
2745 public void SendHealth(float health)
2746 {
2747 HealthMessagePacket healthpacket = (HealthMessagePacket)PacketPool.Instance.GetPacket(PacketType.HealthMessage);
2748 healthpacket.HealthData.Health = health;
2749 OutPacket(healthpacket, ThrottleOutPacketType.Task);
2750 }
2751
2752 public void SendAgentOnline(UUID[] agentIDs)
2753 {
2754 OnlineNotificationPacket onp = new OnlineNotificationPacket();
2755 OnlineNotificationPacket.AgentBlockBlock[] onpb = new OnlineNotificationPacket.AgentBlockBlock[agentIDs.Length];
2756 for (int i = 0; i < agentIDs.Length; i++)
2757 {
2758 OnlineNotificationPacket.AgentBlockBlock onpbl = new OnlineNotificationPacket.AgentBlockBlock();
2759 onpbl.AgentID = agentIDs[i];
2760 onpb[i] = onpbl;
2761 }
2762 onp.AgentBlock = onpb;
2763 onp.Header.Reliable = true;
2764 OutPacket(onp, ThrottleOutPacketType.Task);
2765 }
2766
2767 public void SendAgentOffline(UUID[] agentIDs)
2768 {
2769 OfflineNotificationPacket offp = new OfflineNotificationPacket();
2770 OfflineNotificationPacket.AgentBlockBlock[] offpb = new OfflineNotificationPacket.AgentBlockBlock[agentIDs.Length];
2771 for (int i = 0; i < agentIDs.Length; i++)
2772 {
2773 OfflineNotificationPacket.AgentBlockBlock onpbl = new OfflineNotificationPacket.AgentBlockBlock();
2774 onpbl.AgentID = agentIDs[i];
2775 offpb[i] = onpbl;
2776 }
2777 offp.AgentBlock = offpb;
2778 offp.Header.Reliable = true;
2779 OutPacket(offp, ThrottleOutPacketType.Task);
2780 }
2781
2782 public void SendFindAgent(UUID HunterID, UUID PreyID, double GlobalX, double GlobalY)
2783 {
2784 FindAgentPacket fap = new FindAgentPacket();
2785 fap.AgentBlock.Hunter = HunterID;
2786 fap.AgentBlock.Prey = PreyID;
2787 fap.AgentBlock.SpaceIP = 0;
2788
2789 fap.LocationBlock = new FindAgentPacket.LocationBlockBlock[1];
2790 fap.LocationBlock[0] = new FindAgentPacket.LocationBlockBlock();
2791 fap.LocationBlock[0].GlobalX = GlobalX;
2792 fap.LocationBlock[0].GlobalY = GlobalY;
2793
2794 OutPacket(fap, ThrottleOutPacketType.Task);
2795 }
2796
2797 public void SendSitResponse(UUID TargetID, Vector3 OffsetPos,
2798 Quaternion SitOrientation, bool autopilot,
2799 Vector3 CameraAtOffset, Vector3 CameraEyeOffset, bool ForceMouseLook)
2800 {
2801 AvatarSitResponsePacket avatarSitResponse = new AvatarSitResponsePacket();
2802 avatarSitResponse.SitObject.ID = TargetID;
2803 avatarSitResponse.SitTransform.CameraAtOffset = CameraAtOffset;
2804 avatarSitResponse.SitTransform.CameraEyeOffset = CameraEyeOffset;
2805 avatarSitResponse.SitTransform.ForceMouselook = ForceMouseLook;
2806 avatarSitResponse.SitTransform.AutoPilot = autopilot;
2807 avatarSitResponse.SitTransform.SitPosition = OffsetPos;
2808 avatarSitResponse.SitTransform.SitRotation = SitOrientation;
2809
2810 OutPacket(avatarSitResponse, ThrottleOutPacketType.Task);
2811 }
2812
2813 public void SendAdminResponse(UUID Token, uint AdminLevel)
2814 {
2815 GrantGodlikePowersPacket respondPacket = new GrantGodlikePowersPacket();
2816 GrantGodlikePowersPacket.GrantDataBlock gdb = new GrantGodlikePowersPacket.GrantDataBlock();
2817 GrantGodlikePowersPacket.AgentDataBlock adb = new GrantGodlikePowersPacket.AgentDataBlock();
2818
2819 adb.AgentID = AgentId;
2820 adb.SessionID = SessionId; // More security
2821 gdb.GodLevel = (byte)AdminLevel;
2822 gdb.Token = Token;
2823 //respondPacket.AgentData = (GrantGodlikePowersPacket.AgentDataBlock)ablock;
2824 respondPacket.GrantData = gdb;
2825 respondPacket.AgentData = adb;
2826 OutPacket(respondPacket, ThrottleOutPacketType.Task);
2827 }
2828
2829 public void SendGroupMembership(GroupMembershipData[] GroupMembership)
2830 {
2831
2832 UpdateGroupMembership(GroupMembership);
2833 SendAgentGroupDataUpdate(AgentId,GroupMembership);
2834 }
2835
2836 public void SendSelectedPartsProprieties(List<ISceneEntity> parts)
2837 {
2838/* not in use
2839 // udp part
2840 ObjectPropertiesPacket packet =
2841 (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties);
2842 ObjectPropertiesPacket.ObjectDataBlock[] ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[parts.Count];
2843
2844 int i = 0;
2845 foreach(SceneObjectPart sop in parts)
2846 ObjectData[i++] = CreateObjectPropertiesBlock(sop);
2847
2848 packet.ObjectData = ObjectData;
2849 packet.Header.Zerocoded = true;
2850 // udp send splits this mega packets correctly
2851 // mb later will avoid that to reduce gc stress
2852 OutPacket(packet, ThrottleOutPacketType.Task, true);
2853
2854 // caps physics part
2855 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>();
2856 if(eq == null)
2857 return;
2858
2859 OSDArray array = new OSDArray();
2860 foreach(SceneObjectPart sop in parts)
2861 {
2862 OSDMap physinfo = new OSDMap(6);
2863 physinfo["LocalID"] = sop.LocalId;
2864 physinfo["Density"] = sop.Density;
2865 physinfo["Friction"] = sop.Friction;
2866 physinfo["GravityMultiplier"] = sop.GravityModifier;
2867 physinfo["Restitution"] = sop.Restitution;
2868 physinfo["PhysicsShapeType"] = (int)sop.PhysicsShapeType;
2869 array.Add(physinfo);
2870 }
2871
2872 OSDMap llsdBody = new OSDMap(1);
2873 llsdBody.Add("ObjectData", array);
2874
2875 eq.Enqueue(BuildEvent("ObjectPhysicsProperties", llsdBody),AgentId);
2876*/
2877 }
2878
2879
2880 public void SendPartPhysicsProprieties(ISceneEntity entity)
2881 {
2882 SceneObjectPart part = (SceneObjectPart)entity;
2883 if (part != null && AgentId != UUID.Zero)
2884 {
2885 try
2886 {
2887 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>();
2888 if (eq != null)
2889 {
2890 uint localid = part.LocalId;
2891 byte physshapetype = part.PhysicsShapeType;
2892 float density = part.Density;
2893 float friction = part.Friction;
2894 float bounce = part.Restitution;
2895 float gravmod = part.GravityModifier;
2896
2897 eq.partPhysicsProperties(localid, physshapetype, density, friction, bounce, gravmod,AgentId);
2898 }
2899 }
2900 catch (Exception ex)
2901 {
2902 m_log.Error("Unable to send part Physics Proprieties - exception: " + ex.ToString());
2903 }
2904 }
2905 }
2906
2907
2908
2909 public void SendGroupNameReply(UUID groupLLUID, string GroupName)
2910 {
2911 UUIDGroupNameReplyPacket pack = new UUIDGroupNameReplyPacket();
2912 UUIDGroupNameReplyPacket.UUIDNameBlockBlock[] uidnameblock = new UUIDGroupNameReplyPacket.UUIDNameBlockBlock[1];
2913 UUIDGroupNameReplyPacket.UUIDNameBlockBlock uidnamebloc = new UUIDGroupNameReplyPacket.UUIDNameBlockBlock();
2914 uidnamebloc.ID = groupLLUID;
2915 uidnamebloc.GroupName = Util.StringToBytes256(GroupName);
2916 uidnameblock[0] = uidnamebloc;
2917 pack.UUIDNameBlock = uidnameblock;
2918 OutPacket(pack, ThrottleOutPacketType.Task);
2919 }
2920
2921 public void SendLandStatReply(uint reportType, uint requestFlags, uint resultCount, LandStatReportItem[] lsrpia)
2922 {
2923 LandStatReplyPacket lsrp = new LandStatReplyPacket();
2924 // LandStatReplyPacket.RequestDataBlock lsreqdpb = new LandStatReplyPacket.RequestDataBlock();
2925 LandStatReplyPacket.ReportDataBlock[] lsrepdba = new LandStatReplyPacket.ReportDataBlock[lsrpia.Length];
2926 //LandStatReplyPacket.ReportDataBlock lsrepdb = new LandStatReplyPacket.ReportDataBlock();
2927 // lsrepdb.
2928 lsrp.RequestData.ReportType = reportType;
2929 lsrp.RequestData.RequestFlags = requestFlags;
2930 lsrp.RequestData.TotalObjectCount = resultCount;
2931 for (int i = 0; i < lsrpia.Length; i++)
2932 {
2933 LandStatReplyPacket.ReportDataBlock lsrepdb = new LandStatReplyPacket.ReportDataBlock();
2934 lsrepdb.LocationX = lsrpia[i].LocationX;
2935 lsrepdb.LocationY = lsrpia[i].LocationY;
2936 lsrepdb.LocationZ = lsrpia[i].LocationZ;
2937 lsrepdb.Score = lsrpia[i].Score;
2938 lsrepdb.TaskID = lsrpia[i].TaskID;
2939 lsrepdb.TaskLocalID = lsrpia[i].TaskLocalID;
2940 lsrepdb.TaskName = Util.StringToBytes256(lsrpia[i].TaskName);
2941 lsrepdb.OwnerName = Util.StringToBytes256(lsrpia[i].OwnerName);
2942 lsrepdba[i] = lsrepdb;
2943 }
2944 lsrp.ReportData = lsrepdba;
2945 OutPacket(lsrp, ThrottleOutPacketType.Task);
2946 }
2947
2948 public void SendScriptRunningReply(UUID objectID, UUID itemID, bool running)
2949 {
2950 ScriptRunningReplyPacket scriptRunningReply = new ScriptRunningReplyPacket();
2951 scriptRunningReply.Script.ObjectID = objectID;
2952 scriptRunningReply.Script.ItemID = itemID;
2953 scriptRunningReply.Script.Running = running;
2954
2955 OutPacket(scriptRunningReply, ThrottleOutPacketType.Task);
2956 }
2957
2958 public void SendAsset(AssetRequestToClient req)
2959 {
2960 if (req.AssetInf == null)
2961 {
2962 m_log.ErrorFormat("{0} Cannot send asset {1} ({2}), asset is null",
2963 LogHeader);
2964 return;
2965 }
2966
2967 if (req.AssetInf.Data == null)
2968 {
2969 m_log.ErrorFormat("{0} Cannot send asset {1} ({2}), asset data is null",
2970 LogHeader, req.AssetInf.ID, req.AssetInf.Metadata.ContentType);
2971 return;
2972 }
2973
2974 bool isWearable = false;
2975
2976 isWearable = ((AssetType) req.AssetInf.Type ==
2977 AssetType.Bodypart || (AssetType) req.AssetInf.Type == AssetType.Clothing);
2978
2979
2980 //m_log.Debug("sending asset " + req.RequestAssetID + ", iswearable: " + isWearable);
2981
2982
2983 //if (isWearable)
2984 // m_log.Debug((AssetType)req.AssetInf.Type);
2985
2986 TransferInfoPacket Transfer = new TransferInfoPacket();
2987 Transfer.TransferInfo.ChannelType = 2;
2988 Transfer.TransferInfo.Status = 0;
2989 Transfer.TransferInfo.TargetType = 0;
2990 if (req.AssetRequestSource == 2)
2991 {
2992 Transfer.TransferInfo.Params = new byte[20];
2993 Array.Copy(req.RequestAssetID.GetBytes(), 0, Transfer.TransferInfo.Params, 0, 16);
2994 int assType = req.AssetInf.Type;
2995 Array.Copy(Utils.IntToBytes(assType), 0, Transfer.TransferInfo.Params, 16, 4);
2996 }
2997 else if (req.AssetRequestSource == 3)
2998 {
2999 Transfer.TransferInfo.Params = req.Params;
3000 // Transfer.TransferInfo.Params = new byte[100];
3001 //Array.Copy(req.RequestUser.AgentId.GetBytes(), 0, Transfer.TransferInfo.Params, 0, 16);
3002 //Array.Copy(req.RequestUser.SessionId.GetBytes(), 0, Transfer.TransferInfo.Params, 16, 16);
3003 }
3004 Transfer.TransferInfo.Size = req.AssetInf.Data.Length;
3005 Transfer.TransferInfo.TransferID = req.TransferRequestID;
3006 Transfer.Header.Zerocoded = true;
3007 OutPacket(Transfer, isWearable ? ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority : ThrottleOutPacketType.Asset);
3008
3009 if (req.NumPackets == 1)
3010 {
3011 TransferPacketPacket TransferPacket = new TransferPacketPacket();
3012 TransferPacket.TransferData.Packet = 0;
3013 TransferPacket.TransferData.ChannelType = 2;
3014 TransferPacket.TransferData.TransferID = req.TransferRequestID;
3015 TransferPacket.TransferData.Data = req.AssetInf.Data;
3016 TransferPacket.TransferData.Status = 1;
3017 TransferPacket.Header.Zerocoded = true;
3018 OutPacket(TransferPacket, isWearable ? ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority : ThrottleOutPacketType.Asset);
3019 }
3020 else
3021 {
3022 int processedLength = 0;
3023// int maxChunkSize = Settings.MAX_PACKET_SIZE - 100;
3024
3025 int maxChunkSize = (int) MaxTransferBytesPerPacket;
3026 int packetNumber = 0;
3027
3028 while (processedLength < req.AssetInf.Data.Length)
3029 {
3030 TransferPacketPacket TransferPacket = new TransferPacketPacket();
3031 TransferPacket.TransferData.Packet = packetNumber;
3032 TransferPacket.TransferData.ChannelType = 2;
3033 TransferPacket.TransferData.TransferID = req.TransferRequestID;
3034
3035 int chunkSize = Math.Min(req.AssetInf.Data.Length - processedLength, maxChunkSize);
3036 byte[] chunk = new byte[chunkSize];
3037 Array.Copy(req.AssetInf.Data, processedLength, chunk, 0, chunk.Length);
3038
3039 TransferPacket.TransferData.Data = chunk;
3040
3041 // 0 indicates more packets to come, 1 indicates last packet
3042 if (req.AssetInf.Data.Length - processedLength > maxChunkSize)
3043 {
3044 TransferPacket.TransferData.Status = 0;
3045 }
3046 else
3047 {
3048 TransferPacket.TransferData.Status = 1;
3049 }
3050 TransferPacket.Header.Zerocoded = true;
3051 OutPacket(TransferPacket, isWearable ? ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority : ThrottleOutPacketType.Asset);
3052
3053 processedLength += chunkSize;
3054 packetNumber++;
3055 }
3056 }
3057 }
3058
3059 public void SendAssetNotFound(AssetRequestToClient req)
3060 {
3061 TransferInfoPacket Transfer = new TransferInfoPacket();
3062 Transfer.TransferInfo.ChannelType = 2;
3063 Transfer.TransferInfo.Status = -2;
3064 Transfer.TransferInfo.TargetType = 0;
3065 Transfer.TransferInfo.Params = req.Params;
3066 Transfer.TransferInfo.Size = 0;
3067 Transfer.TransferInfo.TransferID = req.TransferRequestID;
3068 Transfer.Header.Zerocoded = true;
3069 OutPacket(Transfer, ThrottleOutPacketType.Asset);
3070 }
3071
3072 public void SendTexture(AssetBase TextureAsset)
3073 {
3074
3075 }
3076
3077 public void SendRegionHandle(UUID regionID, ulong handle)
3078 {
3079 RegionIDAndHandleReplyPacket reply = (RegionIDAndHandleReplyPacket)PacketPool.Instance.GetPacket(PacketType.RegionIDAndHandleReply);
3080 reply.ReplyBlock.RegionID = regionID;
3081 reply.ReplyBlock.RegionHandle = handle;
3082 OutPacket(reply, ThrottleOutPacketType.Land);
3083 }
3084
3085 public void SendParcelInfo(RegionInfo info, LandData land, UUID parcelID, uint x, uint y)
3086 {
3087 ParcelInfoReplyPacket reply = (ParcelInfoReplyPacket)PacketPool.Instance.GetPacket(PacketType.ParcelInfoReply);
3088 reply.AgentData.AgentID = m_agentId;
3089 reply.Data.ParcelID = parcelID;
3090 reply.Data.OwnerID = land.OwnerID;
3091 reply.Data.Name = Utils.StringToBytes(land.Name);
3092 if (land.Description != null && land.Description != String.Empty)
3093 reply.Data.Desc = Utils.StringToBytes(land.Description.Substring(0, land.Description.Length > 254 ? 254: land.Description.Length));
3094 else
3095 reply.Data.Desc = new Byte[0];
3096 reply.Data.ActualArea = land.Area;
3097 reply.Data.BillableArea = land.Area; // TODO: what is this?
3098
3099 reply.Data.Flags = (byte)Util.ConvertAccessLevelToMaturity((byte)info.AccessLevel);
3100 if((land.Flags & (uint)ParcelFlags.ForSale) != 0)
3101 reply.Data.Flags |= (byte)((1 << 7));
3102
3103 Vector3 pos = land.UserLocation;
3104 if (pos.Equals(Vector3.Zero))
3105 {
3106 pos = (land.AABBMax + land.AABBMin) * 0.5f;
3107 }
3108 reply.Data.GlobalX = info.RegionLocX + x;
3109 reply.Data.GlobalY = info.RegionLocY + y;
3110 reply.Data.GlobalZ = pos.Z;
3111 reply.Data.SimName = Utils.StringToBytes(info.RegionName);
3112 reply.Data.SnapshotID = land.SnapshotID;
3113 reply.Data.Dwell = land.Dwell;
3114 reply.Data.SalePrice = land.SalePrice;
3115 reply.Data.AuctionID = (int)land.AuctionID;
3116
3117 OutPacket(reply, ThrottleOutPacketType.Land);
3118 }
3119
3120 public void SendScriptTeleportRequest(string objName, string simName, Vector3 pos, Vector3 lookAt)
3121 {
3122 ScriptTeleportRequestPacket packet = (ScriptTeleportRequestPacket)PacketPool.Instance.GetPacket(PacketType.ScriptTeleportRequest);
3123
3124 packet.Data.ObjectName = Utils.StringToBytes(objName);
3125 packet.Data.SimName = Utils.StringToBytes(simName);
3126 packet.Data.SimPosition = pos;
3127 packet.Data.LookAt = lookAt;
3128
3129 OutPacket(packet, ThrottleOutPacketType.Task);
3130 }
3131
3132 public void SendDirPlacesReply(UUID queryID, DirPlacesReplyData[] data)
3133 {
3134 DirPlacesReplyPacket packet = (DirPlacesReplyPacket)PacketPool.Instance.GetPacket(PacketType.DirPlacesReply);
3135
3136 packet.AgentData = new DirPlacesReplyPacket.AgentDataBlock();
3137
3138 packet.QueryData = new DirPlacesReplyPacket.QueryDataBlock[1];
3139 packet.QueryData[0] = new DirPlacesReplyPacket.QueryDataBlock();
3140
3141 packet.AgentData.AgentID = AgentId;
3142
3143 packet.QueryData[0].QueryID = queryID;
3144
3145 DirPlacesReplyPacket.QueryRepliesBlock[] replies =
3146 new DirPlacesReplyPacket.QueryRepliesBlock[0];
3147 DirPlacesReplyPacket.StatusDataBlock[] status =
3148 new DirPlacesReplyPacket.StatusDataBlock[0];
3149
3150 packet.QueryReplies = replies;
3151 packet.StatusData = status;
3152
3153 foreach (DirPlacesReplyData d in data)
3154 {
3155 int idx = replies.Length;
3156 Array.Resize(ref replies, idx + 1);
3157 Array.Resize(ref status, idx + 1);
3158
3159 replies[idx] = new DirPlacesReplyPacket.QueryRepliesBlock();
3160 status[idx] = new DirPlacesReplyPacket.StatusDataBlock();
3161 replies[idx].ParcelID = d.parcelID;
3162 replies[idx].Name = Utils.StringToBytes(d.name);
3163 replies[idx].ForSale = d.forSale;
3164 replies[idx].Auction = d.auction;
3165 replies[idx].Dwell = d.dwell;
3166 status[idx].Status = d.Status;
3167
3168 packet.QueryReplies = replies;
3169 packet.StatusData = status;
3170
3171 if (packet.Length >= 1000)
3172 {
3173 OutPacket(packet, ThrottleOutPacketType.Task);
3174
3175 packet = (DirPlacesReplyPacket)PacketPool.Instance.GetPacket(PacketType.DirPlacesReply);
3176
3177 packet.AgentData = new DirPlacesReplyPacket.AgentDataBlock();
3178
3179 packet.QueryData = new DirPlacesReplyPacket.QueryDataBlock[1];
3180 packet.QueryData[0] = new DirPlacesReplyPacket.QueryDataBlock();
3181
3182 packet.AgentData.AgentID = AgentId;
3183
3184 packet.QueryData[0].QueryID = queryID;
3185
3186 replies = new DirPlacesReplyPacket.QueryRepliesBlock[0];
3187 status = new DirPlacesReplyPacket.StatusDataBlock[0];
3188 }
3189 }
3190
3191 if (replies.Length > 0 || data.Length == 0)
3192 OutPacket(packet, ThrottleOutPacketType.Task);
3193 }
3194
3195 public void SendDirPeopleReply(UUID queryID, DirPeopleReplyData[] data)
3196 {
3197 DirPeopleReplyPacket packet = (DirPeopleReplyPacket)PacketPool.Instance.GetPacket(PacketType.DirPeopleReply);
3198
3199 packet.AgentData = new DirPeopleReplyPacket.AgentDataBlock();
3200 packet.AgentData.AgentID = AgentId;
3201
3202 packet.QueryData = new DirPeopleReplyPacket.QueryDataBlock();
3203 packet.QueryData.QueryID = queryID;
3204
3205 packet.QueryReplies = new DirPeopleReplyPacket.QueryRepliesBlock[
3206 data.Length];
3207
3208 int i = 0;
3209 foreach (DirPeopleReplyData d in data)
3210 {
3211 packet.QueryReplies[i] = new DirPeopleReplyPacket.QueryRepliesBlock();
3212 packet.QueryReplies[i].AgentID = d.agentID;
3213 packet.QueryReplies[i].FirstName =
3214 Utils.StringToBytes(d.firstName);
3215 packet.QueryReplies[i].LastName =
3216 Utils.StringToBytes(d.lastName);
3217 packet.QueryReplies[i].Group =
3218 Utils.StringToBytes(d.group);
3219 packet.QueryReplies[i].Online = d.online;
3220 packet.QueryReplies[i].Reputation = d.reputation;
3221 i++;
3222 }
3223
3224 OutPacket(packet, ThrottleOutPacketType.Task);
3225 }
3226
3227 public void SendDirEventsReply(UUID queryID, DirEventsReplyData[] data)
3228 {
3229 DirEventsReplyPacket packet = (DirEventsReplyPacket)PacketPool.Instance.GetPacket(PacketType.DirEventsReply);
3230
3231 packet.AgentData = new DirEventsReplyPacket.AgentDataBlock();
3232 packet.AgentData.AgentID = AgentId;
3233
3234 packet.QueryData = new DirEventsReplyPacket.QueryDataBlock();
3235 packet.QueryData.QueryID = queryID;
3236
3237 packet.QueryReplies = new DirEventsReplyPacket.QueryRepliesBlock[
3238 data.Length];
3239
3240 packet.StatusData = new DirEventsReplyPacket.StatusDataBlock[
3241 data.Length];
3242
3243 int i = 0;
3244 foreach (DirEventsReplyData d in data)
3245 {
3246 packet.QueryReplies[i] = new DirEventsReplyPacket.QueryRepliesBlock();
3247 packet.StatusData[i] = new DirEventsReplyPacket.StatusDataBlock();
3248 packet.QueryReplies[i].OwnerID = d.ownerID;
3249 packet.QueryReplies[i].Name =
3250 Utils.StringToBytes(d.name);
3251 packet.QueryReplies[i].EventID = d.eventID;
3252 packet.QueryReplies[i].Date =
3253 Utils.StringToBytes(d.date);
3254 packet.QueryReplies[i].UnixTime = d.unixTime;
3255 packet.QueryReplies[i].EventFlags = d.eventFlags;
3256 packet.StatusData[i].Status = d.Status;
3257 i++;
3258 }
3259
3260 OutPacket(packet, ThrottleOutPacketType.Task);
3261 }
3262
3263 public void SendDirGroupsReply(UUID queryID, DirGroupsReplyData[] data)
3264 {
3265 DirGroupsReplyPacket packet = (DirGroupsReplyPacket)PacketPool.Instance.GetPacket(PacketType.DirGroupsReply);
3266
3267 packet.AgentData = new DirGroupsReplyPacket.AgentDataBlock();
3268 packet.AgentData.AgentID = AgentId;
3269
3270 packet.QueryData = new DirGroupsReplyPacket.QueryDataBlock();
3271 packet.QueryData.QueryID = queryID;
3272
3273 packet.QueryReplies = new DirGroupsReplyPacket.QueryRepliesBlock[
3274 data.Length];
3275
3276 int i = 0;
3277 foreach (DirGroupsReplyData d in data)
3278 {
3279 packet.QueryReplies[i] = new DirGroupsReplyPacket.QueryRepliesBlock();
3280 packet.QueryReplies[i].GroupID = d.groupID;
3281 packet.QueryReplies[i].GroupName =
3282 Utils.StringToBytes(d.groupName);
3283 packet.QueryReplies[i].Members = d.members;
3284 packet.QueryReplies[i].SearchOrder = d.searchOrder;
3285 i++;
3286 }
3287
3288 OutPacket(packet, ThrottleOutPacketType.Task);
3289 }
3290
3291 public void SendDirClassifiedReply(UUID queryID, DirClassifiedReplyData[] data)
3292 {
3293 DirClassifiedReplyPacket packet = (DirClassifiedReplyPacket)PacketPool.Instance.GetPacket(PacketType.DirClassifiedReply);
3294
3295 packet.AgentData = new DirClassifiedReplyPacket.AgentDataBlock();
3296 packet.AgentData.AgentID = AgentId;
3297
3298 packet.QueryData = new DirClassifiedReplyPacket.QueryDataBlock();
3299 packet.QueryData.QueryID = queryID;
3300
3301 packet.QueryReplies = new DirClassifiedReplyPacket.QueryRepliesBlock[
3302 data.Length];
3303 packet.StatusData = new DirClassifiedReplyPacket.StatusDataBlock[
3304 data.Length];
3305
3306 int i = 0;
3307 foreach (DirClassifiedReplyData d in data)
3308 {
3309 packet.QueryReplies[i] = new DirClassifiedReplyPacket.QueryRepliesBlock();
3310 packet.StatusData[i] = new DirClassifiedReplyPacket.StatusDataBlock();
3311 packet.QueryReplies[i].ClassifiedID = d.classifiedID;
3312 packet.QueryReplies[i].Name =
3313 Utils.StringToBytes(d.name);
3314 packet.QueryReplies[i].ClassifiedFlags = d.classifiedFlags;
3315 packet.QueryReplies[i].CreationDate = d.creationDate;
3316 packet.QueryReplies[i].ExpirationDate = d.expirationDate;
3317 packet.QueryReplies[i].PriceForListing = d.price;
3318 packet.StatusData[i].Status = d.Status;
3319 i++;
3320 }
3321
3322 OutPacket(packet, ThrottleOutPacketType.Task);
3323 }
3324
3325 public void SendDirLandReply(UUID queryID, DirLandReplyData[] data)
3326 {
3327 DirLandReplyPacket packet = (DirLandReplyPacket)PacketPool.Instance.GetPacket(PacketType.DirLandReply);
3328
3329 packet.AgentData = new DirLandReplyPacket.AgentDataBlock();
3330 packet.AgentData.AgentID = AgentId;
3331
3332 packet.QueryData = new DirLandReplyPacket.QueryDataBlock();
3333 packet.QueryData.QueryID = queryID;
3334
3335 packet.QueryReplies = new DirLandReplyPacket.QueryRepliesBlock[
3336 data.Length];
3337
3338 int i = 0;
3339 foreach (DirLandReplyData d in data)
3340 {
3341 packet.QueryReplies[i] = new DirLandReplyPacket.QueryRepliesBlock();
3342 packet.QueryReplies[i].ParcelID = d.parcelID;
3343 packet.QueryReplies[i].Name =
3344 Utils.StringToBytes(d.name);
3345 packet.QueryReplies[i].Auction = d.auction;
3346 packet.QueryReplies[i].ForSale = d.forSale;
3347 packet.QueryReplies[i].SalePrice = d.salePrice;
3348 packet.QueryReplies[i].ActualArea = d.actualArea;
3349 i++;
3350 }
3351
3352 OutPacket(packet, ThrottleOutPacketType.Task);
3353 }
3354
3355 public void SendDirPopularReply(UUID queryID, DirPopularReplyData[] data)
3356 {
3357 DirPopularReplyPacket packet = (DirPopularReplyPacket)PacketPool.Instance.GetPacket(PacketType.DirPopularReply);
3358
3359 packet.AgentData = new DirPopularReplyPacket.AgentDataBlock();
3360 packet.AgentData.AgentID = AgentId;
3361
3362 packet.QueryData = new DirPopularReplyPacket.QueryDataBlock();
3363 packet.QueryData.QueryID = queryID;
3364
3365 packet.QueryReplies = new DirPopularReplyPacket.QueryRepliesBlock[
3366 data.Length];
3367
3368 int i = 0;
3369 foreach (DirPopularReplyData d in data)
3370 {
3371 packet.QueryReplies[i] = new DirPopularReplyPacket.QueryRepliesBlock();
3372 packet.QueryReplies[i].ParcelID = d.parcelID;
3373 packet.QueryReplies[i].Name =
3374 Utils.StringToBytes(d.name);
3375 packet.QueryReplies[i].Dwell = d.dwell;
3376 i++;
3377 }
3378
3379 OutPacket(packet, ThrottleOutPacketType.Task);
3380 }
3381
3382 public void SendEventInfoReply(EventData data)
3383 {
3384 EventInfoReplyPacket packet = (EventInfoReplyPacket)PacketPool.Instance.GetPacket(PacketType.EventInfoReply);
3385
3386 packet.AgentData = new EventInfoReplyPacket.AgentDataBlock();
3387 packet.AgentData.AgentID = AgentId;
3388
3389 packet.EventData = new EventInfoReplyPacket.EventDataBlock();
3390 packet.EventData.EventID = data.eventID;
3391 packet.EventData.Creator = Utils.StringToBytes(data.creator);
3392 packet.EventData.Name = Utils.StringToBytes(data.name);
3393 packet.EventData.Category = Utils.StringToBytes(data.category);
3394 packet.EventData.Desc = Utils.StringToBytes(data.description);
3395 packet.EventData.Date = Utils.StringToBytes(data.date);
3396 packet.EventData.DateUTC = data.dateUTC;
3397 packet.EventData.Duration = data.duration;
3398 packet.EventData.Cover = data.cover;
3399 packet.EventData.Amount = data.amount;
3400 packet.EventData.SimName = Utils.StringToBytes(data.simName);
3401 packet.EventData.GlobalPos = new Vector3d(data.globalPos);
3402 packet.EventData.EventFlags = data.eventFlags;
3403
3404 OutPacket(packet, ThrottleOutPacketType.Task);
3405 }
3406
3407 public void SendMapItemReply(mapItemReply[] replies, uint mapitemtype, uint flags)
3408 {
3409 MapItemReplyPacket mirplk = new MapItemReplyPacket();
3410 mirplk.AgentData.AgentID = AgentId;
3411 mirplk.RequestData.ItemType = mapitemtype;
3412 mirplk.Data = new MapItemReplyPacket.DataBlock[replies.Length];
3413 for (int i = 0; i < replies.Length; i++)
3414 {
3415 MapItemReplyPacket.DataBlock mrdata = new MapItemReplyPacket.DataBlock();
3416 mrdata.X = replies[i].x;
3417 mrdata.Y = replies[i].y;
3418 mrdata.ID = replies[i].id;
3419 mrdata.Extra = replies[i].Extra;
3420 mrdata.Extra2 = replies[i].Extra2;
3421 mrdata.Name = Utils.StringToBytes(replies[i].name);
3422 mirplk.Data[i] = mrdata;
3423 }
3424 //m_log.Debug(mirplk.ToString());
3425 OutPacket(mirplk, ThrottleOutPacketType.Task);
3426
3427 }
3428
3429 public void SendOfferCallingCard(UUID srcID, UUID transactionID)
3430 {
3431 // a bit special, as this uses AgentID to store the source instead
3432 // of the destination. The destination (the receiver) goes into destID
3433 OfferCallingCardPacket p = (OfferCallingCardPacket)PacketPool.Instance.GetPacket(PacketType.OfferCallingCard);
3434 p.AgentData.AgentID = srcID;
3435 p.AgentData.SessionID = UUID.Zero;
3436 p.AgentBlock.DestID = AgentId;
3437 p.AgentBlock.TransactionID = transactionID;
3438 OutPacket(p, ThrottleOutPacketType.Task);
3439 }
3440
3441 public void SendAcceptCallingCard(UUID transactionID)
3442 {
3443 AcceptCallingCardPacket p = (AcceptCallingCardPacket)PacketPool.Instance.GetPacket(PacketType.AcceptCallingCard);
3444 p.AgentData.AgentID = AgentId;
3445 p.AgentData.SessionID = UUID.Zero;
3446 p.FolderData = new AcceptCallingCardPacket.FolderDataBlock[1];
3447 p.FolderData[0] = new AcceptCallingCardPacket.FolderDataBlock();
3448 p.FolderData[0].FolderID = UUID.Zero;
3449 OutPacket(p, ThrottleOutPacketType.Task);
3450 }
3451
3452 public void SendDeclineCallingCard(UUID transactionID)
3453 {
3454 DeclineCallingCardPacket p = (DeclineCallingCardPacket)PacketPool.Instance.GetPacket(PacketType.DeclineCallingCard);
3455 p.AgentData.AgentID = AgentId;
3456 p.AgentData.SessionID = UUID.Zero;
3457 p.TransactionBlock.TransactionID = transactionID;
3458 OutPacket(p, ThrottleOutPacketType.Task);
3459 }
3460
3461 public void SendTerminateFriend(UUID exFriendID)
3462 {
3463 TerminateFriendshipPacket p = (TerminateFriendshipPacket)PacketPool.Instance.GetPacket(PacketType.TerminateFriendship);
3464 p.AgentData.AgentID = AgentId;
3465 p.AgentData.SessionID = SessionId;
3466 p.ExBlock.OtherID = exFriendID;
3467 OutPacket(p, ThrottleOutPacketType.Task);
3468 }
3469
3470 public void SendAvatarGroupsReply(UUID avatarID, GroupMembershipData[] data)
3471 {
3472 OSDMap llsd = new OSDMap(3);
3473 OSDArray AgentData = new OSDArray(1);
3474 OSDMap AgentDataMap = new OSDMap(1);
3475 AgentDataMap.Add("AgentID", OSD.FromUUID(this.AgentId));
3476 AgentDataMap.Add("AvatarID", OSD.FromUUID(avatarID));
3477 AgentData.Add(AgentDataMap);
3478 llsd.Add("AgentData", AgentData);
3479 OSDArray GroupData = new OSDArray(data.Length);
3480// OSDArray NewGroupData = new OSDArray(data.Length);
3481 foreach (GroupMembershipData m in data)
3482 {
3483 OSDMap GroupDataMap = new OSDMap(6);
3484 OSDMap NewGroupDataMap = new OSDMap(1);
3485 GroupDataMap.Add("GroupPowers", OSD.FromULong(m.GroupPowers));
3486 GroupDataMap.Add("AcceptNotices", OSD.FromBoolean(m.AcceptNotices));
3487 GroupDataMap.Add("GroupTitle", OSD.FromString(m.GroupTitle));
3488 GroupDataMap.Add("GroupID", OSD.FromUUID(m.GroupID));
3489 GroupDataMap.Add("GroupName", OSD.FromString(m.GroupName));
3490 GroupDataMap.Add("GroupInsigniaID", OSD.FromUUID(m.GroupPicture));
3491// NewGroupDataMap.Add("ListInProfile", OSD.FromBoolean(m.ListInProfile));
3492 GroupData.Add(GroupDataMap);
3493// NewGroupData.Add(NewGroupDataMap);
3494 }
3495 llsd.Add("GroupData", GroupData);
3496 // llsd.Add("NewGroupData", NewGroupData);
3497
3498 IEventQueue eq = this.Scene.RequestModuleInterface<IEventQueue>();
3499 if (eq != null)
3500 {
3501 eq.Enqueue(BuildEvent("AvatarGroupsReply", llsd), this.AgentId);
3502 }
3503 }
3504
3505 public void SendAgentGroupDataUpdate(UUID avatarID, GroupMembershipData[] data)
3506 {
3507 if(avatarID != AgentId)
3508 m_log.Debug("[CLIENT]: SendAgentGroupDataUpdate avatarID != AgentId");
3509
3510 IEventQueue eq = this.Scene.RequestModuleInterface<IEventQueue>();
3511 if(eq != null)
3512 {
3513 eq.GroupMembershipData(avatarID,data);
3514 }
3515 else
3516 {
3517 // use UDP if no caps
3518 AgentGroupDataUpdatePacket Groupupdate = new AgentGroupDataUpdatePacket();
3519 AgentGroupDataUpdatePacket.GroupDataBlock[] Groups = new AgentGroupDataUpdatePacket.GroupDataBlock[data.Length];
3520 for (int i = 0; i < data.Length; i++)
3521 {
3522 AgentGroupDataUpdatePacket.GroupDataBlock Group = new AgentGroupDataUpdatePacket.GroupDataBlock();
3523 Group.AcceptNotices = data[i].AcceptNotices;
3524 Group.Contribution = data[i].Contribution;
3525 Group.GroupID = data[i].GroupID;
3526 Group.GroupInsigniaID = data[i].GroupPicture;
3527 Group.GroupName = Util.StringToBytes256(data[i].GroupName);
3528 Group.GroupPowers = data[i].GroupPowers;
3529 Groups[i] = Group;
3530 }
3531 Groupupdate.GroupData = Groups;
3532 Groupupdate.AgentData = new AgentGroupDataUpdatePacket.AgentDataBlock();
3533 Groupupdate.AgentData.AgentID = avatarID;
3534 OutPacket(Groupupdate, ThrottleOutPacketType.Task);
3535 }
3536 }
3537
3538 public void SendJoinGroupReply(UUID groupID, bool success)
3539 {
3540 JoinGroupReplyPacket p = (JoinGroupReplyPacket)PacketPool.Instance.GetPacket(PacketType.JoinGroupReply);
3541
3542 p.AgentData = new JoinGroupReplyPacket.AgentDataBlock();
3543 p.AgentData.AgentID = AgentId;
3544
3545 p.GroupData = new JoinGroupReplyPacket.GroupDataBlock();
3546 p.GroupData.GroupID = groupID;
3547 p.GroupData.Success = success;
3548
3549 OutPacket(p, ThrottleOutPacketType.Task);
3550 }
3551
3552 public void SendEjectGroupMemberReply(UUID agentID, UUID groupID, bool success)
3553 {
3554 EjectGroupMemberReplyPacket p = (EjectGroupMemberReplyPacket)PacketPool.Instance.GetPacket(PacketType.EjectGroupMemberReply);
3555
3556 p.AgentData = new EjectGroupMemberReplyPacket.AgentDataBlock();
3557 p.AgentData.AgentID = agentID;
3558
3559 p.GroupData = new EjectGroupMemberReplyPacket.GroupDataBlock();
3560 p.GroupData.GroupID = groupID;
3561
3562 p.EjectData = new EjectGroupMemberReplyPacket.EjectDataBlock();
3563 p.EjectData.Success = success;
3564
3565 OutPacket(p, ThrottleOutPacketType.Task);
3566 }
3567
3568 public void SendLeaveGroupReply(UUID groupID, bool success)
3569 {
3570 LeaveGroupReplyPacket p = (LeaveGroupReplyPacket)PacketPool.Instance.GetPacket(PacketType.LeaveGroupReply);
3571
3572 p.AgentData = new LeaveGroupReplyPacket.AgentDataBlock();
3573 p.AgentData.AgentID = AgentId;
3574
3575 p.GroupData = new LeaveGroupReplyPacket.GroupDataBlock();
3576 p.GroupData.GroupID = groupID;
3577 p.GroupData.Success = success;
3578
3579 OutPacket(p, ThrottleOutPacketType.Task);
3580 }
3581
3582 public void SendAvatarClassifiedReply(UUID targetID, UUID[] classifiedID, string[] name)
3583 {
3584 if (classifiedID.Length != name.Length)
3585 return;
3586
3587 AvatarClassifiedReplyPacket ac =
3588 (AvatarClassifiedReplyPacket)PacketPool.Instance.GetPacket(
3589 PacketType.AvatarClassifiedReply);
3590
3591 ac.AgentData = new AvatarClassifiedReplyPacket.AgentDataBlock();
3592 ac.AgentData.AgentID = AgentId;
3593 ac.AgentData.TargetID = targetID;
3594
3595 ac.Data = new AvatarClassifiedReplyPacket.DataBlock[classifiedID.Length];
3596 int i;
3597 for (i = 0; i < classifiedID.Length; i++)
3598 {
3599 ac.Data[i].ClassifiedID = classifiedID[i];
3600 ac.Data[i].Name = Utils.StringToBytes(name[i]);
3601 }
3602
3603 OutPacket(ac, ThrottleOutPacketType.Task);
3604 }
3605
3606 public void SendClassifiedInfoReply(UUID classifiedID, UUID creatorID, uint creationDate, uint expirationDate, uint category, string name, string description, UUID parcelID, uint parentEstate, UUID snapshotID, string simName, Vector3 globalPos, string parcelName, byte classifiedFlags, int price)
3607 {
3608 ClassifiedInfoReplyPacket cr =
3609 (ClassifiedInfoReplyPacket)PacketPool.Instance.GetPacket(
3610 PacketType.ClassifiedInfoReply);
3611
3612 cr.AgentData = new ClassifiedInfoReplyPacket.AgentDataBlock();
3613 cr.AgentData.AgentID = AgentId;
3614
3615 cr.Data = new ClassifiedInfoReplyPacket.DataBlock();
3616 cr.Data.ClassifiedID = classifiedID;
3617 cr.Data.CreatorID = creatorID;
3618 cr.Data.CreationDate = creationDate;
3619 cr.Data.ExpirationDate = expirationDate;
3620 cr.Data.Category = category;
3621 cr.Data.Name = Utils.StringToBytes(name);
3622 cr.Data.Desc = Utils.StringToBytes(description);
3623 cr.Data.ParcelID = parcelID;
3624 cr.Data.ParentEstate = parentEstate;
3625 cr.Data.SnapshotID = snapshotID;
3626 cr.Data.SimName = Utils.StringToBytes(simName);
3627 cr.Data.PosGlobal = new Vector3d(globalPos);
3628 cr.Data.ParcelName = Utils.StringToBytes(parcelName);
3629 cr.Data.ClassifiedFlags = classifiedFlags;
3630 cr.Data.PriceForListing = price;
3631
3632 OutPacket(cr, ThrottleOutPacketType.Task);
3633 }
3634
3635 public void SendAgentDropGroup(UUID groupID)
3636 {
3637 AgentDropGroupPacket dg =
3638 (AgentDropGroupPacket)PacketPool.Instance.GetPacket(
3639 PacketType.AgentDropGroup);
3640
3641 dg.AgentData = new AgentDropGroupPacket.AgentDataBlock();
3642 dg.AgentData.AgentID = AgentId;
3643 dg.AgentData.GroupID = groupID;
3644
3645 OutPacket(dg, ThrottleOutPacketType.Task);
3646 }
3647
3648 public void SendAvatarNotesReply(UUID targetID, string text)
3649 {
3650 AvatarNotesReplyPacket an =
3651 (AvatarNotesReplyPacket)PacketPool.Instance.GetPacket(
3652 PacketType.AvatarNotesReply);
3653
3654 an.AgentData = new AvatarNotesReplyPacket.AgentDataBlock();
3655 an.AgentData.AgentID = AgentId;
3656
3657 an.Data = new AvatarNotesReplyPacket.DataBlock();
3658 an.Data.TargetID = targetID;
3659 an.Data.Notes = Utils.StringToBytes(text);
3660
3661 OutPacket(an, ThrottleOutPacketType.Task);
3662 }
3663
3664 public void SendAvatarPicksReply(UUID targetID, Dictionary<UUID, string> picks)
3665 {
3666 AvatarPicksReplyPacket ap =
3667 (AvatarPicksReplyPacket)PacketPool.Instance.GetPacket(
3668 PacketType.AvatarPicksReply);
3669
3670 ap.AgentData = new AvatarPicksReplyPacket.AgentDataBlock();
3671 ap.AgentData.AgentID = AgentId;
3672 ap.AgentData.TargetID = targetID;
3673
3674 ap.Data = new AvatarPicksReplyPacket.DataBlock[picks.Count];
3675
3676 int i = 0;
3677 foreach (KeyValuePair<UUID, string> pick in picks)
3678 {
3679 ap.Data[i] = new AvatarPicksReplyPacket.DataBlock();
3680 ap.Data[i].PickID = pick.Key;
3681 ap.Data[i].PickName = Utils.StringToBytes(pick.Value);
3682 i++;
3683 }
3684
3685 OutPacket(ap, ThrottleOutPacketType.Task);
3686 }
3687
3688 public void SendAvatarClassifiedReply(UUID targetID, Dictionary<UUID, string> classifieds)
3689 {
3690 AvatarClassifiedReplyPacket ac =
3691 (AvatarClassifiedReplyPacket)PacketPool.Instance.GetPacket(
3692 PacketType.AvatarClassifiedReply);
3693
3694 ac.AgentData = new AvatarClassifiedReplyPacket.AgentDataBlock();
3695 ac.AgentData.AgentID = AgentId;
3696 ac.AgentData.TargetID = targetID;
3697
3698 ac.Data = new AvatarClassifiedReplyPacket.DataBlock[classifieds.Count];
3699
3700 int i = 0;
3701 foreach (KeyValuePair<UUID, string> classified in classifieds)
3702 {
3703 ac.Data[i] = new AvatarClassifiedReplyPacket.DataBlock();
3704 ac.Data[i].ClassifiedID = classified.Key;
3705 ac.Data[i].Name = Utils.StringToBytes(classified.Value);
3706 i++;
3707 }
3708
3709 OutPacket(ac, ThrottleOutPacketType.Task);
3710 }
3711
3712 public void SendParcelDwellReply(int localID, UUID parcelID, float dwell)
3713 {
3714 ParcelDwellReplyPacket pd =
3715 (ParcelDwellReplyPacket)PacketPool.Instance.GetPacket(
3716 PacketType.ParcelDwellReply);
3717
3718 pd.AgentData = new ParcelDwellReplyPacket.AgentDataBlock();
3719 pd.AgentData.AgentID = AgentId;
3720
3721 pd.Data = new ParcelDwellReplyPacket.DataBlock();
3722 pd.Data.LocalID = localID;
3723 pd.Data.ParcelID = parcelID;
3724 pd.Data.Dwell = dwell;
3725
3726 OutPacket(pd, ThrottleOutPacketType.Land);
3727 }
3728
3729 public void SendUserInfoReply(bool imViaEmail, bool visible, string email)
3730 {
3731 UserInfoReplyPacket ur =
3732 (UserInfoReplyPacket)PacketPool.Instance.GetPacket(
3733 PacketType.UserInfoReply);
3734
3735 string Visible = "hidden";
3736 if (visible)
3737 Visible = "default";
3738
3739 ur.AgentData = new UserInfoReplyPacket.AgentDataBlock();
3740 ur.AgentData.AgentID = AgentId;
3741
3742 ur.UserData = new UserInfoReplyPacket.UserDataBlock();
3743 ur.UserData.IMViaEMail = imViaEmail;
3744 ur.UserData.DirectoryVisibility = Utils.StringToBytes(Visible);
3745 ur.UserData.EMail = Utils.StringToBytes(email);
3746
3747 OutPacket(ur, ThrottleOutPacketType.Task);
3748 }
3749
3750 public void SendCreateGroupReply(UUID groupID, bool success, string message)
3751 {
3752 CreateGroupReplyPacket createGroupReply = (CreateGroupReplyPacket)PacketPool.Instance.GetPacket(PacketType.CreateGroupReply);
3753
3754 createGroupReply.AgentData =
3755 new CreateGroupReplyPacket.AgentDataBlock();
3756 createGroupReply.ReplyData =
3757 new CreateGroupReplyPacket.ReplyDataBlock();
3758
3759 createGroupReply.AgentData.AgentID = AgentId;
3760 createGroupReply.ReplyData.GroupID = groupID;
3761
3762 createGroupReply.ReplyData.Success = success;
3763 createGroupReply.ReplyData.Message = Utils.StringToBytes(message);
3764 OutPacket(createGroupReply, ThrottleOutPacketType.Task);
3765 }
3766
3767 public void SendUseCachedMuteList()
3768 {
3769 UseCachedMuteListPacket useCachedMuteList = (UseCachedMuteListPacket)PacketPool.Instance.GetPacket(PacketType.UseCachedMuteList);
3770
3771 useCachedMuteList.AgentData = new UseCachedMuteListPacket.AgentDataBlock();
3772 useCachedMuteList.AgentData.AgentID = AgentId;
3773
3774 OutPacket(useCachedMuteList, ThrottleOutPacketType.Task);
3775 }
3776
3777 public void SendEmpytMuteList()
3778 {
3779 GenericMessagePacket gmp = new GenericMessagePacket();
3780
3781 gmp.AgentData.AgentID = AgentId;
3782 gmp.AgentData.SessionID = m_sessionId;
3783 gmp.AgentData.TransactionID = UUID.Zero;
3784
3785 gmp.MethodData.Method = Util.StringToBytes256("emptymutelist");
3786 gmp.ParamList = new GenericMessagePacket.ParamListBlock[1];
3787 gmp.ParamList[0] = new GenericMessagePacket.ParamListBlock();
3788 gmp.ParamList[0].Parameter = new byte[0];
3789
3790 OutPacket(gmp, ThrottleOutPacketType.Task);
3791 }
3792
3793 public void SendMuteListUpdate(string filename)
3794 {
3795 MuteListUpdatePacket muteListUpdate = (MuteListUpdatePacket)PacketPool.Instance.GetPacket(PacketType.MuteListUpdate);
3796
3797 muteListUpdate.MuteData = new MuteListUpdatePacket.MuteDataBlock();
3798 muteListUpdate.MuteData.AgentID = AgentId;
3799 muteListUpdate.MuteData.Filename = Utils.StringToBytes(filename);
3800
3801 OutPacket(muteListUpdate, ThrottleOutPacketType.Task);
3802 }
3803
3804 public void SendPickInfoReply(UUID pickID, UUID creatorID, bool topPick, UUID parcelID, string name, string desc, UUID snapshotID, string user, string originalName, string simName, Vector3 posGlobal, int sortOrder, bool enabled)
3805 {
3806 PickInfoReplyPacket pickInfoReply = (PickInfoReplyPacket)PacketPool.Instance.GetPacket(PacketType.PickInfoReply);
3807
3808 pickInfoReply.AgentData = new PickInfoReplyPacket.AgentDataBlock();
3809 pickInfoReply.AgentData.AgentID = AgentId;
3810
3811 pickInfoReply.Data = new PickInfoReplyPacket.DataBlock();
3812 pickInfoReply.Data.PickID = pickID;
3813 pickInfoReply.Data.CreatorID = creatorID;
3814 pickInfoReply.Data.TopPick = topPick;
3815 pickInfoReply.Data.ParcelID = parcelID;
3816 pickInfoReply.Data.Name = Utils.StringToBytes(name);
3817 pickInfoReply.Data.Desc = Utils.StringToBytes(desc);
3818 pickInfoReply.Data.SnapshotID = snapshotID;
3819 pickInfoReply.Data.User = Utils.StringToBytes(user);
3820 pickInfoReply.Data.OriginalName = Utils.StringToBytes(originalName);
3821 pickInfoReply.Data.SimName = Utils.StringToBytes(simName);
3822 pickInfoReply.Data.PosGlobal = new Vector3d(posGlobal);
3823 pickInfoReply.Data.SortOrder = sortOrder;
3824 pickInfoReply.Data.Enabled = enabled;
3825
3826 OutPacket(pickInfoReply, ThrottleOutPacketType.Task);
3827 }
3828
3829 #endregion Scene/Avatar to Client
3830
3831 // Gesture
3832
3833 #region Appearance/ Wearables Methods
3834
3835 public void SendWearables(AvatarWearable[] wearables, int serial)
3836 {
3837 AgentWearablesUpdatePacket aw = (AgentWearablesUpdatePacket)PacketPool.Instance.GetPacket(PacketType.AgentWearablesUpdate);
3838 aw.AgentData.AgentID = AgentId;
3839 aw.AgentData.SerialNum = (uint)serial;
3840 aw.AgentData.SessionID = m_sessionId;
3841
3842 int count = 0;
3843 for (int i = 0; i < wearables.Length; i++)
3844 count += wearables[i].Count;
3845
3846 // TODO: don't create new blocks if recycling an old packet
3847 aw.WearableData = new AgentWearablesUpdatePacket.WearableDataBlock[count];
3848 AgentWearablesUpdatePacket.WearableDataBlock awb;
3849 int idx = 0;
3850
3851 for (int i = 0; i < wearables.Length; i++)
3852 {
3853 for (int j = 0; j < wearables[i].Count; j++)
3854 {
3855 awb = new AgentWearablesUpdatePacket.WearableDataBlock();
3856 awb.WearableType = (byte) i;
3857 awb.AssetID = wearables[i][j].AssetID;
3858 awb.ItemID = wearables[i][j].ItemID;
3859 aw.WearableData[idx] = awb;
3860 idx++;
3861
3862 // m_log.DebugFormat(
3863 // "[APPEARANCE]: Sending wearable item/asset {0} {1} (index {2}) for {3}",
3864 // awb.ItemID, awb.AssetID, i, Name);
3865 }
3866 }
3867
3868 OutPacket(aw, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority);
3869 }
3870
3871 public void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry)
3872 {
3873// m_log.DebugFormat(
3874// "[LLCLIENTVIEW]: Sending avatar appearance for {0} with {1} bytes to {2} {3}",
3875// agentID, textureEntry.Length, Name, AgentId);
3876
3877 AvatarAppearancePacket avp = (AvatarAppearancePacket)PacketPool.Instance.GetPacket(PacketType.AvatarAppearance);
3878 // TODO: don't create new blocks if recycling an old packet
3879 avp.VisualParam = new AvatarAppearancePacket.VisualParamBlock[visualParams.Length];
3880 avp.ObjectData.TextureEntry = textureEntry;
3881
3882 AvatarAppearancePacket.VisualParamBlock avblock = null;
3883 for (int i = 0; i < visualParams.Length; i++)
3884 {
3885 avblock = new AvatarAppearancePacket.VisualParamBlock();
3886 avblock.ParamValue = visualParams[i];
3887 avp.VisualParam[i] = avblock;
3888 }
3889
3890 avp.Sender.IsTrial = false;
3891 avp.Sender.ID = agentID;
3892 avp.AppearanceData = new AvatarAppearancePacket.AppearanceDataBlock[0];
3893 avp.AppearanceHover = new AvatarAppearancePacket.AppearanceHoverBlock[0];
3894
3895// this need be use in future ?
3896// avp.AppearanceData[0].AppearanceVersion = 0;
3897// avp.AppearanceData[0].CofVersion = 0;
3898
3899 //m_log.DebugFormat("[CLIENT]: Sending appearance for {0} to {1}", agentID.ToString(), AgentId.ToString());
3900 OutPacket(avp, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority);
3901 }
3902
3903 public void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs)
3904 {
3905// m_log.DebugFormat("[LLCLIENTVIEW]: Sending animations for {0} to {1}", sourceAgentId, Name);
3906
3907 AvatarAnimationPacket ani = (AvatarAnimationPacket)PacketPool.Instance.GetPacket(PacketType.AvatarAnimation);
3908 // TODO: don't create new blocks if recycling an old packet
3909 ani.AnimationSourceList = new AvatarAnimationPacket.AnimationSourceListBlock[animations.Length];
3910 ani.Sender = new AvatarAnimationPacket.SenderBlock();
3911 ani.Sender.ID = sourceAgentId;
3912 ani.AnimationList = new AvatarAnimationPacket.AnimationListBlock[animations.Length];
3913 ani.PhysicalAvatarEventList = new AvatarAnimationPacket.PhysicalAvatarEventListBlock[0];
3914
3915 for (int i = 0; i < animations.Length; ++i)
3916 {
3917 ani.AnimationList[i] = new AvatarAnimationPacket.AnimationListBlock();
3918 ani.AnimationList[i].AnimID = animations[i];
3919 ani.AnimationList[i].AnimSequenceID = seqs[i];
3920
3921 ani.AnimationSourceList[i] = new AvatarAnimationPacket.AnimationSourceListBlock();
3922 if (objectIDs[i].Equals(sourceAgentId))
3923 ani.AnimationSourceList[i].ObjectID = UUID.Zero;
3924 else
3925 ani.AnimationSourceList[i].ObjectID = objectIDs[i];
3926 }
3927 ani.Header.Reliable = false;
3928 OutPacket(ani, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority);
3929 }
3930
3931 #endregion
3932
3933 #region Avatar Packet/Data Sending Methods
3934
3935 /// <summary>
3936 /// Send an ObjectUpdate packet with information about an avatar
3937 /// </summary>
3938 public void SendEntityFullUpdateImmediate(ISceneEntity ent)
3939 {
3940// m_log.DebugFormat(
3941// "[LLCLIENTVIEW]: Sending immediate object update for avatar {0} {1} to {2} {3}",
3942// avatar.Name, avatar.UUID, Name, AgentId);
3943
3944 if (ent == null)
3945 return;
3946
3947 ObjectUpdatePacket objupdate = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
3948 objupdate.Header.Zerocoded = true;
3949
3950 objupdate.RegionData.TimeDilation = Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f);
3951 objupdate.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1];
3952
3953 if(ent is ScenePresence)
3954 {
3955 ScenePresence presence = ent as ScenePresence;
3956 objupdate.RegionData.RegionHandle = presence.RegionHandle;
3957 objupdate.ObjectData[0] = CreateAvatarUpdateBlock(presence);
3958 }
3959 else if(ent is SceneObjectPart)
3960 {
3961 SceneObjectPart part = ent as SceneObjectPart;
3962 objupdate.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3963 objupdate.ObjectData[0] = CreatePrimUpdateBlock(part, (ScenePresence)SceneAgent);
3964 }
3965
3966 OutPacket(objupdate, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority);
3967
3968 // We need to record the avatar local id since the root prim of an attachment points to this.
3969// m_attachmentsSent.Add(avatar.LocalId);
3970 }
3971
3972 public void SendEntityTerseUpdateImmediate(ISceneEntity ent)
3973 {
3974// m_log.DebugFormat(
3975// "[LLCLIENTVIEW]: Sending immediate object update for avatar {0} {1} to {2} {3}",
3976// avatar.Name, avatar.UUID, Name, AgentId);
3977
3978 if (ent == null)
3979 return;
3980
3981 ImprovedTerseObjectUpdatePacket objupdate =
3982 (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate);
3983 objupdate.Header.Zerocoded = true;
3984
3985 objupdate.RegionData.TimeDilation = Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f);
3986 objupdate.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1];
3987
3988 if(ent is ScenePresence)
3989 {
3990 ScenePresence presence = ent as ScenePresence;
3991 objupdate.RegionData.RegionHandle = presence.RegionHandle;
3992 objupdate.ObjectData[0] = CreateImprovedTerseBlock(ent, false);
3993 }
3994 else if(ent is SceneObjectPart)
3995 {
3996 SceneObjectPart part = ent as SceneObjectPart;
3997 objupdate.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3998 objupdate.ObjectData[0] = CreateImprovedTerseBlock(ent, false);
3999 }
4000
4001 OutPacket(objupdate, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority);
4002
4003 // We need to record the avatar local id since the root prim of an attachment points to this.
4004// m_attachmentsSent.Add(avatar.LocalId);
4005 }
4006
4007 public void SendCoarseLocationUpdate(List<UUID> users, List<Vector3> CoarseLocations)
4008 {
4009 // We don't need to update inactive clients.
4010 if (!IsActive)
4011 return;
4012
4013 CoarseLocationUpdatePacket loc = (CoarseLocationUpdatePacket)PacketPool.Instance.GetPacket(PacketType.CoarseLocationUpdate);
4014 loc.Header.Reliable = false;
4015
4016 // Each packet can only hold around 60 avatar positions and the client clears the mini-map each time
4017 // a CoarseLocationUpdate packet is received. Oh well.
4018 int total = Math.Min(CoarseLocations.Count, 60);
4019
4020 CoarseLocationUpdatePacket.IndexBlock ib = new CoarseLocationUpdatePacket.IndexBlock();
4021
4022 loc.Location = new CoarseLocationUpdatePacket.LocationBlock[total];
4023 loc.AgentData = new CoarseLocationUpdatePacket.AgentDataBlock[total];
4024
4025 int selfindex = -1;
4026 for (int i = 0; i < total; i++)
4027 {
4028 CoarseLocationUpdatePacket.LocationBlock lb =
4029 new CoarseLocationUpdatePacket.LocationBlock();
4030
4031 lb.X = (byte)CoarseLocations[i].X;
4032 lb.Y = (byte)CoarseLocations[i].Y;
4033
4034 lb.Z = CoarseLocations[i].Z > 1024 ? (byte)0 : (byte)(CoarseLocations[i].Z * 0.25f);
4035 loc.Location[i] = lb;
4036 loc.AgentData[i] = new CoarseLocationUpdatePacket.AgentDataBlock();
4037 loc.AgentData[i].AgentID = users[i];
4038 if (users[i] == AgentId)
4039 selfindex = i;
4040 }
4041
4042 ib.You = (short)selfindex;
4043 ib.Prey = -1;
4044 loc.Index = ib;
4045
4046 OutPacket(loc, ThrottleOutPacketType.Task);
4047 }
4048
4049 #endregion Avatar Packet/Data Sending Methods
4050
4051 #region Primitive Packet/Data Sending Methods
4052
4053 /// <summary>
4054 /// Generate one of the object update packets based on PrimUpdateFlags
4055 /// and broadcast the packet to clients
4056 /// </summary>
4057 public void SendEntityUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags)
4058 {
4059/*
4060 if (entity.UUID == m_agentId && !updateFlags.HasFlag(PrimUpdateFlags.FullUpdate))
4061 {
4062 ImprovedTerseObjectUpdatePacket packet
4063 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate);
4064
4065 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4066 packet.RegionData.TimeDilation = Utils.FloatToUInt16(1, 0.0f, 1.0f);
4067 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1];
4068 packet.ObjectData[0] = CreateImprovedTerseBlock(entity, false);
4069 OutPacket(packet, ThrottleOutPacketType.Unknown, true);
4070 return;
4071 }
4072*/
4073 if (entity is SceneObjectPart)
4074 {
4075 SceneObjectPart p = (SceneObjectPart)entity;
4076 SceneObjectGroup g = p.ParentGroup;
4077 if (g.HasPrivateAttachmentPoint && g.OwnerID != AgentId)
4078 return; // Don't send updates for other people's HUDs
4079
4080 if((updateFlags ^ PrimUpdateFlags.SendInTransit) == 0)
4081 {
4082 List<uint> partIDs = (new List<uint> {p.LocalId});
4083 lock (m_entityProps.SyncRoot)
4084 m_entityProps.Remove(partIDs);
4085 lock (m_entityUpdates.SyncRoot)
4086 m_entityUpdates.Remove(partIDs);
4087 return;
4088 }
4089 }
4090
4091 //double priority = m_prioritizer.GetUpdatePriority(this, entity);
4092 uint priority = m_prioritizer.GetUpdatePriority(this, entity);
4093
4094 lock (m_entityUpdates.SyncRoot)
4095 m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags));
4096 }
4097
4098 /// <summary>
4099 /// Requeue an EntityUpdate when it was not acknowledged by the client.
4100 /// We will update the priority and put it in the correct queue, merging update flags
4101 /// with any other updates that may be queued for the same entity.
4102 /// The original update time is used for the merged update.
4103 /// </summary>
4104 private void ResendPrimUpdate(EntityUpdate update)
4105 {
4106 // If the update exists in priority queue, it will be updated.
4107 // If it does not exist then it will be added with the current (rather than its original) priority
4108 uint priority = m_prioritizer.GetUpdatePriority(this, update.Entity);
4109
4110 lock (m_entityUpdates.SyncRoot)
4111 m_entityUpdates.Enqueue(priority, update);
4112 }
4113
4114 /// <summary>
4115 /// Requeue a list of EntityUpdates when they were not acknowledged by the client.
4116 /// We will update the priority and put it in the correct queue, merging update flags
4117 /// with any other updates that may be queued for the same entity.
4118 /// The original update time is used for the merged update.
4119 /// </summary>
4120 private void ResendPrimUpdates(List<EntityUpdate> updates, OutgoingPacket oPacket)
4121 {
4122 // m_log.WarnFormat("[CLIENT] resending prim updates {0}, packet sequence number {1}", updates[0].UpdateTime, oPacket.SequenceNumber);
4123
4124 // Remove the update packet from the list of packets waiting for acknowledgement
4125 // because we are requeuing the list of updates. They will be resent in new packets
4126 // with the most recent state and priority.
4127 m_udpClient.NeedAcks.Remove(oPacket.SequenceNumber);
4128
4129 // Count this as a resent packet since we are going to requeue all of the updates contained in it
4130 Interlocked.Increment(ref m_udpClient.PacketsResent);
4131
4132 // We're not going to worry about interlock yet since its not currently critical that this total count
4133 // is 100% correct
4134 m_udpServer.PacketsResentCount++;
4135
4136 foreach (EntityUpdate update in updates)
4137 ResendPrimUpdate(update);
4138 }
4139
4140 private List<ObjectUpdatePacket.ObjectDataBlock> objectUpdateBlocks = new List<ObjectUpdatePacket.ObjectDataBlock>();
4141 private List<ObjectUpdateCompressedPacket.ObjectDataBlock> compressedUpdateBlocks = new List<ObjectUpdateCompressedPacket.ObjectDataBlock>();
4142 private List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> terseUpdateBlocks = new List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>();
4143 private List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> terseAgentUpdateBlocks = new List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>();
4144
4145 private void ProcessEntityUpdates(int maxUpdatesBytes)
4146 {
4147 OpenSim.Framework.Lazy<List<EntityUpdate>> objectUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
4148 OpenSim.Framework.Lazy<List<EntityUpdate>> compressedUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
4149 OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
4150 OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
4151
4152 // Check to see if this is a flush
4153 if (maxUpdatesBytes <= 0)
4154 {
4155 maxUpdatesBytes = Int32.MaxValue;
4156 }
4157
4158 EntityUpdate update;
4159 Int32 timeinqueue; // this is just debugging code & can be dropped later
4160
4161 bool doCulling = m_scene.ObjectsCullingByDistance;
4162 float cullingrange = 64.0f;
4163 HashSet<SceneObjectGroup> GroupsNeedFullUpdate = new HashSet<SceneObjectGroup>();
4164// Vector3 mycamera = Vector3.Zero;
4165 Vector3 mypos = Vector3.Zero;
4166 ScenePresence mysp = (ScenePresence)SceneAgent;
4167
4168 bool orderedDequeue = m_scene.UpdatePrioritizationScheme == UpdatePrioritizationSchemes.SimpleAngularDistance;
4169 // we should have a presence
4170 if(mysp == null)
4171 return;
4172
4173 if(doCulling)
4174 {
4175 cullingrange = mysp.DrawDistance + m_scene.ReprioritizationDistance + 16f;
4176// mycamera = mysp.CameraPosition;
4177 mypos = mysp.AbsolutePosition;
4178 }
4179
4180 while (maxUpdatesBytes > 0)
4181 {
4182 lock (m_entityUpdates.SyncRoot)
4183 {
4184 if(orderedDequeue)
4185 {
4186 if (!m_entityUpdates.TryOrderedDequeue(out update, out timeinqueue))
4187 break;
4188 }
4189 else
4190 {
4191 if (!m_entityUpdates.TryDequeue(out update, out timeinqueue))
4192 break;
4193 }
4194 }
4195
4196 PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags;
4197
4198 if(updateFlags.HasFlag(PrimUpdateFlags.Kill))
4199 {
4200 m_killRecord.Add(update.Entity.LocalId);
4201 maxUpdatesBytes -= 30;
4202 continue;
4203 }
4204
4205 if (update.Entity is SceneObjectPart)
4206 {
4207 SceneObjectPart part = (SceneObjectPart)update.Entity;
4208 SceneObjectGroup grp = part.ParentGroup;
4209 if (grp.inTransit && !update.Flags.HasFlag(PrimUpdateFlags.SendInTransit))
4210 continue;
4211/* debug
4212 if (update.Flags.HasFlag(PrimUpdateFlags.SendInTransit))
4213 {
4214
4215
4216 }
4217*/
4218 if (grp.IsDeleted)
4219 {
4220 // Don't send updates for objects that have been marked deleted.
4221 // Instead send another kill object, because the first one may have gotten
4222 // into a race condition
4223 if (part == grp.RootPart && !m_killRecord.Contains(grp.LocalId))
4224 {
4225 m_killRecord.Add(grp.LocalId);
4226 maxUpdatesBytes -= 30;
4227 }
4228 continue;
4229 }
4230
4231 if (grp.IsAttachment)
4232 { // Someone else's HUD, why are we getting these?
4233 if (grp.OwnerID != AgentId && grp.HasPrivateAttachmentPoint)
4234 continue;
4235 ScenePresence sp;
4236 // Owner is not in the sim, don't update it to
4237 // anyone
4238 if (!m_scene.TryGetScenePresence(part.OwnerID, out sp))
4239 continue;
4240
4241 List<SceneObjectGroup> atts = sp.GetAttachments();
4242 bool found = false;
4243 foreach (SceneObjectGroup att in atts)
4244 {
4245 if (att == grp)
4246 {
4247 found = true;
4248 break;
4249 }
4250 }
4251
4252 // It's an attachment of a valid avatar, but
4253 // doesn't seem to be attached, skip
4254 if (!found)
4255 continue;
4256
4257 // On vehicle crossing, the attachments are received
4258 // while the avatar is still a child. Don't send
4259 // updates here because the LocalId has not yet
4260 // been updated and the viewer will derender the
4261 // attachments until the avatar becomes root.
4262 if (sp.IsChildAgent)
4263 continue;
4264
4265 }
4266
4267 if (grp.IsAttachment && m_disableFacelights)
4268 {
4269 if (grp.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand &&
4270 grp.RootPart.Shape.State != (byte)AttachmentPoint.RightHand)
4271 {
4272 part.Shape.LightEntry = false;
4273 }
4274 }
4275
4276 if(doCulling && !grp.IsAttachment)
4277 {
4278 if(GroupsNeedFullUpdate.Contains(grp))
4279 continue;
4280
4281 bool inview = false;
4282 lock(GroupsInView)
4283 inview = GroupsInView.Contains(grp);
4284
4285 if(!inview)
4286 {
4287 float bradius = grp.GetBoundsRadius();
4288 Vector3 partpos = grp.AbsolutePosition + grp.getBoundsCenter();
4289// float dcam = (partpos - mycamera).LengthSquared();
4290 float dpos = (partpos - mypos).LengthSquared();
4291// if(dcam < dpos)
4292// dpos = dcam;
4293 dpos = (float)Math.Sqrt(dpos) - bradius;
4294 if(dpos > cullingrange)
4295 continue;
4296
4297 GroupsNeedFullUpdate.Add(grp);
4298 continue;
4299 }
4300 }
4301 }
4302 else if (update.Entity is ScenePresence)
4303 {
4304 ScenePresence presence = (ScenePresence)update.Entity;
4305 if (presence.IsDeleted)
4306 continue;
4307 // If ParentUUID is not UUID.Zero and ParentID is 0, this
4308 // avatar is in the process of crossing regions while
4309 // sat on an object. In this state, we don't want any
4310 // updates because they will visually orbit the avatar.
4311 // Update will be forced once crossing is completed anyway.
4312 if (presence.ParentUUID != UUID.Zero && presence.ParentID == 0)
4313 continue;
4314 }
4315
4316 #region UpdateFlags to packet type conversion
4317
4318 bool canUseCompressed = true;
4319 bool canUseImproved = true;
4320
4321
4322 // Compressed object updates only make sense for LL primitives
4323 if (!(update.Entity is SceneObjectPart))
4324 {
4325 canUseCompressed = false;
4326 }
4327
4328 if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate))
4329 {
4330 canUseCompressed = false;
4331 canUseImproved = false;
4332 }
4333 else
4334 {
4335 if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) ||
4336 updateFlags.HasFlag(PrimUpdateFlags.Acceleration) ||
4337 updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) ||
4338 updateFlags.HasFlag(PrimUpdateFlags.Joint))
4339 {
4340 canUseCompressed = false;
4341 }
4342
4343 if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) ||
4344 updateFlags.HasFlag(PrimUpdateFlags.ParentID) ||
4345 updateFlags.HasFlag(PrimUpdateFlags.Scale) ||
4346 updateFlags.HasFlag(PrimUpdateFlags.PrimData) ||
4347 updateFlags.HasFlag(PrimUpdateFlags.Text) ||
4348 updateFlags.HasFlag(PrimUpdateFlags.NameValue) ||
4349 updateFlags.HasFlag(PrimUpdateFlags.ExtraData) ||
4350 updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) ||
4351 updateFlags.HasFlag(PrimUpdateFlags.Sound) ||
4352 updateFlags.HasFlag(PrimUpdateFlags.Particles) ||
4353 updateFlags.HasFlag(PrimUpdateFlags.Material) ||
4354 updateFlags.HasFlag(PrimUpdateFlags.ClickAction) ||
4355 updateFlags.HasFlag(PrimUpdateFlags.MediaURL) ||
4356 updateFlags.HasFlag(PrimUpdateFlags.Joint))
4357 {
4358 canUseImproved = false;
4359 }
4360 }
4361
4362 #endregion UpdateFlags to packet type conversion
4363
4364 #region Block Construction
4365
4366 // TODO: Remove this once we can build compressed updates
4367 canUseCompressed = false;
4368
4369 if (!canUseImproved && !canUseCompressed)
4370 {
4371 ObjectUpdatePacket.ObjectDataBlock ablock;
4372 if (update.Entity is ScenePresence)
4373 ablock = CreateAvatarUpdateBlock((ScenePresence)update.Entity);
4374 else
4375 ablock = CreatePrimUpdateBlock((SceneObjectPart)update.Entity, mysp);
4376 objectUpdateBlocks.Add(ablock);
4377 objectUpdates.Value.Add(update);
4378 maxUpdatesBytes -= ablock.Length;
4379
4380 }
4381 else if (!canUseImproved)
4382 {
4383 ObjectUpdateCompressedPacket.ObjectDataBlock ablock =
4384 CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags);
4385 compressedUpdateBlocks.Add(ablock);
4386 compressedUpdates.Value.Add(update);
4387 maxUpdatesBytes -= ablock.Length;
4388 }
4389 else
4390 {
4391 ImprovedTerseObjectUpdatePacket.ObjectDataBlock ablock;
4392 if (update.Entity is ScenePresence)
4393 {
4394 // ALL presence updates go into a special list
4395 ablock = CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures));
4396 terseAgentUpdateBlocks.Add(ablock);
4397 terseAgentUpdates.Value.Add(update);
4398 }
4399 else
4400 {
4401 // Everything else goes here
4402 ablock = CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures));
4403 terseUpdateBlocks.Add(ablock);
4404 terseUpdates.Value.Add(update);
4405 }
4406 maxUpdatesBytes -= ablock.Length;
4407 }
4408
4409 #endregion Block Construction
4410 }
4411
4412 #region Packet Sending
4413
4414 ushort timeDilation;
4415
4416 if(!IsActive)
4417 return;
4418
4419 timeDilation = Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f);
4420
4421 if (terseAgentUpdateBlocks.Count > 0)
4422 {
4423 ImprovedTerseObjectUpdatePacket packet
4424 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate);
4425 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4426 packet.RegionData.TimeDilation = timeDilation;
4427 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[terseAgentUpdateBlocks.Count];
4428
4429 for (int i = 0; i < terseAgentUpdateBlocks.Count; i++)
4430 packet.ObjectData[i] = terseAgentUpdateBlocks[i];
4431
4432 terseAgentUpdateBlocks.Clear();
4433
4434 OutPacket(packet, ThrottleOutPacketType.Unknown, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseAgentUpdates.Value, oPacket); });
4435 }
4436
4437 if (objectUpdateBlocks.Count > 0)
4438 {
4439 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
4440 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4441 packet.RegionData.TimeDilation = timeDilation;
4442 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[objectUpdateBlocks.Count];
4443
4444 for (int i = 0; i < objectUpdateBlocks.Count; i++)
4445 packet.ObjectData[i] = objectUpdateBlocks[i];
4446
4447 objectUpdateBlocks.Clear();
4448
4449 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(objectUpdates.Value, oPacket); });
4450 }
4451
4452 if (compressedUpdateBlocks.Count > 0)
4453 {
4454 ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
4455 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4456 packet.RegionData.TimeDilation = timeDilation;
4457 packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[compressedUpdateBlocks.Count];
4458
4459 for (int i = 0; i < compressedUpdateBlocks.Count; i++)
4460 packet.ObjectData[i] = compressedUpdateBlocks[i];
4461
4462 compressedUpdateBlocks.Clear();
4463
4464 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(compressedUpdates.Value, oPacket); });
4465 }
4466
4467 if (terseUpdateBlocks.Count > 0)
4468 {
4469 ImprovedTerseObjectUpdatePacket packet
4470 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
4471 PacketType.ImprovedTerseObjectUpdate);
4472 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4473 packet.RegionData.TimeDilation = timeDilation;
4474 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[terseUpdateBlocks.Count];
4475
4476 for (int i = 0; i < terseUpdateBlocks.Count; i++)
4477 packet.ObjectData[i] = terseUpdateBlocks[i];
4478
4479 terseUpdateBlocks.Clear();
4480
4481 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); });
4482 }
4483
4484 #endregion Packet Sending
4485
4486 #region Handle deleted objects
4487 if (m_killRecord.Count > 0)
4488 {
4489 SendKillObject(m_killRecord);
4490 m_killRecord.Clear();
4491 }
4492
4493 if(GroupsNeedFullUpdate.Count > 0)
4494 {
4495 foreach(SceneObjectGroup grp in GroupsNeedFullUpdate)
4496 {
4497 foreach(SceneObjectPart p in grp.Parts)
4498 SendEntityUpdate(p,PrimUpdateFlags.CancelKill);
4499 lock(GroupsInView)
4500 GroupsInView.Add(grp);
4501 }
4502 }
4503 #endregion
4504 }
4505
4506 // hack.. dont use
4507/*
4508 public void SendPartFullUpdate(ISceneEntity ent, uint? parentID)
4509 {
4510 if (ent is SceneObjectPart)
4511 {
4512 SceneObjectPart part = (SceneObjectPart)ent;
4513 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
4514 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4515 packet.RegionData.TimeDilation = Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f);
4516 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1];
4517
4518 ObjectUpdatePacket.ObjectDataBlock blk = CreatePrimUpdateBlock(part, mysp);
4519 if (parentID.HasValue)
4520 {
4521 blk.ParentID = parentID.Value;
4522 }
4523
4524 packet.ObjectData[0] = blk;
4525
4526 OutPacket(packet, ThrottleOutPacketType.Task, true);
4527 }
4528
4529// m_log.DebugFormat(
4530// "[LLCLIENTVIEW]: Sent {0} updates in ProcessEntityUpdates() for {1} {2} in {3}",
4531// updatesThisCall, Name, SceneAgent.IsChildAgent ? "child" : "root", Scene.Name);
4532//
4533 }
4534*/
4535 public void ReprioritizeUpdates()
4536 {
4537 lock (m_entityUpdates.SyncRoot)
4538 m_entityUpdates.Reprioritize(UpdatePriorityHandler);
4539 CheckGroupsInView();
4540 }
4541
4542 private bool CheckGroupsInViewBusy = false;
4543
4544 public void CheckGroupsInView()
4545 {
4546 bool doCulling = m_scene.ObjectsCullingByDistance;
4547 if(!doCulling)
4548 return;
4549
4550 if(CheckGroupsInViewBusy)
4551 return;
4552
4553 CheckGroupsInViewBusy = true;
4554
4555 float cullingrange = 64.0f;
4556// Vector3 mycamera = Vector3.Zero;
4557 Vector3 mypos = Vector3.Zero;
4558 ScenePresence mysp = (ScenePresence)SceneAgent;
4559 if(mysp != null && !mysp.IsDeleted)
4560 {
4561 cullingrange = mysp.DrawDistance + m_scene.ReprioritizationDistance + 16f;
4562// mycamera = mysp.CameraPosition;
4563 mypos = mysp.AbsolutePosition;
4564 }
4565 else
4566 {
4567 CheckGroupsInViewBusy= false;
4568 return;
4569 }
4570
4571 HashSet<SceneObjectGroup> NewGroupsInView = new HashSet<SceneObjectGroup>();
4572 HashSet<SceneObjectGroup> GroupsNeedFullUpdate = new HashSet<SceneObjectGroup>();
4573 List<SceneObjectGroup> kills = new List<SceneObjectGroup>();
4574
4575 EntityBase[] entities = m_scene.Entities.GetEntities();
4576 foreach (EntityBase e in entities)
4577 {
4578 if(!IsActive)
4579 return;
4580
4581 if (e != null && e is SceneObjectGroup)
4582 {
4583 SceneObjectGroup grp = (SceneObjectGroup)e;
4584 if(grp.IsDeleted || grp.IsAttachment)
4585 continue;
4586
4587 float bradius = grp.GetBoundsRadius();
4588 Vector3 grppos = grp.AbsolutePosition + grp.getBoundsCenter();
4589// float dcam = (grppos - mycamera).LengthSquared();
4590 float dpos = (grppos - mypos).LengthSquared();
4591// if(dcam < dpos)
4592// dpos = dcam;
4593
4594 dpos = (float)Math.Sqrt(dpos) - bradius;
4595
4596 bool inview;
4597 lock(GroupsInView)
4598 inview = GroupsInView.Contains(grp);
4599
4600 if(dpos > cullingrange)
4601 {
4602 if(inview)
4603 kills.Add(grp);
4604 }
4605 else
4606 {
4607 if(!inview)
4608 GroupsNeedFullUpdate.Add(grp);
4609 NewGroupsInView.Add(grp);
4610 }
4611 }
4612 }
4613
4614 lock(GroupsInView)
4615 GroupsInView = NewGroupsInView;
4616
4617 if (kills.Count > 0)
4618 {
4619 List<uint> partIDs = new List<uint>();
4620 foreach(SceneObjectGroup grp in kills)
4621 {
4622 SendEntityUpdate(grp.RootPart,PrimUpdateFlags.Kill);
4623 foreach(SceneObjectPart p in grp.Parts)
4624 {
4625 if(p != grp.RootPart)
4626 partIDs.Add(p.LocalId);
4627 }
4628 }
4629 kills.Clear();
4630 if(partIDs.Count > 0)
4631 {
4632 lock (m_entityProps.SyncRoot)
4633 m_entityProps.Remove(partIDs);
4634 lock (m_entityUpdates.SyncRoot)
4635 m_entityUpdates.Remove(partIDs);
4636 }
4637 }
4638
4639 if(GroupsNeedFullUpdate.Count > 0)
4640 {
4641 foreach(SceneObjectGroup grp in GroupsNeedFullUpdate)
4642 {
4643 foreach(SceneObjectPart p in grp.Parts)
4644 SendEntityUpdate(p,PrimUpdateFlags.CancelKill);
4645 }
4646 }
4647
4648 CheckGroupsInViewBusy = false;
4649 }
4650
4651 private bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity)
4652 {
4653 if (entity != null)
4654 {
4655 priority = m_prioritizer.GetUpdatePriority(this, entity);
4656 return true;
4657 }
4658
4659 return false;
4660 }
4661
4662 public void FlushPrimUpdates()
4663 {
4664 m_log.WarnFormat("[CLIENT]: Flushing prim updates to " + m_firstName + " " + m_lastName);
4665
4666 while (m_entityUpdates.Count > 0)
4667 ProcessEntityUpdates(-1);
4668 }
4669
4670 #endregion Primitive Packet/Data Sending Methods
4671
4672 // These are used to implement an adaptive backoff in the number
4673 // of updates converted to packets. Since we don't want packets
4674 // to sit in the queue with old data, only convert enough updates
4675 // to packets that can be sent in 200ms.
4676// private Int32 m_LastQueueFill = 0;
4677// private Int32 m_maxUpdates = 0;
4678
4679 void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories)
4680 {
4681 if(m_scene == null)
4682 return;
4683
4684 if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
4685 {
4686 int maxUpdateBytes = m_udpClient.GetCatBytesCanSend(ThrottleOutPacketType.Task, 30);
4687
4688 if (m_entityUpdates.Count > 0)
4689 ProcessEntityUpdates(maxUpdateBytes);
4690
4691 if (m_entityProps.Count > 0)
4692 ProcessEntityPropertyRequests(maxUpdateBytes);
4693 }
4694
4695 if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0)
4696 ImageManager.ProcessImageQueue(m_udpServer.TextureSendLimit);
4697 }
4698
4699 internal bool HandleHasUpdates(ThrottleOutPacketTypeFlags categories)
4700 {
4701 if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
4702 {
4703 if (m_entityUpdates.Count > 0)
4704 return true;
4705 if (m_entityProps.Count > 0)
4706 return true;
4707 }
4708
4709 if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0)
4710 {
4711 if (ImageManager.HasUpdates())
4712 return true;
4713 }
4714
4715 return false;
4716 }
4717
4718 public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID)
4719 {
4720 AssetUploadCompletePacket newPack = new AssetUploadCompletePacket();
4721 newPack.AssetBlock.Type = AssetType;
4722 newPack.AssetBlock.Success = Success;
4723 newPack.AssetBlock.UUID = AssetFullID;
4724 newPack.Header.Zerocoded = true;
4725 OutPacket(newPack, ThrottleOutPacketType.Asset);
4726 }
4727
4728 public void SendXferRequest(ulong XferID, short AssetType, UUID vFileID, byte FilePath, byte[] FileName)
4729 {
4730 RequestXferPacket newPack = new RequestXferPacket();
4731 newPack.XferID.ID = XferID;
4732 newPack.XferID.VFileType = AssetType;
4733 newPack.XferID.VFileID = vFileID;
4734 newPack.XferID.FilePath = FilePath;
4735 newPack.XferID.Filename = FileName;
4736 newPack.Header.Zerocoded = true;
4737 OutPacket(newPack, ThrottleOutPacketType.Asset);
4738 }
4739
4740 public void SendConfirmXfer(ulong xferID, uint PacketID)
4741 {
4742 ConfirmXferPacketPacket newPack = new ConfirmXferPacketPacket();
4743 newPack.XferID.ID = xferID;
4744 newPack.XferID.Packet = PacketID;
4745 newPack.Header.Zerocoded = true;
4746 OutPacket(newPack, ThrottleOutPacketType.Asset);
4747 }
4748
4749 public void SendInitiateDownload(string simFileName, string clientFileName)
4750 {
4751 InitiateDownloadPacket newPack = new InitiateDownloadPacket();
4752 newPack.AgentData.AgentID = AgentId;
4753 newPack.FileData.SimFilename = Utils.StringToBytes(simFileName);
4754 newPack.FileData.ViewerFilename = Utils.StringToBytes(clientFileName);
4755 OutPacket(newPack, ThrottleOutPacketType.Asset);
4756 }
4757
4758 public void SendImageFirstPart(
4759 ushort numParts, UUID ImageUUID, uint ImageSize, byte[] ImageData, byte imageCodec)
4760 {
4761 ImageDataPacket im = new ImageDataPacket();
4762 im.Header.Reliable = false;
4763 im.ImageID.Packets = numParts;
4764 im.ImageID.ID = ImageUUID;
4765
4766 if (ImageSize > 0)
4767 im.ImageID.Size = ImageSize;
4768
4769 im.ImageData.Data = ImageData;
4770 im.ImageID.Codec = imageCodec;
4771 im.Header.Zerocoded = true;
4772 OutPacket(im, ThrottleOutPacketType.Texture);
4773 }
4774
4775 public void SendImageNextPart(ushort partNumber, UUID imageUuid, byte[] imageData)
4776 {
4777 ImagePacketPacket im = new ImagePacketPacket();
4778 im.Header.Reliable = false;
4779 im.ImageID.Packet = partNumber;
4780 im.ImageID.ID = imageUuid;
4781 im.ImageData.Data = imageData;
4782
4783 OutPacket(im, ThrottleOutPacketType.Texture);
4784 }
4785
4786 public void SendImageNotFound(UUID imageid)
4787 {
4788 ImageNotInDatabasePacket notFoundPacket
4789 = (ImageNotInDatabasePacket)PacketPool.Instance.GetPacket(PacketType.ImageNotInDatabase);
4790
4791 notFoundPacket.ImageID.ID = imageid;
4792
4793 OutPacket(notFoundPacket, ThrottleOutPacketType.Texture);
4794 }
4795
4796 public void SendShutdownConnectionNotice()
4797 {
4798 OutPacket(PacketPool.Instance.GetPacket(PacketType.DisableSimulator), ThrottleOutPacketType.Unknown);
4799 }
4800
4801 public void SendSimStats(SimStats stats)
4802 {
4803 SimStatsPacket pack = new SimStatsPacket();
4804 pack.Region = new SimStatsPacket.RegionBlock();
4805 pack.Region.RegionX = stats.RegionX;
4806 pack.Region.RegionY = stats.RegionY;
4807 pack.Region.RegionFlags = stats.RegionFlags;
4808 pack.Region.ObjectCapacity = stats.ObjectCapacity;
4809 //pack.Region = //stats.RegionBlock;
4810 pack.Stat = stats.StatsBlock;
4811
4812 pack.Header.Reliable = false;
4813 pack.RegionInfo = new SimStatsPacket.RegionInfoBlock[0];
4814 OutPacket(pack, ThrottleOutPacketType.Task);
4815 }
4816
4817 private class ObjectPropertyUpdate : EntityUpdate
4818 {
4819 internal bool SendFamilyProps;
4820 internal bool SendObjectProps;
4821
4822 public ObjectPropertyUpdate(ISceneEntity entity, uint flags, bool sendfam, bool sendobj)
4823 : base(entity,(PrimUpdateFlags)flags)
4824 {
4825 SendFamilyProps = sendfam;
4826 SendObjectProps = sendobj;
4827 }
4828 public void Update(ObjectPropertyUpdate update)
4829 {
4830 SendFamilyProps = SendFamilyProps || update.SendFamilyProps;
4831 SendObjectProps = SendObjectProps || update.SendObjectProps;
4832 // other properties may need to be updated by base class
4833 base.Update(update);
4834 }
4835 }
4836
4837 public void SendObjectPropertiesFamilyData(ISceneEntity entity, uint requestFlags)
4838 {
4839 uint priority = 0; // time based ordering only
4840 lock (m_entityProps.SyncRoot)
4841 m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,requestFlags,true,false));
4842 }
4843
4844 private void ResendPropertyUpdate(ObjectPropertyUpdate update)
4845 {
4846 uint priority = 0;
4847 lock (m_entityProps.SyncRoot)
4848 m_entityProps.Enqueue(priority, update);
4849 }
4850
4851 private void ResendPropertyUpdates(List<ObjectPropertyUpdate> updates, OutgoingPacket oPacket)
4852 {
4853 // m_log.WarnFormat("[CLIENT] resending object property {0}",updates[0].UpdateTime);
4854
4855 // Remove the update packet from the list of packets waiting for acknowledgement
4856 // because we are requeuing the list of updates. They will be resent in new packets
4857 // with the most recent state.
4858 m_udpClient.NeedAcks.Remove(oPacket.SequenceNumber);
4859
4860 // Count this as a resent packet since we are going to requeue all of the updates contained in it
4861 Interlocked.Increment(ref m_udpClient.PacketsResent);
4862
4863 // We're not going to worry about interlock yet since its not currently critical that this total count
4864 // is 100% correct
4865 m_udpServer.PacketsResentCount++;
4866
4867 foreach (ObjectPropertyUpdate update in updates)
4868 ResendPropertyUpdate(update);
4869 }
4870
4871 public void SendObjectPropertiesReply(ISceneEntity entity)
4872 {
4873 uint priority = 0; // time based ordering only
4874 lock (m_entityProps.SyncRoot)
4875 m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,0,false,true));
4876 }
4877
4878 List<ObjectPropertiesFamilyPacket.ObjectDataBlock> objectFamilyBlocks = new
4879 List<ObjectPropertiesFamilyPacket.ObjectDataBlock>();
4880 List<ObjectPropertiesPacket.ObjectDataBlock> objectPropertiesBlocks =
4881 new List<ObjectPropertiesPacket.ObjectDataBlock>();
4882 List<SceneObjectPart> needPhysics = new List<SceneObjectPart>();
4883
4884 private void ProcessEntityPropertyRequests(int maxUpdateBytes)
4885 {
4886// OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>> familyUpdates =
4887// new OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>>();
4888
4889// OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>> propertyUpdates =
4890// new OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>>();
4891
4892 bool orderedDequeue = m_scene.UpdatePrioritizationScheme == UpdatePrioritizationSchemes.SimpleAngularDistance;
4893
4894 EntityUpdate iupdate;
4895 Int32 timeinqueue; // this is just debugging code & can be dropped later
4896
4897 while (maxUpdateBytes > 0)
4898 {
4899 lock (m_entityProps.SyncRoot)
4900 {
4901 if(orderedDequeue)
4902 {
4903 if (!m_entityProps.TryOrderedDequeue(out iupdate, out timeinqueue))
4904 break;
4905 }
4906 else
4907 {
4908 if (!m_entityProps.TryDequeue(out iupdate, out timeinqueue))
4909 break;
4910 }
4911 }
4912
4913 ObjectPropertyUpdate update = (ObjectPropertyUpdate)iupdate;
4914 if (update.SendFamilyProps)
4915 {
4916 if (update.Entity is SceneObjectPart)
4917 {
4918 SceneObjectPart sop = (SceneObjectPart)update.Entity;
4919 ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesFamilyBlock(sop,update.Flags);
4920 objectFamilyBlocks.Add(objPropDB);
4921// familyUpdates.Value.Add(update);
4922 maxUpdateBytes -= objPropDB.Length;
4923 }
4924 }
4925
4926 if (update.SendObjectProps)
4927 {
4928 if (update.Entity is SceneObjectPart)
4929 {
4930 SceneObjectPart sop = (SceneObjectPart)update.Entity;
4931 needPhysics.Add(sop);
4932 ObjectPropertiesPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesBlock(sop);
4933 objectPropertiesBlocks.Add(objPropDB);
4934// propertyUpdates.Value.Add(update);
4935 maxUpdateBytes -= objPropDB.Length;
4936 }
4937 }
4938 }
4939
4940 if (objectPropertiesBlocks.Count > 0)
4941 {
4942 ObjectPropertiesPacket packet = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties);
4943 packet.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[objectPropertiesBlocks.Count];
4944 for (int i = 0; i < objectPropertiesBlocks.Count; i++)
4945 packet.ObjectData[i] = objectPropertiesBlocks[i];
4946
4947
4948 objectPropertiesBlocks.Clear();
4949 packet.Header.Zerocoded = true;
4950
4951 // Pass in the delegate so that if this packet needs to be resent, we send the current properties
4952 // of the object rather than the properties when the packet was created
4953 // HACK : Remove intelligent resending until it's fixed in core
4954 //OutPacket(packet, ThrottleOutPacketType.Task, true,
4955 // delegate(OutgoingPacket oPacket)
4956 // {
4957 // ResendPropertyUpdates(propertyUpdates.Value, oPacket);
4958 // });
4959 OutPacket(packet, ThrottleOutPacketType.Task, true);
4960
4961 // pbcnt += blocks.Count;
4962 // ppcnt++;
4963 }
4964
4965 // Int32 fpcnt = 0;
4966 // Int32 fbcnt = 0;
4967
4968 if (objectFamilyBlocks.Count > 0)
4969 {
4970 // one packet per object block... uggh...
4971 for (int i = 0; i < objectFamilyBlocks.Count; i++)
4972 {
4973 ObjectPropertiesFamilyPacket packet =
4974 (ObjectPropertiesFamilyPacket)PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily);
4975
4976 packet.ObjectData = objectFamilyBlocks[i];
4977 packet.Header.Zerocoded = true;
4978
4979 // Pass in the delegate so that if this packet needs to be resent, we send the current properties
4980 // of the object rather than the properties when the packet was created
4981// List<ObjectPropertyUpdate> updates = new List<ObjectPropertyUpdate>();
4982// updates.Add(familyUpdates.Value[i]);
4983 // HACK : Remove intelligent resending until it's fixed in core
4984 //OutPacket(packet, ThrottleOutPacketType.Task, true,
4985 // delegate(OutgoingPacket oPacket)
4986 // {
4987 // ResendPropertyUpdates(updates, oPacket);
4988 // });
4989 OutPacket(packet, ThrottleOutPacketType.Task, true);
4990
4991 // fpcnt++;
4992 // fbcnt++;
4993 }
4994 objectFamilyBlocks.Clear();
4995 }
4996
4997 if(needPhysics.Count > 0)
4998 {
4999 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>();
5000 if(eq != null)
5001 {
5002 OSDArray array = new OSDArray();
5003 foreach(SceneObjectPart sop in needPhysics)
5004 {
5005 OSDMap physinfo = new OSDMap(6);
5006 physinfo["LocalID"] = sop.LocalId;
5007 physinfo["Density"] = sop.Density;
5008 physinfo["Friction"] = sop.Friction;
5009 physinfo["GravityMultiplier"] = sop.GravityModifier;
5010 physinfo["Restitution"] = sop.Restitution;
5011 physinfo["PhysicsShapeType"] = (int)sop.PhysicsShapeType;
5012 array.Add(physinfo);
5013 }
5014
5015 OSDMap llsdBody = new OSDMap(1);
5016 llsdBody.Add("ObjectData", array);
5017
5018 eq.Enqueue(BuildEvent("ObjectPhysicsProperties", llsdBody),AgentId);
5019 }
5020 needPhysics.Clear();
5021 }
5022
5023 // m_log.WarnFormat("[PACKETCOUNTS] queued {0} property packets with {1} blocks",ppcnt,pbcnt);
5024 // m_log.WarnFormat("[PACKETCOUNTS] queued {0} family property packets with {1} blocks",fpcnt,fbcnt);
5025 }
5026
5027 private ObjectPropertiesFamilyPacket.ObjectDataBlock CreateObjectPropertiesFamilyBlock(SceneObjectPart sop, PrimUpdateFlags requestFlags)
5028 {
5029 ObjectPropertiesFamilyPacket.ObjectDataBlock block = new ObjectPropertiesFamilyPacket.ObjectDataBlock();
5030
5031 block.RequestFlags = (uint)requestFlags;
5032 block.ObjectID = sop.UUID;
5033 if (sop.OwnerID == sop.GroupID)
5034 block.OwnerID = UUID.Zero;
5035 else
5036 block.OwnerID = sop.OwnerID;
5037 block.GroupID = sop.GroupID;
5038 block.BaseMask = sop.BaseMask;
5039 block.OwnerMask = sop.OwnerMask;
5040 block.GroupMask = sop.GroupMask;
5041 block.EveryoneMask = sop.EveryoneMask;
5042 block.NextOwnerMask = sop.NextOwnerMask;
5043
5044 // TODO: More properties are needed in SceneObjectPart!
5045 block.OwnershipCost = sop.OwnershipCost;
5046 block.SaleType = sop.ObjectSaleType;
5047 block.SalePrice = sop.SalePrice;
5048 block.Category = sop.Category;
5049 block.LastOwnerID = sop.LastOwnerID;
5050 block.Name = Util.StringToBytes256(sop.Name);
5051 block.Description = Util.StringToBytes256(sop.Description);
5052
5053 return block;
5054 }
5055
5056 private ObjectPropertiesPacket.ObjectDataBlock CreateObjectPropertiesBlock(SceneObjectPart sop)
5057 {
5058 //ObjectPropertiesPacket proper = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties);
5059 // TODO: don't create new blocks if recycling an old packet
5060
5061 ObjectPropertiesPacket.ObjectDataBlock block =
5062 new ObjectPropertiesPacket.ObjectDataBlock();
5063
5064 block.ObjectID = sop.UUID;
5065 block.Name = Util.StringToBytes256(sop.Name);
5066 block.Description = Util.StringToBytes256(sop.Description);
5067
5068 block.CreationDate = (ulong)sop.CreationDate * 1000000; // viewer wants date in microseconds
5069 block.CreatorID = sop.CreatorID;
5070 block.GroupID = sop.GroupID;
5071 block.LastOwnerID = sop.LastOwnerID;
5072 if (sop.OwnerID == sop.GroupID)
5073 block.OwnerID = UUID.Zero;
5074 else
5075 block.OwnerID = sop.OwnerID;
5076
5077 block.ItemID = sop.FromUserInventoryItemID;
5078 block.FolderID = UUID.Zero; // sog.FromFolderID ??
5079 block.FromTaskID = UUID.Zero; // ???
5080 block.InventorySerial = (short)sop.InventorySerial;
5081
5082 SceneObjectPart root = sop.ParentGroup.RootPart;
5083
5084 block.TouchName = Util.StringToBytes256(root.TouchName);
5085
5086 // SL 3.3.4, at least, appears to read this information as a concatenated byte[] stream of UUIDs but
5087 // it's not yet clear whether this is actually used. If this is done in the future then a pre-cached
5088 // copy is really needed since it's less efficient to be constantly recreating this byte array.
5089// using (MemoryStream memStream = new MemoryStream())
5090// {
5091// using (BinaryWriter binWriter = new BinaryWriter(memStream))
5092// {
5093// for (int i = 0; i < sop.GetNumberOfSides(); i++)
5094// {
5095// Primitive.TextureEntryFace teFace = sop.Shape.Textures.FaceTextures[i];
5096//
5097// UUID textureID;
5098//
5099// if (teFace != null)
5100// textureID = teFace.TextureID;
5101// else
5102// textureID = sop.Shape.Textures.DefaultTexture.TextureID;
5103//
5104// binWriter.Write(textureID.GetBytes());
5105// }
5106//
5107// block.TextureID = memStream.ToArray();
5108// }
5109// }
5110
5111 block.TextureID = new byte[0]; // TextureID ???
5112 block.SitName = Util.StringToBytes256(root.SitName);
5113 block.OwnerMask = root.OwnerMask;
5114 block.NextOwnerMask = root.NextOwnerMask;
5115 block.GroupMask = root.GroupMask;
5116 block.EveryoneMask = root.EveryoneMask;
5117 block.BaseMask = root.BaseMask;
5118 block.SaleType = root.ObjectSaleType;
5119 block.SalePrice = root.SalePrice;
5120
5121 return block;
5122 }
5123
5124 #region Estate Data Sending Methods
5125
5126 private static bool convertParamStringToBool(byte[] field)
5127 {
5128 string s = Utils.BytesToString(field);
5129 if (s == "1" || s.ToLower() == "y" || s.ToLower() == "yes" || s.ToLower() == "t" || s.ToLower() == "true")
5130 {
5131 return true;
5132 }
5133 return false;
5134 }
5135
5136 public void SendEstateList(UUID invoice, int code, UUID[] Data, uint estateID)
5137 {
5138 int TotalnumberIDs = Data.Length;
5139 int numberIDs;
5140 int IDIndex = 0;
5141
5142 do
5143 {
5144 if(TotalnumberIDs > 63)
5145 numberIDs = 63;
5146 else
5147 numberIDs = TotalnumberIDs;
5148
5149 TotalnumberIDs -= numberIDs;
5150
5151 EstateOwnerMessagePacket packet = new EstateOwnerMessagePacket();
5152 packet.AgentData.TransactionID = UUID.Random();
5153 packet.AgentData.AgentID = AgentId;
5154 packet.AgentData.SessionID = SessionId;
5155 packet.MethodData.Invoice = invoice;
5156 packet.MethodData.Method = Utils.StringToBytes("setaccess");
5157
5158 EstateOwnerMessagePacket.ParamListBlock[] returnblock = new EstateOwnerMessagePacket.ParamListBlock[6 + numberIDs];
5159
5160 for (int i = 0; i < (6 + numberIDs); i++)
5161 {
5162 returnblock[i] = new EstateOwnerMessagePacket.ParamListBlock();
5163 }
5164
5165 returnblock[0].Parameter = Utils.StringToBytes(estateID.ToString());
5166 returnblock[1].Parameter = Utils.StringToBytes(code.ToString());
5167
5168 if((code & 1) != 0) // allowagents
5169 returnblock[2].Parameter = Utils.StringToBytes(numberIDs.ToString());
5170 else
5171 returnblock[2].Parameter = Utils.StringToBytes("0");
5172
5173 if((code & 2) != 0) // groups
5174 returnblock[3].Parameter = Utils.StringToBytes(numberIDs.ToString());
5175 else
5176 returnblock[3].Parameter = Utils.StringToBytes("0");
5177
5178 if((code & 4) != 0) // bans
5179 returnblock[4].Parameter = Utils.StringToBytes(numberIDs.ToString());
5180 else
5181 returnblock[4].Parameter = Utils.StringToBytes("0");
5182
5183 if((code & 8) != 0) // managers
5184 returnblock[5].Parameter = Utils.StringToBytes(numberIDs.ToString());
5185 else
5186 returnblock[5].Parameter = Utils.StringToBytes("0");
5187
5188 int j = 6;
5189
5190 for (int i = 0; i < numberIDs; i++)
5191 {
5192 returnblock[j].Parameter = Data[IDIndex].GetBytes();
5193 j++;
5194 IDIndex++;
5195 }
5196 packet.ParamList = returnblock;
5197 packet.Header.Reliable = true;
5198 OutPacket(packet, ThrottleOutPacketType.Task);
5199 } while (TotalnumberIDs > 0);
5200 }
5201
5202 public void SendBannedUserList(UUID invoice, EstateBan[] bl, uint estateID)
5203 {
5204 List<UUID> BannedUsers = new List<UUID>();
5205 for (int i = 0; i < bl.Length; i++)
5206 {
5207 if (bl[i] == null)
5208 continue;
5209 if (bl[i].BannedUserID == UUID.Zero)
5210 continue;
5211 BannedUsers.Add(bl[i].BannedUserID);
5212 }
5213 SendEstateList(invoice, 4, BannedUsers.ToArray(), estateID);
5214 }
5215
5216 public void SendRegionInfoToEstateMenu(RegionInfoForEstateMenuArgs args)
5217 {
5218 RegionInfoPacket rinfopack = new RegionInfoPacket();
5219 RegionInfoPacket.RegionInfoBlock rinfoblk = new RegionInfoPacket.RegionInfoBlock();
5220 rinfopack.AgentData.AgentID = AgentId;
5221 rinfopack.AgentData.SessionID = SessionId;
5222 rinfoblk.BillableFactor = args.billableFactor;
5223 rinfoblk.EstateID = args.estateID;
5224 rinfoblk.MaxAgents = args.maxAgents;
5225 rinfoblk.ObjectBonusFactor = args.objectBonusFactor;
5226 rinfoblk.ParentEstateID = args.parentEstateID;
5227 rinfoblk.PricePerMeter = args.pricePerMeter;
5228 rinfoblk.RedirectGridX = args.redirectGridX;
5229 rinfoblk.RedirectGridY = args.redirectGridY;
5230 rinfoblk.RegionFlags = args.regionFlags;
5231 rinfoblk.SimAccess = args.simAccess;
5232 rinfoblk.SunHour = args.sunHour;
5233 rinfoblk.TerrainLowerLimit = args.terrainLowerLimit;
5234 rinfoblk.TerrainRaiseLimit = args.terrainRaiseLimit;
5235 rinfoblk.UseEstateSun = args.useEstateSun;
5236 rinfoblk.WaterHeight = args.waterHeight;
5237 rinfoblk.SimName = Utils.StringToBytes(args.simName);
5238
5239 rinfopack.RegionInfo2 = new RegionInfoPacket.RegionInfo2Block();
5240 rinfopack.RegionInfo2.HardMaxAgents = uint.MaxValue;
5241 rinfopack.RegionInfo2.HardMaxObjects = uint.MaxValue;
5242 rinfopack.RegionInfo2.MaxAgents32 = uint.MaxValue;
5243 rinfopack.RegionInfo2.ProductName = Util.StringToBytes256(args.regionType);
5244 rinfopack.RegionInfo2.ProductSKU = Utils.EmptyBytes;
5245
5246 rinfopack.HasVariableBlocks = true;
5247 rinfopack.RegionInfo = rinfoblk;
5248 rinfopack.AgentData = new RegionInfoPacket.AgentDataBlock();
5249 rinfopack.AgentData.AgentID = AgentId;
5250 rinfopack.AgentData.SessionID = SessionId;
5251 rinfopack.RegionInfo3 = new RegionInfoPacket.RegionInfo3Block[0];
5252
5253 OutPacket(rinfopack, ThrottleOutPacketType.Task);
5254 }
5255
5256 public void SendEstateCovenantInformation(UUID covenant)
5257 {
5258// m_log.DebugFormat("[LLCLIENTVIEW]: Sending estate covenant asset id of {0} to {1}", covenant, Name);
5259
5260 EstateCovenantReplyPacket einfopack = new EstateCovenantReplyPacket();
5261 EstateCovenantReplyPacket.DataBlock edata = new EstateCovenantReplyPacket.DataBlock();
5262 edata.CovenantID = covenant;
5263 edata.CovenantTimestamp = (uint) m_scene.RegionInfo.RegionSettings.CovenantChangedDateTime;
5264 edata.EstateOwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
5265 edata.EstateName = Utils.StringToBytes(m_scene.RegionInfo.EstateSettings.EstateName);
5266 einfopack.Data = edata;
5267 OutPacket(einfopack, ThrottleOutPacketType.Task);
5268 }
5269
5270 public void SendDetailedEstateData(
5271 UUID invoice, string estateName, uint estateID, uint parentEstate, uint estateFlags, uint sunPosition,
5272 UUID covenant, uint covenantChanged, string abuseEmail, UUID estateOwner)
5273 {
5274// m_log.DebugFormat(
5275// "[LLCLIENTVIEW]: Sending detailed estate data to {0} with covenant asset id {1}", Name, covenant);
5276
5277 EstateOwnerMessagePacket packet = new EstateOwnerMessagePacket();
5278 packet.MethodData.Invoice = invoice;
5279 packet.AgentData.TransactionID = UUID.Random();
5280 packet.MethodData.Method = Utils.StringToBytes("estateupdateinfo");
5281 EstateOwnerMessagePacket.ParamListBlock[] returnblock = new EstateOwnerMessagePacket.ParamListBlock[10];
5282
5283 for (int i = 0; i < 10; i++)
5284 {
5285 returnblock[i] = new EstateOwnerMessagePacket.ParamListBlock();
5286 }
5287
5288 //Sending Estate Settings
5289 returnblock[0].Parameter = Utils.StringToBytes(estateName);
5290 returnblock[1].Parameter = Utils.StringToBytes(estateOwner.ToString());
5291 returnblock[2].Parameter = Utils.StringToBytes(estateID.ToString());
5292
5293 returnblock[3].Parameter = Utils.StringToBytes(estateFlags.ToString());
5294 returnblock[4].Parameter = Utils.StringToBytes(sunPosition.ToString());
5295 returnblock[5].Parameter = Utils.StringToBytes(parentEstate.ToString());
5296 returnblock[6].Parameter = Utils.StringToBytes(covenant.ToString());
5297 returnblock[7].Parameter = Utils.StringToBytes(covenantChanged.ToString());
5298 returnblock[8].Parameter = Utils.StringToBytes("1"); // what is this?
5299 returnblock[9].Parameter = Utils.StringToBytes(abuseEmail);
5300
5301 packet.ParamList = returnblock;
5302 packet.Header.Reliable = false;
5303 //m_log.Debug("[ESTATE]: SIM--->" + packet.ToString());
5304 OutPacket(packet, ThrottleOutPacketType.Task);
5305 }
5306
5307 public void SendTelehubInfo(UUID ObjectID, string ObjectName, Vector3 ObjectPos, Quaternion ObjectRot, List<Vector3> SpawnPoint)
5308 {
5309 TelehubInfoPacket packet = (TelehubInfoPacket)PacketPool.Instance.GetPacket(PacketType.TelehubInfo);
5310 packet.TelehubBlock.ObjectID = ObjectID;
5311 packet.TelehubBlock.ObjectName = Utils.StringToBytes(ObjectName);
5312 packet.TelehubBlock.TelehubPos = ObjectPos;
5313 packet.TelehubBlock.TelehubRot = ObjectRot;
5314
5315 packet.SpawnPointBlock = new TelehubInfoPacket.SpawnPointBlockBlock[SpawnPoint.Count];
5316 for (int n = 0; n < SpawnPoint.Count; n++)
5317 {
5318 packet.SpawnPointBlock[n] = new TelehubInfoPacket.SpawnPointBlockBlock{SpawnPointPos = SpawnPoint[n]};
5319 }
5320
5321 OutPacket(packet, ThrottleOutPacketType.Task);
5322 }
5323
5324 #endregion
5325
5326 #region Land Data Sending Methods
5327
5328 public void SendLandParcelOverlay(byte[] data, int sequence_id)
5329 {
5330 ParcelOverlayPacket packet = (ParcelOverlayPacket)PacketPool.Instance.GetPacket(PacketType.ParcelOverlay);
5331 packet.ParcelData.Data = data;
5332 packet.ParcelData.SequenceID = sequence_id;
5333 packet.Header.Zerocoded = true;
5334// OutPacket(packet, ThrottleOutPacketType.Task);
5335 OutPacket(packet, ThrottleOutPacketType.Land);
5336 }
5337
5338 public void SendLandProperties(
5339 int sequence_id, bool snap_selection, int request_result, ILandObject lo,
5340 float simObjectBonusFactor, int parcelObjectCapacity, int simObjectCapacity, uint regionFlags)
5341 {
5342// m_log.DebugFormat("[LLCLIENTVIEW]: Sending land properties for {0} to {1}", lo.LandData.GlobalID, Name);
5343
5344 LandData landData = lo.LandData;
5345
5346 ParcelPropertiesMessage updateMessage = new ParcelPropertiesMessage();
5347
5348 updateMessage.AABBMax = landData.AABBMax;
5349 updateMessage.AABBMin = landData.AABBMin;
5350 updateMessage.Area = landData.Area;
5351 updateMessage.AuctionID = landData.AuctionID;
5352 updateMessage.AuthBuyerID = landData.AuthBuyerID;
5353 updateMessage.Bitmap = landData.Bitmap;
5354 updateMessage.Desc = landData.Description;
5355 updateMessage.Category = landData.Category;
5356 updateMessage.ClaimDate = Util.ToDateTime(landData.ClaimDate);
5357 updateMessage.ClaimPrice = landData.ClaimPrice;
5358 updateMessage.GroupID = landData.GroupID;
5359 updateMessage.IsGroupOwned = landData.IsGroupOwned;
5360 updateMessage.LandingType = (LandingType) landData.LandingType;
5361 updateMessage.LocalID = landData.LocalID;
5362
5363 if (landData.Area > 0)
5364 {
5365 updateMessage.MaxPrims = parcelObjectCapacity;
5366 }
5367 else
5368 {
5369 updateMessage.MaxPrims = 0;
5370 }
5371
5372 updateMessage.MediaAutoScale = Convert.ToBoolean(landData.MediaAutoScale);
5373 updateMessage.MediaID = landData.MediaID;
5374 updateMessage.MediaURL = landData.MediaURL;
5375 updateMessage.MusicURL = landData.MusicURL;
5376 updateMessage.Name = landData.Name;
5377 updateMessage.OtherCleanTime = landData.OtherCleanTime;
5378 updateMessage.OtherCount = 0; //TODO: Unimplemented
5379 updateMessage.OwnerID = landData.OwnerID;
5380 updateMessage.ParcelFlags = (ParcelFlags) landData.Flags;
5381 updateMessage.ParcelPrimBonus = simObjectBonusFactor;
5382 updateMessage.PassHours = landData.PassHours;
5383 updateMessage.PassPrice = landData.PassPrice;
5384 updateMessage.PublicCount = 0; //TODO: Unimplemented
5385
5386 updateMessage.RegionPushOverride = (regionFlags & (uint)RegionFlags.RestrictPushObject) > 0;
5387 updateMessage.RegionDenyAnonymous = (regionFlags & (uint)RegionFlags.DenyAnonymous) > 0;
5388
5389 //updateMessage.RegionDenyIdentified = (regionFlags & (uint)RegionFlags.DenyIdentified) > 0;
5390 //updateMessage.RegionDenyTransacted = (regionFlags & (uint)RegionFlags.DenyTransacted) > 0;
5391
5392 updateMessage.RentPrice = 0;
5393 updateMessage.RequestResult = (ParcelResult) request_result;
5394 updateMessage.SalePrice = landData.SalePrice;
5395 updateMessage.SelfCount = 0; //TODO: Unimplemented
5396 updateMessage.SequenceID = sequence_id;
5397
5398 if (landData.SimwideArea > 0)
5399 {
5400 updateMessage.SimWideMaxPrims = lo.GetSimulatorMaxPrimCount();
5401 }
5402 else
5403 {
5404 updateMessage.SimWideMaxPrims = 0;
5405 }
5406
5407 updateMessage.SnapSelection = snap_selection;
5408 updateMessage.SnapshotID = landData.SnapshotID;
5409 updateMessage.Status = (ParcelStatus) landData.Status;
5410 updateMessage.UserLocation = landData.UserLocation;
5411 updateMessage.UserLookAt = landData.UserLookAt;
5412
5413 updateMessage.MediaType = landData.MediaType;
5414 updateMessage.MediaDesc = landData.MediaDescription;
5415 updateMessage.MediaWidth = landData.MediaWidth;
5416 updateMessage.MediaHeight = landData.MediaHeight;
5417 updateMessage.MediaLoop = landData.MediaLoop;
5418 updateMessage.ObscureMusic = landData.ObscureMusic;
5419 updateMessage.ObscureMedia = landData.ObscureMedia;
5420
5421 updateMessage.SeeAVs = landData.SeeAVs;
5422 updateMessage.AnyAVSounds = landData.AnyAVSounds;
5423 updateMessage.GroupAVSounds = landData.GroupAVSounds;
5424
5425 IPrimCounts pc = lo.PrimCounts;
5426 updateMessage.OwnerPrims = pc.Owner;
5427 updateMessage.GroupPrims = pc.Group;
5428 updateMessage.OtherPrims = pc.Others;
5429 updateMessage.SelectedPrims = pc.Selected;
5430 updateMessage.TotalPrims = pc.Total;
5431 updateMessage.SimWideTotalPrims = pc.Simulator;
5432
5433 //m_log.DebugFormat("[YYY]: SimWideMaxPrims={0} OwnerPrims={1} TotalPrims={2} SimWideTotalPrims={3} MaxPrims={4}",
5434 // updateMessage.SimWideMaxPrims, updateMessage.OwnerPrims, updateMessage.TotalPrims, updateMessage.SimWideTotalPrims, updateMessage.MaxPrims);
5435 try
5436 {
5437 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>();
5438 if (eq != null)
5439 {
5440 eq.ParcelProperties(updateMessage, this.AgentId);
5441 }
5442 else
5443 {
5444 m_log.Warn("[LLCLIENTVIEW]: No EQ Interface when sending parcel data.");
5445 }
5446 }
5447 catch (Exception ex)
5448 {
5449 m_log.Error("[LLCLIENTVIEW]: Unable to send parcel data via eventqueue - exception: " + ex.ToString());
5450 }
5451 }
5452
5453 public void SendLandAccessListData(List<LandAccessEntry> accessList, uint accessFlag, int localLandID)
5454 {
5455 ParcelAccessListReplyPacket replyPacket = (ParcelAccessListReplyPacket)PacketPool.Instance.GetPacket(PacketType.ParcelAccessListReply);
5456 replyPacket.Data.AgentID = AgentId;
5457 replyPacket.Data.Flags = accessFlag;
5458 replyPacket.Data.LocalID = localLandID;
5459 replyPacket.Data.SequenceID = 0;
5460
5461 List<ParcelAccessListReplyPacket.ListBlock> list = new List<ParcelAccessListReplyPacket.ListBlock>();
5462 foreach (LandAccessEntry entry in accessList)
5463 {
5464 ParcelAccessListReplyPacket.ListBlock block = new ParcelAccessListReplyPacket.ListBlock();
5465 block.Flags = accessFlag;
5466 block.ID = entry.AgentID;
5467 block.Time = entry.Expires;
5468 list.Add(block);
5469 }
5470
5471 replyPacket.List = list.ToArray();
5472 replyPacket.Header.Zerocoded = true;
5473 OutPacket(replyPacket, ThrottleOutPacketType.Task);
5474 }
5475
5476 public void SendForceClientSelectObjects(List<uint> ObjectIDs)
5477 {
5478// m_log.DebugFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count);
5479
5480 bool firstCall = true;
5481 const int MAX_OBJECTS_PER_PACKET = 251;
5482 ForceObjectSelectPacket pack = (ForceObjectSelectPacket)PacketPool.Instance.GetPacket(PacketType.ForceObjectSelect);
5483 ForceObjectSelectPacket.DataBlock[] data;
5484 while (ObjectIDs.Count > 0)
5485 {
5486 if (firstCall)
5487 {
5488 pack._Header.ResetList = true;
5489 firstCall = false;
5490 }
5491 else
5492 {
5493 pack._Header.ResetList = false;
5494 }
5495
5496 if (ObjectIDs.Count > MAX_OBJECTS_PER_PACKET)
5497 {
5498 data = new ForceObjectSelectPacket.DataBlock[MAX_OBJECTS_PER_PACKET];
5499 }
5500 else
5501 {
5502 data = new ForceObjectSelectPacket.DataBlock[ObjectIDs.Count];
5503 }
5504
5505 int i;
5506 for (i = 0; i < MAX_OBJECTS_PER_PACKET && ObjectIDs.Count > 0; i++)
5507 {
5508 data[i] = new ForceObjectSelectPacket.DataBlock();
5509 data[i].LocalID = Convert.ToUInt32(ObjectIDs[0]);
5510 ObjectIDs.RemoveAt(0);
5511 }
5512 pack.Data = data;
5513 pack.Header.Zerocoded = true;
5514 OutPacket(pack, ThrottleOutPacketType.Task);
5515 }
5516 }
5517
5518 public void SendCameraConstraint(Vector4 ConstraintPlane)
5519 {
5520 CameraConstraintPacket cpack = (CameraConstraintPacket)PacketPool.Instance.GetPacket(PacketType.CameraConstraint);
5521 cpack.CameraCollidePlane = new CameraConstraintPacket.CameraCollidePlaneBlock();
5522 cpack.CameraCollidePlane.Plane = ConstraintPlane;
5523 //m_log.DebugFormat("[CLIENTVIEW]: Constraint {0}", ConstraintPlane);
5524 OutPacket(cpack, ThrottleOutPacketType.Task);
5525 }
5526
5527 public void SendLandObjectOwners(LandData land, List<UUID> groups, Dictionary<UUID, int> ownersAndCount)
5528 {
5529 int notifyCount = ownersAndCount.Count;
5530 ParcelObjectOwnersReplyPacket pack = (ParcelObjectOwnersReplyPacket)PacketPool.Instance.GetPacket(PacketType.ParcelObjectOwnersReply);
5531
5532 if (notifyCount > 0)
5533 {
5534// if (notifyCount > 32)
5535// {
5536// m_log.InfoFormat(
5537// "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}"
5538// + " - a developer might want to investigate whether this is a hard limit", 32);
5539//
5540// notifyCount = 32;
5541// }
5542
5543 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock
5544 = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount];
5545
5546 int num = 0;
5547 foreach (UUID owner in ownersAndCount.Keys)
5548 {
5549 dataBlock[num] = new ParcelObjectOwnersReplyPacket.DataBlock();
5550 dataBlock[num].Count = ownersAndCount[owner];
5551
5552 if (land.GroupID == owner || groups.Contains(owner))
5553 dataBlock[num].IsGroupOwned = true;
5554
5555 dataBlock[num].OnlineStatus = true; //TODO: fix me later
5556 dataBlock[num].OwnerID = owner;
5557
5558 num++;
5559
5560 if (num >= notifyCount)
5561 {
5562 break;
5563 }
5564 }
5565
5566 pack.Data = dataBlock;
5567 }
5568 else
5569 {
5570 pack.Data = new ParcelObjectOwnersReplyPacket.DataBlock[0];
5571 }
5572 pack.Header.Zerocoded = true;
5573 this.OutPacket(pack, ThrottleOutPacketType.Task);
5574 }
5575
5576 #endregion
5577
5578 #region Helper Methods
5579 private void ClampVectorForUint(ref Vector3 v, float max)
5580 {
5581 float a,b;
5582
5583 a = Math.Abs(v.X);
5584 b = Math.Abs(v.Y);
5585 if(b > a)
5586 a = b;
5587 b= Math.Abs(v.Z);
5588 if(b > a)
5589 a = b;
5590
5591 if (a > max)
5592 {
5593 a = max / a;
5594 v.X *= a;
5595 v.Y *= a;
5596 v.Z *= a;
5597 }
5598 }
5599
5600 protected ImprovedTerseObjectUpdatePacket.ObjectDataBlock CreateImprovedTerseBlock(ISceneEntity entity, bool sendTexture)
5601 {
5602 #region ScenePresence/SOP Handling
5603
5604 bool avatar = (entity is ScenePresence);
5605 uint localID = entity.LocalId;
5606 uint attachPoint;
5607 Vector4 collisionPlane;
5608 Vector3 position, velocity, acceleration, angularVelocity;
5609 Quaternion rotation;
5610 byte[] textureEntry;
5611
5612 if (avatar)
5613 {
5614 ScenePresence presence = (ScenePresence)entity;
5615
5616 position = presence.OffsetPosition;
5617 velocity = presence.Velocity;
5618 acceleration = Vector3.Zero;
5619 rotation = presence.Rotation;
5620 // tpvs can only see rotations around Z in some cases
5621 if(!presence.Flying && !presence.IsSatOnObject)
5622 {
5623 rotation.X = 0f;
5624 rotation.Y = 0f;
5625 rotation.Normalize();
5626 }
5627 angularVelocity = presence.AngularVelocity;
5628
5629// m_log.DebugFormat(
5630// "[LLCLIENTVIEW]: Sending terse update to {0} with position {1} in {2}", Name, presence.OffsetPosition, m_scene.Name);
5631
5632 attachPoint = presence.State;
5633 collisionPlane = presence.CollisionPlane;
5634
5635 if (sendTexture)
5636 {
5637 textureEntry = presence.Appearance.Texture.GetBytes();
5638 }
5639 else
5640 textureEntry = null;
5641 }
5642 else
5643 {
5644 SceneObjectPart part = (SceneObjectPart)entity;
5645
5646 attachPoint = part.ParentGroup.AttachmentPoint;
5647 attachPoint = ((attachPoint % 16) * 16 + (attachPoint / 16));
5648// m_log.DebugFormat(
5649// "[LLCLIENTVIEW]: Sending attachPoint {0} for {1} {2} to {3}",
5650// attachPoint, part.Name, part.LocalId, Name);
5651
5652 collisionPlane = Vector4.Zero;
5653 position = part.RelativePosition;
5654 velocity = part.Velocity;
5655 acceleration = part.Acceleration;
5656 angularVelocity = part.AngularVelocity;
5657 rotation = part.RotationOffset;
5658
5659 if (sendTexture)
5660 textureEntry = part.Shape.TextureEntry;
5661 else
5662 textureEntry = null;
5663 }
5664
5665 #endregion ScenePresence/SOP Handling
5666
5667 int pos = 0;
5668 byte[] data = new byte[(avatar ? 60 : 44)];
5669
5670 // LocalID
5671 Utils.UIntToBytes(localID, data, pos);
5672 pos += 4;
5673
5674 // Avatar/CollisionPlane
5675 data[pos++] = (byte) attachPoint;
5676 if (avatar)
5677 {
5678 data[pos++] = 1;
5679
5680 if (collisionPlane == Vector4.Zero)
5681 collisionPlane = Vector4.UnitW;
5682 //m_log.DebugFormat("CollisionPlane: {0}",collisionPlane);
5683 collisionPlane.ToBytes(data, pos);
5684 pos += 16;
5685 }
5686 else
5687 {
5688 ++pos;
5689 }
5690
5691 // Position
5692 position.ToBytes(data, pos);
5693 pos += 12;
5694
5695 // Velocity
5696 ClampVectorForUint(ref velocity, 128f);
5697 Utils.UInt16ToBytes(Utils.FloatToUInt16(velocity.X, -128.0f, 128.0f), data, pos); pos += 2;
5698 Utils.UInt16ToBytes(Utils.FloatToUInt16(velocity.Y, -128.0f, 128.0f), data, pos); pos += 2;
5699 Utils.UInt16ToBytes(Utils.FloatToUInt16(velocity.Z, -128.0f, 128.0f), data, pos); pos += 2;
5700
5701 // Acceleration
5702 ClampVectorForUint(ref acceleration, 64f);
5703 Utils.UInt16ToBytes(Utils.FloatToUInt16(acceleration.X, -64.0f, 64.0f), data, pos); pos += 2;
5704 Utils.UInt16ToBytes(Utils.FloatToUInt16(acceleration.Y, -64.0f, 64.0f), data, pos); pos += 2;
5705 Utils.UInt16ToBytes(Utils.FloatToUInt16(acceleration.Z, -64.0f, 64.0f), data, pos); pos += 2;
5706
5707 // Rotation
5708 Utils.UInt16ToBytes(Utils.FloatToUInt16(rotation.X, -1.0f, 1.0f), data, pos); pos += 2;
5709 Utils.UInt16ToBytes(Utils.FloatToUInt16(rotation.Y, -1.0f, 1.0f), data, pos); pos += 2;
5710 Utils.UInt16ToBytes(Utils.FloatToUInt16(rotation.Z, -1.0f, 1.0f), data, pos); pos += 2;
5711 Utils.UInt16ToBytes(Utils.FloatToUInt16(rotation.W, -1.0f, 1.0f), data, pos); pos += 2;
5712
5713 // Angular Velocity
5714 ClampVectorForUint(ref angularVelocity, 64f);
5715 Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.X, -64.0f, 64.0f), data, pos); pos += 2;
5716 Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Y, -64.0f, 64.0f), data, pos); pos += 2;
5717 Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Z, -64.0f, 64.0f), data, pos); pos += 2;
5718
5719 ImprovedTerseObjectUpdatePacket.ObjectDataBlock block
5720 = PacketPool.Instance.GetDataBlock<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>();
5721
5722 block.Data = data;
5723
5724 if (textureEntry != null && textureEntry.Length > 0)
5725 {
5726 byte[] teBytesFinal = new byte[textureEntry.Length + 4];
5727
5728 // Texture Length
5729 Utils.IntToBytes(textureEntry.Length, textureEntry, 0);
5730 // Texture
5731 Buffer.BlockCopy(textureEntry, 0, teBytesFinal, 4, textureEntry.Length);
5732
5733 block.TextureEntry = teBytesFinal;
5734 }
5735 else
5736 {
5737 block.TextureEntry = Utils.EmptyBytes;
5738 }
5739
5740 return block;
5741 }
5742
5743 protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(ScenePresence data)
5744 {
5745 Vector3 offsetPosition = data.OffsetPosition;
5746 Quaternion rotation = data.Rotation;
5747 uint parentID = data.ParentID;
5748
5749// m_log.DebugFormat(
5750// "[LLCLIENTVIEW]: Sending full update to {0} with pos {1}, vel {2} in {3}", Name, data.OffsetPosition, data.Velocity, m_scene.Name);
5751
5752 byte[] objectData = new byte[76];
5753
5754 Vector3 velocity = new Vector3(0, 0, 0);
5755 Vector3 acceleration = new Vector3(0, 0, 0);
5756 // tpvs can only see rotations around Z in some cases
5757 if(!data.Flying && !data.IsSatOnObject)
5758 {
5759 rotation.X = 0f;
5760 rotation.Y = 0f;
5761 }
5762 rotation.Normalize();
5763
5764 data.CollisionPlane.ToBytes(objectData, 0);
5765 offsetPosition.ToBytes(objectData, 16);
5766 velocity.ToBytes(objectData, 28);
5767 acceleration.ToBytes(objectData, 40);
5768 rotation.ToBytes(objectData, 52);
5769 data.AngularVelocity.ToBytes(objectData, 64);
5770
5771 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock();
5772
5773 update.Data = Utils.EmptyBytes;
5774 update.ExtraParams = new byte[1];
5775 update.FullID = data.UUID;
5776 update.ID = data.LocalId;
5777 update.Material = (byte)Material.Flesh;
5778 update.MediaURL = Utils.EmptyBytes;
5779 update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " +
5780 data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle);
5781 update.ObjectData = objectData;
5782
5783 SceneObjectPart parentPart = data.ParentPart;
5784 if (parentPart != null)
5785 update.ParentID = parentPart.ParentGroup.LocalId;
5786 else
5787 update.ParentID = 0;
5788
5789 update.PathCurve = 16;
5790 update.PathScaleX = 100;
5791 update.PathScaleY = 100;
5792 update.PCode = (byte)PCode.Avatar;
5793 update.ProfileCurve = 1;
5794 update.PSBlock = Utils.EmptyBytes;
5795 update.Scale = data.Appearance.AvatarSize;
5796// update.Scale.Z -= 0.2f;
5797
5798 update.Text = Utils.EmptyBytes;
5799 update.TextColor = new byte[4];
5800
5801 // Don't send texture anim for avatars - this has no meaning for them.
5802 update.TextureAnim = Utils.EmptyBytes;
5803
5804 // Don't send texture entry for avatars here - this is accomplished via the AvatarAppearance packet
5805 update.TextureEntry = Utils.EmptyBytes;
5806// update.TextureEntry = (data.Appearance.Texture != null) ? data.Appearance.Texture.GetBytes() : Utils.EmptyBytes;
5807
5808/* all this flags seem related to prims and not avatars. This allow for wrong viewer side move of a avatar in prim edition mode (anv mantis 854)
5809 update.UpdateFlags = (uint)(
5810 PrimFlags.Physics | PrimFlags.ObjectModify | PrimFlags.ObjectCopy | PrimFlags.ObjectAnyOwner |
5811 PrimFlags.ObjectYouOwner | PrimFlags.ObjectMove | PrimFlags.InventoryEmpty | PrimFlags.ObjectTransfer |
5812 PrimFlags.ObjectOwnerModify);
5813*/
5814 update.UpdateFlags = 0;
5815
5816 return update;
5817 }
5818
5819// protected ObjectUpdatePacket.ObjectDataBlock CreatePrimUpdateBlock(SceneObjectPart data, UUID recipientID)
5820 protected ObjectUpdatePacket.ObjectDataBlock CreatePrimUpdateBlock(SceneObjectPart part, ScenePresence sp)
5821 {
5822 byte[] objectData = new byte[60];
5823 part.RelativePosition.ToBytes(objectData, 0);
5824 part.Velocity.ToBytes(objectData, 12);
5825 part.Acceleration.ToBytes(objectData, 24);
5826
5827 Quaternion rotation = part.RotationOffset;
5828 rotation.Normalize();
5829 rotation.ToBytes(objectData, 36);
5830 part.AngularVelocity.ToBytes(objectData, 48);
5831
5832 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock();
5833 update.ClickAction = (byte)part.ClickAction;
5834 update.CRC = 0;
5835 update.ExtraParams = part.Shape.ExtraParams ?? Utils.EmptyBytes;
5836 update.FullID = part.UUID;
5837 update.ID = part.LocalId;
5838 //update.JointAxisOrAnchor = Vector3.Zero; // These are deprecated
5839 //update.JointPivot = Vector3.Zero;
5840 //update.JointType = 0;
5841 update.Material = part.Material;
5842/*
5843 if (data.ParentGroup.IsAttachment)
5844 {
5845 update.NameValue
5846 = Util.StringToBytes256(
5847 string.Format("AttachItemID STRING RW SV {0}", data.ParentGroup.FromItemID));
5848
5849 update.State = (byte)((data.ParentGroup.AttachmentPoint % 16) * 16 + (data.ParentGroup.AttachmentPoint / 16));
5850
5851// m_log.DebugFormat(
5852// "[LLCLIENTVIEW]: Sending NameValue {0} for {1} {2} to {3}",
5853// Util.UTF8.GetString(update.NameValue), data.Name, data.LocalId, Name);
5854//
5855// m_log.DebugFormat(
5856// "[LLCLIENTVIEW]: Sending state {0} for {1} {2} to {3}",
5857// update.State, data.Name, data.LocalId, Name);
5858 }
5859 else
5860 {
5861 update.NameValue = Utils.EmptyBytes;
5862
5863 // The root part state is the canonical state for all parts of the object. The other part states in the
5864 // case for attachments may contain conflicting values that can end up crashing the viewer.
5865 update.State = data.ParentGroup.RootPart.Shape.State;
5866 }
5867*/
5868
5869 if (part.ParentGroup.IsAttachment)
5870 {
5871 if (part.IsRoot)
5872 {
5873 update.NameValue = Util.StringToBytes256("AttachItemID STRING RW SV " + part.ParentGroup.FromItemID);
5874 }
5875 else
5876 update.NameValue = Utils.EmptyBytes;
5877
5878 int st = (int)part.ParentGroup.AttachmentPoint;
5879 update.State = (byte)(((st & 0xf0) >> 4) + ((st & 0x0f) << 4)); ;
5880 }
5881 else
5882 {
5883 update.NameValue = Utils.EmptyBytes;
5884 update.State = part.Shape.State; // not sure about this
5885 }
5886
5887 update.ObjectData = objectData;
5888 update.ParentID = part.ParentID;
5889 update.PathBegin = part.Shape.PathBegin;
5890 update.PathCurve = part.Shape.PathCurve;
5891 update.PathEnd = part.Shape.PathEnd;
5892 update.PathRadiusOffset = part.Shape.PathRadiusOffset;
5893 update.PathRevolutions = part.Shape.PathRevolutions;
5894 update.PathScaleX = part.Shape.PathScaleX;
5895 update.PathScaleY = part.Shape.PathScaleY;
5896 update.PathShearX = part.Shape.PathShearX;
5897 update.PathShearY = part.Shape.PathShearY;
5898 update.PathSkew = part.Shape.PathSkew;
5899 update.PathTaperX = part.Shape.PathTaperX;
5900 update.PathTaperY = part.Shape.PathTaperY;
5901 update.PathTwist = part.Shape.PathTwist;
5902 update.PathTwistBegin = part.Shape.PathTwistBegin;
5903 update.PCode = part.Shape.PCode;
5904 update.ProfileBegin = part.Shape.ProfileBegin;
5905 update.ProfileCurve = part.Shape.ProfileCurve;
5906
5907 ushort profileBegin = part.Shape.ProfileBegin;
5908 ushort profileHollow = part.Shape.ProfileHollow;
5909
5910 if(part.Shape.SculptType == (byte)SculptType.Mesh) // filter out hack
5911 {
5912 update.ProfileCurve = (byte)(part.Shape.ProfileCurve & 0x0f);
5913 // fix old values that confused viewers
5914 if(profileBegin == 1)
5915 profileBegin = 9375;
5916 if(profileHollow == 1)
5917 profileHollow = 27500;
5918 // fix torus hole size Y that also confuse some viewers
5919 if(update.ProfileCurve == (byte)ProfileShape.Circle && update.PathScaleY < 150)
5920 update.PathScaleY = 150;
5921 }
5922 else
5923 {
5924 update.ProfileCurve = part.Shape.ProfileCurve;
5925 }
5926
5927 update.ProfileHollow = profileHollow;
5928 update.ProfileBegin = profileBegin;
5929 update.ProfileEnd = part.Shape.ProfileEnd;
5930 update.PSBlock = part.ParticleSystem ?? Utils.EmptyBytes;
5931 update.TextColor = part.GetTextColor().GetBytes(false);
5932 update.TextureAnim = part.TextureAnimation ?? Utils.EmptyBytes;
5933 update.TextureEntry = part.Shape.TextureEntry ?? Utils.EmptyBytes;
5934 update.Scale = part.Shape.Scale;
5935 update.Text = Util.StringToBytes(part.Text, 255);
5936 update.MediaURL = Util.StringToBytes(part.MediaUrl, 255);
5937
5938 #region PrimFlags
5939
5940 PrimFlags flags = (PrimFlags)m_scene.Permissions.GenerateClientFlags(part, sp);
5941
5942 // Don't send the CreateSelected flag to everyone
5943 flags &= ~PrimFlags.CreateSelected;
5944
5945 if (sp.UUID == part.OwnerID)
5946 {
5947 if (part.CreateSelected)
5948 {
5949 // Only send this flag once, then unset it
5950 flags |= PrimFlags.CreateSelected;
5951 part.CreateSelected = false;
5952 }
5953 }
5954
5955// m_log.DebugFormat(
5956// "[LLCLIENTVIEW]: Constructing client update for part {0} {1} with flags {2}, localId {3}",
5957// data.Name, update.FullID, flags, update.ID);
5958
5959 update.UpdateFlags = (uint)flags;
5960
5961 #endregion PrimFlags
5962
5963 if (part.Sound != UUID.Zero)
5964 {
5965 update.Sound = part.Sound;
5966 update.OwnerID = part.OwnerID;
5967 update.Gain = (float)part.SoundGain;
5968 update.Radius = (float)part.SoundRadius;
5969 update.Flags = part.SoundFlags;
5970 }
5971
5972 switch ((PCode)part.Shape.PCode)
5973 {
5974 case PCode.Grass:
5975 case PCode.Tree:
5976 case PCode.NewTree:
5977 update.Data = new byte[] { part.Shape.State };
5978 break;
5979 default:
5980 update.Data = Utils.EmptyBytes;
5981 break;
5982 }
5983
5984 return update;
5985 }
5986
5987 protected ObjectUpdateCompressedPacket.ObjectDataBlock CreateCompressedUpdateBlock(SceneObjectPart part, PrimUpdateFlags updateFlags)
5988 {
5989 // TODO: Implement this
5990 return null;
5991 }
5992
5993 public void SendNameReply(UUID profileId, string firstname, string lastname)
5994 {
5995 UUIDNameReplyPacket packet = (UUIDNameReplyPacket)PacketPool.Instance.GetPacket(PacketType.UUIDNameReply);
5996 // TODO: don't create new blocks if recycling an old packet
5997 packet.UUIDNameBlock = new UUIDNameReplyPacket.UUIDNameBlockBlock[1];
5998 packet.UUIDNameBlock[0] = new UUIDNameReplyPacket.UUIDNameBlockBlock();
5999 packet.UUIDNameBlock[0].ID = profileId;
6000 packet.UUIDNameBlock[0].FirstName = Util.StringToBytes256(firstname);
6001 packet.UUIDNameBlock[0].LastName = Util.StringToBytes256(lastname);
6002
6003 OutPacket(packet, ThrottleOutPacketType.Task);
6004 }
6005
6006 public Dictionary<UUID, ulong> GetGroupPowers()
6007 {
6008 lock(m_groupPowers)
6009 {
6010 return new Dictionary<UUID, ulong>(m_groupPowers);
6011 }
6012 }
6013
6014 public void SetGroupPowers(Dictionary<UUID, ulong> powers)
6015 {
6016 lock(m_groupPowers)
6017 {
6018 m_groupPowers.Clear();
6019 m_groupPowers = powers;
6020 }
6021 }
6022
6023 public ulong GetGroupPowers(UUID groupID)
6024 {
6025 lock(m_groupPowers)
6026 {
6027 if (m_groupPowers.ContainsKey(groupID))
6028 return m_groupPowers[groupID];
6029 }
6030 return 0;
6031 }
6032
6033 #endregion
6034
6035 /// <summary>
6036 /// This is a different way of processing packets then ProcessInPacket
6037 /// </summary>
6038 protected virtual void RegisterLocalPacketHandlers()
6039 {
6040 AddLocalPacketHandler(PacketType.LogoutRequest, HandleLogout);
6041
6042 // If AgentUpdate is ever handled asynchronously, then we will also need to construct a new AgentUpdateArgs
6043 // for each AgentUpdate packet.
6044 AddLocalPacketHandler(PacketType.AgentUpdate, HandleAgentUpdate, false);
6045
6046 AddLocalPacketHandler(PacketType.ViewerEffect, HandleViewerEffect, false);
6047 AddLocalPacketHandler(PacketType.VelocityInterpolateOff, HandleVelocityInterpolateOff, false);
6048 AddLocalPacketHandler(PacketType.VelocityInterpolateOn, HandleVelocityInterpolateOn, false);
6049 AddLocalPacketHandler(PacketType.AgentCachedTexture, HandleAgentTextureCached, false);
6050 AddLocalPacketHandler(PacketType.MultipleObjectUpdate, HandleMultipleObjUpdate, false);
6051 AddLocalPacketHandler(PacketType.MoneyTransferRequest, HandleMoneyTransferRequest, false);
6052 AddLocalPacketHandler(PacketType.ParcelBuy, HandleParcelBuyRequest, false);
6053 AddLocalPacketHandler(PacketType.UUIDGroupNameRequest, HandleUUIDGroupNameRequest);
6054 AddLocalPacketHandler(PacketType.ObjectGroup, HandleObjectGroupRequest);
6055 AddLocalPacketHandler(PacketType.GenericMessage, HandleGenericMessage);
6056 AddLocalPacketHandler(PacketType.AvatarPropertiesRequest, HandleAvatarPropertiesRequest);
6057 AddLocalPacketHandler(PacketType.ChatFromViewer, HandleChatFromViewer);
6058 AddLocalPacketHandler(PacketType.AvatarPropertiesUpdate, HandlerAvatarPropertiesUpdate);
6059 AddLocalPacketHandler(PacketType.ScriptDialogReply, HandlerScriptDialogReply);
6060 AddLocalPacketHandler(PacketType.ImprovedInstantMessage, HandlerImprovedInstantMessage);
6061 AddLocalPacketHandler(PacketType.AcceptFriendship, HandlerAcceptFriendship);
6062 AddLocalPacketHandler(PacketType.DeclineFriendship, HandlerDeclineFriendship);
6063 AddLocalPacketHandler(PacketType.TerminateFriendship, HandlerTerminateFriendship);
6064 AddLocalPacketHandler(PacketType.RezObject, HandlerRezObject);
6065 AddLocalPacketHandler(PacketType.DeRezObject, HandlerDeRezObject);
6066 AddLocalPacketHandler(PacketType.RezRestoreToWorld, HandlerRezRestoreToWorld);
6067 AddLocalPacketHandler(PacketType.ModifyLand, HandlerModifyLand);
6068 AddLocalPacketHandler(PacketType.RegionHandshakeReply, HandlerRegionHandshakeReply, false);
6069 AddLocalPacketHandler(PacketType.AgentWearablesRequest, HandlerAgentWearablesRequest);
6070 AddLocalPacketHandler(PacketType.AgentSetAppearance, HandlerAgentSetAppearance);
6071 AddLocalPacketHandler(PacketType.AgentIsNowWearing, HandlerAgentIsNowWearing);
6072 AddLocalPacketHandler(PacketType.RezSingleAttachmentFromInv, HandlerRezSingleAttachmentFromInv);
6073 AddLocalPacketHandler(PacketType.RezMultipleAttachmentsFromInv, HandleRezMultipleAttachmentsFromInv);
6074 AddLocalPacketHandler(PacketType.DetachAttachmentIntoInv, HandleDetachAttachmentIntoInv);
6075 AddLocalPacketHandler(PacketType.ObjectAttach, HandleObjectAttach);
6076 AddLocalPacketHandler(PacketType.ObjectDetach, HandleObjectDetach);
6077 AddLocalPacketHandler(PacketType.ObjectDrop, HandleObjectDrop);
6078 AddLocalPacketHandler(PacketType.SetAlwaysRun, HandleSetAlwaysRun, false);
6079 AddLocalPacketHandler(PacketType.CompleteAgentMovement, HandleCompleteAgentMovement);
6080 AddLocalPacketHandler(PacketType.AgentAnimation, HandleAgentAnimation, false);
6081 AddLocalPacketHandler(PacketType.AgentRequestSit, HandleAgentRequestSit);
6082 AddLocalPacketHandler(PacketType.AgentSit, HandleAgentSit);
6083 AddLocalPacketHandler(PacketType.SoundTrigger, HandleSoundTrigger);
6084 AddLocalPacketHandler(PacketType.AvatarPickerRequest, HandleAvatarPickerRequest);
6085 AddLocalPacketHandler(PacketType.AgentDataUpdateRequest, HandleAgentDataUpdateRequest);
6086 AddLocalPacketHandler(PacketType.UserInfoRequest, HandleUserInfoRequest);
6087 AddLocalPacketHandler(PacketType.UpdateUserInfo, HandleUpdateUserInfo);
6088 AddLocalPacketHandler(PacketType.SetStartLocationRequest, HandleSetStartLocationRequest);
6089 AddLocalPacketHandler(PacketType.AgentThrottle, HandleAgentThrottle, false);
6090 AddLocalPacketHandler(PacketType.AgentPause, HandleAgentPause, false);
6091 AddLocalPacketHandler(PacketType.AgentResume, HandleAgentResume, false);
6092 AddLocalPacketHandler(PacketType.ForceScriptControlRelease, HandleForceScriptControlRelease);
6093 AddLocalPacketHandler(PacketType.ObjectLink, HandleObjectLink);
6094 AddLocalPacketHandler(PacketType.ObjectDelink, HandleObjectDelink);
6095 AddLocalPacketHandler(PacketType.ObjectAdd, HandleObjectAdd);
6096 AddLocalPacketHandler(PacketType.ObjectShape, HandleObjectShape);
6097 AddLocalPacketHandler(PacketType.ObjectExtraParams, HandleObjectExtraParams);
6098 AddLocalPacketHandler(PacketType.ObjectDuplicate, HandleObjectDuplicate);
6099 AddLocalPacketHandler(PacketType.RequestMultipleObjects, HandleRequestMultipleObjects);
6100 AddLocalPacketHandler(PacketType.ObjectSelect, HandleObjectSelect);
6101 AddLocalPacketHandler(PacketType.ObjectDeselect, HandleObjectDeselect);
6102 AddLocalPacketHandler(PacketType.ObjectPosition, HandleObjectPosition);
6103 AddLocalPacketHandler(PacketType.ObjectScale, HandleObjectScale);
6104 AddLocalPacketHandler(PacketType.ObjectRotation, HandleObjectRotation);
6105 AddLocalPacketHandler(PacketType.ObjectFlagUpdate, HandleObjectFlagUpdate);
6106
6107 // Handle ObjectImage (TextureEntry) updates synchronously, since when updating multiple prim faces at once,
6108 // some clients will send out a separate ObjectImage packet for each face
6109 AddLocalPacketHandler(PacketType.ObjectImage, HandleObjectImage, false);
6110
6111 AddLocalPacketHandler(PacketType.ObjectGrab, HandleObjectGrab, false);
6112 AddLocalPacketHandler(PacketType.ObjectGrabUpdate, HandleObjectGrabUpdate, false);
6113 AddLocalPacketHandler(PacketType.ObjectDeGrab, HandleObjectDeGrab);
6114 AddLocalPacketHandler(PacketType.ObjectSpinStart, HandleObjectSpinStart, false);
6115 AddLocalPacketHandler(PacketType.ObjectSpinUpdate, HandleObjectSpinUpdate, false);
6116 AddLocalPacketHandler(PacketType.ObjectSpinStop, HandleObjectSpinStop, false);
6117 AddLocalPacketHandler(PacketType.ObjectDescription, HandleObjectDescription, false);
6118 AddLocalPacketHandler(PacketType.ObjectName, HandleObjectName, false);
6119 AddLocalPacketHandler(PacketType.ObjectPermissions, HandleObjectPermissions, false);
6120 AddLocalPacketHandler(PacketType.Undo, HandleUndo, false);
6121 AddLocalPacketHandler(PacketType.UndoLand, HandleLandUndo, false);
6122 AddLocalPacketHandler(PacketType.Redo, HandleRedo, false);
6123 AddLocalPacketHandler(PacketType.ObjectDuplicateOnRay, HandleObjectDuplicateOnRay);
6124 AddLocalPacketHandler(PacketType.RequestObjectPropertiesFamily, HandleRequestObjectPropertiesFamily, false);
6125 AddLocalPacketHandler(PacketType.ObjectIncludeInSearch, HandleObjectIncludeInSearch);
6126 AddLocalPacketHandler(PacketType.ScriptAnswerYes, HandleScriptAnswerYes, false);
6127 AddLocalPacketHandler(PacketType.ObjectClickAction, HandleObjectClickAction, false);
6128 AddLocalPacketHandler(PacketType.ObjectMaterial, HandleObjectMaterial, false);
6129 AddLocalPacketHandler(PacketType.RequestImage, HandleRequestImage, false);
6130 AddLocalPacketHandler(PacketType.TransferRequest, HandleTransferRequest, false);
6131 AddLocalPacketHandler(PacketType.AssetUploadRequest, HandleAssetUploadRequest);
6132 AddLocalPacketHandler(PacketType.RequestXfer, HandleRequestXfer);
6133 AddLocalPacketHandler(PacketType.SendXferPacket, HandleSendXferPacket);
6134 AddLocalPacketHandler(PacketType.ConfirmXferPacket, HandleConfirmXferPacket);
6135 AddLocalPacketHandler(PacketType.AbortXfer, HandleAbortXfer);
6136 AddLocalPacketHandler(PacketType.CreateInventoryFolder, HandleCreateInventoryFolder);
6137 AddLocalPacketHandler(PacketType.UpdateInventoryFolder, HandleUpdateInventoryFolder);
6138 AddLocalPacketHandler(PacketType.MoveInventoryFolder, HandleMoveInventoryFolder);
6139 AddLocalPacketHandler(PacketType.CreateInventoryItem, HandleCreateInventoryItem);
6140 AddLocalPacketHandler(PacketType.LinkInventoryItem, HandleLinkInventoryItem);
6141 AddLocalPacketHandler(PacketType.FetchInventory, HandleFetchInventory);
6142 AddLocalPacketHandler(PacketType.FetchInventoryDescendents, HandleFetchInventoryDescendents);
6143 AddLocalPacketHandler(PacketType.PurgeInventoryDescendents, HandlePurgeInventoryDescendents);
6144 AddLocalPacketHandler(PacketType.UpdateInventoryItem, HandleUpdateInventoryItem);
6145 AddLocalPacketHandler(PacketType.CopyInventoryItem, HandleCopyInventoryItem);
6146 AddLocalPacketHandler(PacketType.MoveInventoryItem, HandleMoveInventoryItem);
6147 AddLocalPacketHandler(PacketType.RemoveInventoryItem, HandleRemoveInventoryItem);
6148 AddLocalPacketHandler(PacketType.RemoveInventoryFolder, HandleRemoveInventoryFolder);
6149 AddLocalPacketHandler(PacketType.RemoveInventoryObjects, HandleRemoveInventoryObjects);
6150 AddLocalPacketHandler(PacketType.RequestTaskInventory, HandleRequestTaskInventory);
6151 AddLocalPacketHandler(PacketType.UpdateTaskInventory, HandleUpdateTaskInventory);
6152 AddLocalPacketHandler(PacketType.RemoveTaskInventory, HandleRemoveTaskInventory);
6153 AddLocalPacketHandler(PacketType.MoveTaskInventory, HandleMoveTaskInventory);
6154 AddLocalPacketHandler(PacketType.RezScript, HandleRezScript);
6155 AddLocalPacketHandler(PacketType.MapLayerRequest, HandleMapLayerRequest);
6156 AddLocalPacketHandler(PacketType.MapBlockRequest, HandleMapBlockRequest);
6157 AddLocalPacketHandler(PacketType.MapNameRequest, HandleMapNameRequest);
6158 AddLocalPacketHandler(PacketType.TeleportLandmarkRequest, HandleTeleportLandmarkRequest);
6159 AddLocalPacketHandler(PacketType.TeleportCancel, HandleTeleportCancel);
6160 AddLocalPacketHandler(PacketType.TeleportLocationRequest, HandleTeleportLocationRequest);
6161 AddLocalPacketHandler(PacketType.UUIDNameRequest, HandleUUIDNameRequest, false);
6162 AddLocalPacketHandler(PacketType.RegionHandleRequest, HandleRegionHandleRequest, false);
6163 AddLocalPacketHandler(PacketType.ParcelInfoRequest, HandleParcelInfoRequest);
6164 AddLocalPacketHandler(PacketType.ParcelAccessListRequest, HandleParcelAccessListRequest, false);
6165 AddLocalPacketHandler(PacketType.ParcelAccessListUpdate, HandleParcelAccessListUpdate, false);
6166 AddLocalPacketHandler(PacketType.ParcelPropertiesRequest, HandleParcelPropertiesRequest, false);
6167 AddLocalPacketHandler(PacketType.ParcelDivide, HandleParcelDivide);
6168 AddLocalPacketHandler(PacketType.ParcelJoin, HandleParcelJoin);
6169 AddLocalPacketHandler(PacketType.ParcelPropertiesUpdate, HandleParcelPropertiesUpdate);
6170 AddLocalPacketHandler(PacketType.ParcelSelectObjects, HandleParcelSelectObjects);
6171 AddLocalPacketHandler(PacketType.ParcelObjectOwnersRequest, HandleParcelObjectOwnersRequest);
6172 AddLocalPacketHandler(PacketType.ParcelGodForceOwner, HandleParcelGodForceOwner);
6173 AddLocalPacketHandler(PacketType.ParcelRelease, HandleParcelRelease);
6174 AddLocalPacketHandler(PacketType.ParcelReclaim, HandleParcelReclaim);
6175 AddLocalPacketHandler(PacketType.ParcelReturnObjects, HandleParcelReturnObjects);
6176 AddLocalPacketHandler(PacketType.ParcelSetOtherCleanTime, HandleParcelSetOtherCleanTime);
6177 AddLocalPacketHandler(PacketType.LandStatRequest, HandleLandStatRequest);
6178 AddLocalPacketHandler(PacketType.ParcelDwellRequest, HandleParcelDwellRequest);
6179 AddLocalPacketHandler(PacketType.EstateOwnerMessage, HandleEstateOwnerMessage);
6180 AddLocalPacketHandler(PacketType.RequestRegionInfo, HandleRequestRegionInfo, false);
6181 AddLocalPacketHandler(PacketType.EstateCovenantRequest, HandleEstateCovenantRequest);
6182 AddLocalPacketHandler(PacketType.RequestGodlikePowers, HandleRequestGodlikePowers);
6183 AddLocalPacketHandler(PacketType.GodKickUser, HandleGodKickUser);
6184 AddLocalPacketHandler(PacketType.MoneyBalanceRequest, HandleMoneyBalanceRequest);
6185 AddLocalPacketHandler(PacketType.EconomyDataRequest, HandleEconomyDataRequest);
6186 AddLocalPacketHandler(PacketType.RequestPayPrice, HandleRequestPayPrice);
6187 AddLocalPacketHandler(PacketType.ObjectSaleInfo, HandleObjectSaleInfo);
6188 AddLocalPacketHandler(PacketType.ObjectBuy, HandleObjectBuy);
6189 AddLocalPacketHandler(PacketType.GetScriptRunning, HandleGetScriptRunning);
6190 AddLocalPacketHandler(PacketType.SetScriptRunning, HandleSetScriptRunning);
6191 AddLocalPacketHandler(PacketType.ScriptReset, HandleScriptReset);
6192 AddLocalPacketHandler(PacketType.ActivateGestures, HandleActivateGestures);
6193 AddLocalPacketHandler(PacketType.DeactivateGestures, HandleDeactivateGestures);
6194 AddLocalPacketHandler(PacketType.ObjectOwner, HandleObjectOwner);
6195 AddLocalPacketHandler(PacketType.AgentFOV, HandleAgentFOV, false);
6196 AddLocalPacketHandler(PacketType.ViewerStats, HandleViewerStats);
6197 AddLocalPacketHandler(PacketType.MapItemRequest, HandleMapItemRequest, false);
6198 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false);
6199 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false);
6200 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode);
6201 AddLocalPacketHandler(PacketType.CreateNewOutfitAttachments, HandleCreateNewOutfitAttachments);
6202 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false);
6203 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents);
6204 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery);
6205 AddLocalPacketHandler(PacketType.DirFindQuery, HandleDirFindQuery);
6206 AddLocalPacketHandler(PacketType.DirLandQuery, HandleDirLandQuery);
6207 AddLocalPacketHandler(PacketType.DirPopularQuery, HandleDirPopularQuery);
6208 AddLocalPacketHandler(PacketType.DirClassifiedQuery, HandleDirClassifiedQuery);
6209 AddLocalPacketHandler(PacketType.EventInfoRequest, HandleEventInfoRequest);
6210 AddLocalPacketHandler(PacketType.OfferCallingCard, HandleOfferCallingCard);
6211 AddLocalPacketHandler(PacketType.AcceptCallingCard, HandleAcceptCallingCard);
6212 AddLocalPacketHandler(PacketType.DeclineCallingCard, HandleDeclineCallingCard);
6213 AddLocalPacketHandler(PacketType.ActivateGroup, HandleActivateGroup);
6214 AddLocalPacketHandler(PacketType.GroupTitlesRequest, HandleGroupTitlesRequest);
6215 AddLocalPacketHandler(PacketType.GroupProfileRequest, HandleGroupProfileRequest);
6216 AddLocalPacketHandler(PacketType.GroupMembersRequest, HandleGroupMembersRequest);
6217 AddLocalPacketHandler(PacketType.GroupRoleDataRequest, HandleGroupRoleDataRequest);
6218 AddLocalPacketHandler(PacketType.GroupRoleMembersRequest, HandleGroupRoleMembersRequest);
6219 AddLocalPacketHandler(PacketType.CreateGroupRequest, HandleCreateGroupRequest);
6220 AddLocalPacketHandler(PacketType.UpdateGroupInfo, HandleUpdateGroupInfo);
6221 AddLocalPacketHandler(PacketType.SetGroupAcceptNotices, HandleSetGroupAcceptNotices);
6222 AddLocalPacketHandler(PacketType.GroupTitleUpdate, HandleGroupTitleUpdate);
6223 AddLocalPacketHandler(PacketType.ParcelDeedToGroup, HandleParcelDeedToGroup);
6224 AddLocalPacketHandler(PacketType.GroupNoticesListRequest, HandleGroupNoticesListRequest);
6225 AddLocalPacketHandler(PacketType.GroupNoticeRequest, HandleGroupNoticeRequest);
6226 AddLocalPacketHandler(PacketType.GroupRoleUpdate, HandleGroupRoleUpdate);
6227 AddLocalPacketHandler(PacketType.GroupRoleChanges, HandleGroupRoleChanges);
6228 AddLocalPacketHandler(PacketType.JoinGroupRequest, HandleJoinGroupRequest);
6229 AddLocalPacketHandler(PacketType.LeaveGroupRequest, HandleLeaveGroupRequest);
6230 AddLocalPacketHandler(PacketType.EjectGroupMemberRequest, HandleEjectGroupMemberRequest);
6231 AddLocalPacketHandler(PacketType.InviteGroupRequest, HandleInviteGroupRequest);
6232 AddLocalPacketHandler(PacketType.StartLure, HandleStartLure);
6233 AddLocalPacketHandler(PacketType.TeleportLureRequest, HandleTeleportLureRequest);
6234 AddLocalPacketHandler(PacketType.ClassifiedInfoRequest, HandleClassifiedInfoRequest);
6235 AddLocalPacketHandler(PacketType.ClassifiedInfoUpdate, HandleClassifiedInfoUpdate);
6236 AddLocalPacketHandler(PacketType.ClassifiedDelete, HandleClassifiedDelete);
6237 AddLocalPacketHandler(PacketType.ClassifiedGodDelete, HandleClassifiedGodDelete);
6238 AddLocalPacketHandler(PacketType.EventGodDelete, HandleEventGodDelete);
6239 AddLocalPacketHandler(PacketType.EventNotificationAddRequest, HandleEventNotificationAddRequest);
6240 AddLocalPacketHandler(PacketType.EventNotificationRemoveRequest, HandleEventNotificationRemoveRequest);
6241 AddLocalPacketHandler(PacketType.RetrieveInstantMessages, HandleRetrieveInstantMessages);
6242 AddLocalPacketHandler(PacketType.PickDelete, HandlePickDelete);
6243 AddLocalPacketHandler(PacketType.PickGodDelete, HandlePickGodDelete);
6244 AddLocalPacketHandler(PacketType.PickInfoUpdate, HandlePickInfoUpdate);
6245 AddLocalPacketHandler(PacketType.AvatarNotesUpdate, HandleAvatarNotesUpdate);
6246 AddLocalPacketHandler(PacketType.AvatarInterestsUpdate, HandleAvatarInterestsUpdate);
6247 AddLocalPacketHandler(PacketType.GrantUserRights, HandleGrantUserRights);
6248 AddLocalPacketHandler(PacketType.PlacesQuery, HandlePlacesQuery);
6249 AddLocalPacketHandler(PacketType.UpdateMuteListEntry, HandleUpdateMuteListEntry);
6250 AddLocalPacketHandler(PacketType.RemoveMuteListEntry, HandleRemoveMuteListEntry);
6251 AddLocalPacketHandler(PacketType.UserReport, HandleUserReport);
6252 AddLocalPacketHandler(PacketType.FindAgent, HandleFindAgent);
6253 AddLocalPacketHandler(PacketType.TrackAgent, HandleTrackAgent);
6254 AddLocalPacketHandler(PacketType.GodUpdateRegionInfo, HandleGodUpdateRegionInfoUpdate);
6255 AddLocalPacketHandler(PacketType.GodlikeMessage, HandleGodlikeMessage);
6256 AddLocalPacketHandler(PacketType.StateSave, HandleSaveStatePacket);
6257 AddLocalPacketHandler(PacketType.GroupAccountDetailsRequest, HandleGroupAccountDetailsRequest);
6258 AddLocalPacketHandler(PacketType.GroupAccountSummaryRequest, HandleGroupAccountSummaryRequest);
6259 AddLocalPacketHandler(PacketType.GroupAccountTransactionsRequest, HandleGroupTransactionsDetailsRequest);
6260 AddLocalPacketHandler(PacketType.FreezeUser, HandleFreezeUser);
6261 AddLocalPacketHandler(PacketType.EjectUser, HandleEjectUser);
6262 AddLocalPacketHandler(PacketType.ParcelBuyPass, HandleParcelBuyPass);
6263 AddLocalPacketHandler(PacketType.ParcelGodMarkAsContent, HandleParcelGodMarkAsContent);
6264 AddLocalPacketHandler(PacketType.GroupActiveProposalsRequest, HandleGroupActiveProposalsRequest);
6265 AddLocalPacketHandler(PacketType.GroupVoteHistoryRequest, HandleGroupVoteHistoryRequest);
6266 AddLocalPacketHandler(PacketType.SimWideDeletes, HandleSimWideDeletes);
6267 AddLocalPacketHandler(PacketType.SendPostcard, HandleSendPostcard);
6268 AddLocalPacketHandler(PacketType.ChangeInventoryItemFlags, HandleChangeInventoryItemFlags);
6269 AddLocalPacketHandler(PacketType.RevokePermissions, HandleRevokePermissions);
6270 AddGenericPacketHandler("autopilot", HandleAutopilot);
6271 }
6272
6273 #region Packet Handlers
6274
6275 public int TotalAgentUpdates { get; set; }
6276
6277 #region Scene/Avatar
6278
6279 // Threshold for body rotation to be a significant agent update
6280 // use the abs of cos
6281 private const float QDELTABody = 1.0f - 0.00005f;
6282 private const float QDELTAHead = 1.0f - 0.00005f;
6283 // Threshold for camera rotation to be a significant agent update
6284 private const float VDELTA = 0.01f;
6285
6286 /// <summary>
6287 /// This checks the update significance against the last update made.
6288 /// </summary>
6289 /// <remarks>Can only be called by one thread at a time</remarks>
6290 /// <returns></returns>
6291 /// <param name='x'></param>
6292 public bool CheckAgentUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
6293 {
6294 return CheckAgentMovementUpdateSignificance(x) || CheckAgentCameraUpdateSignificance(x);
6295 }
6296
6297 /// <summary>
6298 /// This checks the movement/state update significance against the last update made.
6299 /// </summary>
6300 /// <remarks>Can only be called by one thread at a time</remarks>
6301 /// <returns></returns>
6302 /// <param name='x'></param>
6303 private bool CheckAgentMovementUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
6304 {
6305 if(
6306 (x.ControlFlags != m_thisAgentUpdateArgs.ControlFlags) // significant if control flags changed
6307// || ((x.ControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0 &&
6308// (x.ControlFlags & 0x3f8dfff) != 0) // we need to rotate the av on fly
6309 || x.ControlFlags != (byte)AgentManager.ControlFlags.NONE// actually all movement controls need to pass
6310 || (x.Flags != m_thisAgentUpdateArgs.Flags) // significant if Flags changed
6311 || (x.State != m_thisAgentUpdateArgs.State) // significant if Stats changed
6312 || (Math.Abs(x.Far - m_thisAgentUpdateArgs.Far) >= 32) // significant if far distance changed
6313 )
6314 return true;
6315
6316 float qdelta1 = Math.Abs(Quaternion.Dot(x.BodyRotation, m_thisAgentUpdateArgs.BodyRotation));
6317 //qdelta2 = Math.Abs(Quaternion.Dot(x.HeadRotation, m_thisAgentUpdateArgs.HeadRotation));
6318
6319 if(
6320 qdelta1 < QDELTABody // significant if body rotation above(below cos) threshold
6321 // Ignoring head rotation altogether, because it's not being used for anything interesting up the stack
6322 // || qdelta2 < QDELTAHead // significant if head rotation above(below cos) threshold
6323 )
6324 return true;
6325
6326 return false;
6327 }
6328
6329 /// <summary>
6330 /// This checks the camera update significance against the last update made.
6331 /// </summary>
6332 /// <remarks>Can only be called by one thread at a time</remarks>
6333 /// <returns></returns>
6334 /// <param name='x'></param>
6335 private bool CheckAgentCameraUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
6336 {
6337 if(Math.Abs(x.CameraCenter.X - m_thisAgentUpdateArgs.CameraCenter.X) > VDELTA ||
6338 Math.Abs(x.CameraCenter.Y - m_thisAgentUpdateArgs.CameraCenter.Y) > VDELTA ||
6339 Math.Abs(x.CameraCenter.Z - m_thisAgentUpdateArgs.CameraCenter.Z) > VDELTA ||
6340
6341 Math.Abs(x.CameraAtAxis.X - m_thisAgentUpdateArgs.CameraAtAxis.X) > VDELTA ||
6342 Math.Abs(x.CameraAtAxis.Y - m_thisAgentUpdateArgs.CameraAtAxis.Y) > VDELTA ||
6343// Math.Abs(x.CameraAtAxis.Z - m_thisAgentUpdateArgs.CameraAtAxis.Z) > VDELTA ||
6344
6345 Math.Abs(x.CameraLeftAxis.X - m_thisAgentUpdateArgs.CameraLeftAxis.X) > VDELTA ||
6346 Math.Abs(x.CameraLeftAxis.Y - m_thisAgentUpdateArgs.CameraLeftAxis.Y) > VDELTA ||
6347// Math.Abs(x.CameraLeftAxis.Z - m_thisAgentUpdateArgs.CameraLeftAxis.Z) > VDELTA ||
6348
6349 Math.Abs(x.CameraUpAxis.X - m_thisAgentUpdateArgs.CameraUpAxis.X) > VDELTA ||
6350 Math.Abs(x.CameraUpAxis.Y - m_thisAgentUpdateArgs.CameraUpAxis.Y) > VDELTA
6351// Math.Abs(x.CameraLeftAxis.Z - m_thisAgentUpdateArgs.CameraLeftAxis.Z) > VDELTA ||
6352 )
6353 return true;
6354
6355 return false;
6356 }
6357
6358 private bool HandleAgentUpdate(IClientAPI sender, Packet packet)
6359 {
6360 AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
6361 AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData;
6362
6363 if (x.AgentID != AgentId || x.SessionID != SessionId)
6364 {
6365 PacketPool.Instance.ReturnPacket(packet);
6366 return false;
6367 }
6368
6369 uint seq = packet.Header.Sequence;
6370
6371 TotalAgentUpdates++;
6372 // dont let ignored updates pollute this throttles
6373 if(SceneAgent == null || SceneAgent.IsChildAgent ||
6374 SceneAgent.IsInTransit || seq <= m_thisAgentUpdateArgs.lastpacketSequence )
6375 {
6376 // throttle reset is done at MoveAgentIntoRegion()
6377 // called by scenepresence on completemovement
6378 PacketPool.Instance.ReturnPacket(packet);
6379 return true;
6380 }
6381
6382 m_thisAgentUpdateArgs.lastpacketSequence = seq;
6383
6384 bool movement = CheckAgentMovementUpdateSignificance(x);
6385 bool camera = CheckAgentCameraUpdateSignificance(x);
6386
6387 // Was there a significant movement/state change?
6388 if (movement)
6389 {
6390 m_thisAgentUpdateArgs.BodyRotation = x.BodyRotation;
6391 m_thisAgentUpdateArgs.ControlFlags = x.ControlFlags;
6392 m_thisAgentUpdateArgs.Far = x.Far;
6393 m_thisAgentUpdateArgs.Flags = x.Flags;
6394 m_thisAgentUpdateArgs.HeadRotation = x.HeadRotation;
6395 m_thisAgentUpdateArgs.State = x.State;
6396
6397 m_thisAgentUpdateArgs.NeedsCameraCollision = !camera;
6398
6399 UpdateAgent handlerAgentUpdate = OnAgentUpdate;
6400 UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate;
6401
6402 if (handlerPreAgentUpdate != null)
6403 OnPreAgentUpdate(this, m_thisAgentUpdateArgs);
6404
6405 if (handlerAgentUpdate != null)
6406 OnAgentUpdate(this, m_thisAgentUpdateArgs);
6407
6408 }
6409
6410 // Was there a significant camera(s) change?
6411 if (camera)
6412 {
6413 m_thisAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis;
6414 m_thisAgentUpdateArgs.CameraCenter = x.CameraCenter;
6415 m_thisAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis;
6416 m_thisAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis;
6417
6418 m_thisAgentUpdateArgs.NeedsCameraCollision = true;
6419
6420 UpdateAgent handlerAgentCameraUpdate = OnAgentCameraUpdate;
6421
6422 if (handlerAgentCameraUpdate != null)
6423 handlerAgentCameraUpdate(this, m_thisAgentUpdateArgs);
6424
6425 }
6426
6427 PacketPool.Instance.ReturnPacket(packet);
6428
6429 return true;
6430 }
6431
6432 private bool HandleMoneyTransferRequest(IClientAPI sender, Packet Pack)
6433 {
6434 MoneyTransferRequestPacket money = (MoneyTransferRequestPacket)Pack;
6435 // validate the agent owns the agentID and sessionID
6436 if (money.MoneyData.SourceID == sender.AgentId && money.AgentData.AgentID == sender.AgentId &&
6437 money.AgentData.SessionID == sender.SessionId)
6438 {
6439 MoneyTransferRequest handlerMoneyTransferRequest = OnMoneyTransferRequest;
6440 if (handlerMoneyTransferRequest != null)
6441 {
6442 handlerMoneyTransferRequest(money.MoneyData.SourceID, money.MoneyData.DestID,
6443 money.MoneyData.Amount, money.MoneyData.TransactionType,
6444 Util.FieldToString(money.MoneyData.Description));
6445 }
6446
6447 return true;
6448 }
6449
6450 return false;
6451 }
6452
6453 private bool HandleParcelGodMarkAsContent(IClientAPI client, Packet Packet)
6454 {
6455 ParcelGodMarkAsContentPacket ParcelGodMarkAsContent =
6456 (ParcelGodMarkAsContentPacket)Packet;
6457
6458 if(SessionId != ParcelGodMarkAsContent.AgentData.SessionID || AgentId != ParcelGodMarkAsContent.AgentData.AgentID)
6459 return false;
6460
6461 ParcelGodMark ParcelGodMarkAsContentHandler = OnParcelGodMark;
6462 if (ParcelGodMarkAsContentHandler != null)
6463 {
6464 ParcelGodMarkAsContentHandler(this,
6465 ParcelGodMarkAsContent.AgentData.AgentID,
6466 ParcelGodMarkAsContent.ParcelData.LocalID);
6467 return true;
6468 }
6469 return false;
6470 }
6471
6472 private bool HandleFreezeUser(IClientAPI client, Packet Packet)
6473 {
6474 FreezeUserPacket FreezeUser = (FreezeUserPacket)Packet;
6475
6476 if(SessionId != FreezeUser.AgentData.SessionID || AgentId != FreezeUser.AgentData.AgentID)
6477 return false;
6478
6479 FreezeUserUpdate FreezeUserHandler = OnParcelFreezeUser;
6480 if (FreezeUserHandler != null)
6481 {
6482 FreezeUserHandler(this,
6483 FreezeUser.AgentData.AgentID,
6484 FreezeUser.Data.Flags,
6485 FreezeUser.Data.TargetID);
6486 return true;
6487 }
6488 return false;
6489 }
6490
6491 private bool HandleEjectUser(IClientAPI client, Packet Packet)
6492 {
6493 EjectUserPacket EjectUser =
6494 (EjectUserPacket)Packet;
6495
6496 if(SessionId != EjectUser.AgentData.SessionID || AgentId != EjectUser.AgentData.AgentID)
6497 return false;
6498
6499 EjectUserUpdate EjectUserHandler = OnParcelEjectUser;
6500 if (EjectUserHandler != null)
6501 {
6502 EjectUserHandler(this,
6503 EjectUser.AgentData.AgentID,
6504 EjectUser.Data.Flags,
6505 EjectUser.Data.TargetID);
6506 return true;
6507 }
6508 return false;
6509 }
6510
6511 private bool HandleParcelBuyPass(IClientAPI client, Packet Packet)
6512 {
6513 ParcelBuyPassPacket ParcelBuyPass =
6514 (ParcelBuyPassPacket)Packet;
6515
6516 if(SessionId != ParcelBuyPass.AgentData.SessionID || AgentId != ParcelBuyPass.AgentData.AgentID)
6517 return false;
6518
6519 ParcelBuyPass ParcelBuyPassHandler = OnParcelBuyPass;
6520 if (ParcelBuyPassHandler != null)
6521 {
6522 ParcelBuyPassHandler(this,
6523 ParcelBuyPass.AgentData.AgentID,
6524 ParcelBuyPass.ParcelData.LocalID);
6525 return true;
6526 }
6527 return false;
6528 }
6529
6530 private bool HandleParcelBuyRequest(IClientAPI sender, Packet Pack)
6531 {
6532 ParcelBuyPacket parcel = (ParcelBuyPacket)Pack;
6533 if (parcel.AgentData.AgentID == AgentId && parcel.AgentData.SessionID == SessionId)
6534 {
6535 ParcelBuy handlerParcelBuy = OnParcelBuy;
6536 if (handlerParcelBuy != null)
6537 {
6538 handlerParcelBuy(parcel.AgentData.AgentID, parcel.Data.GroupID, parcel.Data.Final,
6539 parcel.Data.IsGroupOwned,
6540 parcel.Data.RemoveContribution, parcel.Data.LocalID, parcel.ParcelData.Area,
6541 parcel.ParcelData.Price,
6542 false);
6543 }
6544 return true;
6545 }
6546 return false;
6547 }
6548
6549 private bool HandleUUIDGroupNameRequest(IClientAPI sender, Packet Pack)
6550 {
6551 ScenePresence sp = (ScenePresence)SceneAgent;
6552 if(sp == null || sp.IsDeleted || (sp.IsInTransit && !sp.IsInLocalTransit))
6553 return true;
6554
6555 UUIDGroupNameRequestPacket upack = (UUIDGroupNameRequestPacket)Pack;
6556
6557 for (int i = 0; i < upack.UUIDNameBlock.Length; i++)
6558 {
6559 UUIDNameRequest handlerUUIDGroupNameRequest = OnUUIDGroupNameRequest;
6560 if (handlerUUIDGroupNameRequest != null)
6561 {
6562 handlerUUIDGroupNameRequest(upack.UUIDNameBlock[i].ID, this);
6563 }
6564 }
6565
6566 return true;
6567 }
6568
6569 public bool HandleGenericMessage(IClientAPI sender, Packet pack)
6570 {
6571 GenericMessagePacket gmpack = (GenericMessagePacket)pack;
6572 if (m_genericPacketHandlers.Count == 0) return false;
6573 if (gmpack.AgentData.SessionID != SessionId) return false;
6574
6575 GenericMessage handlerGenericMessage = null;
6576
6577 string method = Util.FieldToString(gmpack.MethodData.Method).ToLower().Trim();
6578
6579 if (m_genericPacketHandlers.TryGetValue(method, out handlerGenericMessage))
6580 {
6581 List<string> msg = new List<string>();
6582 List<byte[]> msgBytes = new List<byte[]>();
6583
6584 if (handlerGenericMessage != null)
6585 {
6586 foreach (GenericMessagePacket.ParamListBlock block in gmpack.ParamList)
6587 {
6588 msg.Add(Util.FieldToString(block.Parameter));
6589 msgBytes.Add(block.Parameter);
6590 }
6591 try
6592 {
6593 if (OnBinaryGenericMessage != null)
6594 {
6595 OnBinaryGenericMessage(this, method, msgBytes.ToArray());
6596 }
6597 handlerGenericMessage(sender, method, msg);
6598 return true;
6599 }
6600 catch (Exception e)
6601 {
6602 m_log.ErrorFormat(
6603 "[LLCLIENTVIEW]: Exeception when handling generic message {0}{1}", e.Message, e.StackTrace);
6604 }
6605 }
6606 }
6607
6608 //m_log.Debug("[LLCLIENTVIEW]: Not handling GenericMessage with method-type of: " + method);
6609 return false;
6610 }
6611
6612 public bool HandleObjectGroupRequest(IClientAPI sender, Packet Pack)
6613 {
6614 ObjectGroupPacket ogpack = (ObjectGroupPacket)Pack;
6615 if (ogpack.AgentData.SessionID != SessionId) return false;
6616
6617 RequestObjectPropertiesFamily handlerObjectGroupRequest = OnObjectGroupRequest;
6618 if (handlerObjectGroupRequest != null)
6619 {
6620 for (int i = 0; i < ogpack.ObjectData.Length; i++)
6621 {
6622 handlerObjectGroupRequest(this, ogpack.AgentData.GroupID, ogpack.ObjectData[i].ObjectLocalID, UUID.Zero);
6623 }
6624 }
6625 return true;
6626 }
6627
6628 private bool HandleViewerEffect(IClientAPI sender, Packet Pack)
6629 {
6630 ViewerEffectPacket viewer = (ViewerEffectPacket)Pack;
6631 if (viewer.AgentData.SessionID != SessionId) return false;
6632 ViewerEffectEventHandler handlerViewerEffect = OnViewerEffect;
6633 if (handlerViewerEffect != null)
6634 {
6635 int length = viewer.Effect.Length;
6636 List<ViewerEffectEventHandlerArg> args = new List<ViewerEffectEventHandlerArg>(length);
6637 for (int i = 0; i < length; i++)
6638 {
6639 //copy the effects block arguments into the event handler arg.
6640 ViewerEffectEventHandlerArg argument = new ViewerEffectEventHandlerArg();
6641 argument.AgentID = viewer.Effect[i].AgentID;
6642 argument.Color = viewer.Effect[i].Color;
6643 argument.Duration = viewer.Effect[i].Duration;
6644 argument.ID = viewer.Effect[i].ID;
6645 argument.Type = viewer.Effect[i].Type;
6646 argument.TypeData = viewer.Effect[i].TypeData;
6647 args.Add(argument);
6648 }
6649
6650 handlerViewerEffect(sender, args);
6651 }
6652
6653 return true;
6654 }
6655
6656 private bool HandleVelocityInterpolateOff(IClientAPI sender, Packet Pack)
6657 {
6658 VelocityInterpolateOffPacket p = (VelocityInterpolateOffPacket)Pack;
6659 if (p.AgentData.SessionID != SessionId ||
6660 p.AgentData.AgentID != AgentId)
6661 return true;
6662
6663// m_VelocityInterpolate = false;
6664 return true;
6665 }
6666
6667 private bool HandleVelocityInterpolateOn(IClientAPI sender, Packet Pack)
6668 {
6669 VelocityInterpolateOnPacket p = (VelocityInterpolateOnPacket)Pack;
6670 if (p.AgentData.SessionID != SessionId ||
6671 p.AgentData.AgentID != AgentId)
6672 return true;
6673
6674// m_VelocityInterpolate = true;
6675 return true;
6676 }
6677
6678
6679 private bool HandleAvatarPropertiesRequest(IClientAPI sender, Packet Pack)
6680 {
6681 AvatarPropertiesRequestPacket avatarProperties = (AvatarPropertiesRequestPacket)Pack;
6682
6683 #region Packet Session and User Check
6684 if (m_checkPackets)
6685 {
6686 if (avatarProperties.AgentData.SessionID != SessionId ||
6687 avatarProperties.AgentData.AgentID != AgentId)
6688 return true;
6689 }
6690 #endregion
6691
6692 RequestAvatarProperties handlerRequestAvatarProperties = OnRequestAvatarProperties;
6693 if (handlerRequestAvatarProperties != null)
6694 {
6695 handlerRequestAvatarProperties(this, avatarProperties.AgentData.AvatarID);
6696 }
6697 return true;
6698 }
6699
6700 private bool HandleChatFromViewer(IClientAPI sender, Packet Pack)
6701 {
6702 ChatFromViewerPacket inchatpack = (ChatFromViewerPacket)Pack;
6703
6704 #region Packet Session and User Check
6705 if (m_checkPackets)
6706 {
6707 if (inchatpack.AgentData.SessionID != SessionId ||
6708 inchatpack.AgentData.AgentID != AgentId)
6709 return true;
6710 }
6711 #endregion
6712
6713 string fromName = String.Empty; //ClientAvatar.firstname + " " + ClientAvatar.lastname;
6714 byte[] message = inchatpack.ChatData.Message;
6715 byte type = inchatpack.ChatData.Type;
6716 Vector3 fromPos = new Vector3(); // ClientAvatar.Pos;
6717 // UUID fromAgentID = AgentId;
6718
6719 int channel = inchatpack.ChatData.Channel;
6720
6721 if (OnChatFromClient != null)
6722 {
6723 OSChatMessage args = new OSChatMessage();
6724 args.Channel = channel;
6725 args.From = fromName;
6726 args.Message = Utils.BytesToString(message);
6727 args.Type = (ChatTypeEnum)type;
6728 args.Position = fromPos;
6729
6730 args.Scene = Scene;
6731 args.Sender = this;
6732 args.SenderUUID = this.AgentId;
6733
6734 ChatMessage handlerChatFromClient = OnChatFromClient;
6735 if (handlerChatFromClient != null)
6736 handlerChatFromClient(this, args);
6737 }
6738 return true;
6739 }
6740
6741 private bool HandlerAvatarPropertiesUpdate(IClientAPI sender, Packet Pack)
6742 {
6743 AvatarPropertiesUpdatePacket avatarProps = (AvatarPropertiesUpdatePacket)Pack;
6744
6745 #region Packet Session and User Check
6746 if (m_checkPackets)
6747 {
6748 if (avatarProps.AgentData.SessionID != SessionId ||
6749 avatarProps.AgentData.AgentID != AgentId)
6750 return true;
6751 }
6752 #endregion
6753
6754 UpdateAvatarProperties handlerUpdateAvatarProperties = OnUpdateAvatarProperties;
6755 if (handlerUpdateAvatarProperties != null)
6756 {
6757 AvatarPropertiesUpdatePacket.PropertiesDataBlock Properties = avatarProps.PropertiesData;
6758 UserProfileData UserProfile = new UserProfileData();
6759 UserProfile.ID = AgentId;
6760 UserProfile.AboutText = Utils.BytesToString(Properties.AboutText);
6761 UserProfile.FirstLifeAboutText = Utils.BytesToString(Properties.FLAboutText);
6762 UserProfile.FirstLifeImage = Properties.FLImageID;
6763 UserProfile.Image = Properties.ImageID;
6764 UserProfile.ProfileUrl = Utils.BytesToString(Properties.ProfileURL);
6765 UserProfile.UserFlags &= ~3;
6766 UserProfile.UserFlags |= Properties.AllowPublish ? 1 : 0;
6767 UserProfile.UserFlags |= Properties.MaturePublish ? 2 : 0;
6768
6769 handlerUpdateAvatarProperties(this, UserProfile);
6770 }
6771 return true;
6772 }
6773
6774 private bool HandlerScriptDialogReply(IClientAPI sender, Packet Pack)
6775 {
6776 ScriptDialogReplyPacket rdialog = (ScriptDialogReplyPacket)Pack;
6777
6778 //m_log.DebugFormat("[CLIENT]: Received ScriptDialogReply from {0}", rdialog.Data.ObjectID);
6779
6780 #region Packet Session and User Check
6781 if (m_checkPackets)
6782 {
6783 if (rdialog.AgentData.SessionID != SessionId ||
6784 rdialog.AgentData.AgentID != AgentId)
6785 return true;
6786 }
6787 #endregion
6788
6789 int ch = rdialog.Data.ChatChannel;
6790 byte[] msg = rdialog.Data.ButtonLabel;
6791 if (OnChatFromClient != null)
6792 {
6793 OSChatMessage args = new OSChatMessage();
6794 args.Channel = ch;
6795 args.From = String.Empty;
6796 args.Message = Utils.BytesToString(msg);
6797 args.Type = ChatTypeEnum.Region; //Behaviour in SL is that the response can be heard from any distance
6798 args.Position = new Vector3();
6799 args.Scene = Scene;
6800 args.Sender = this;
6801 ChatMessage handlerChatFromClient2 = OnChatFromClient;
6802 if (handlerChatFromClient2 != null)
6803 handlerChatFromClient2(this, args);
6804 }
6805
6806 return true;
6807 }
6808
6809 private bool HandlerImprovedInstantMessage(IClientAPI sender, Packet Pack)
6810 {
6811 ImprovedInstantMessagePacket msgpack = (ImprovedInstantMessagePacket)Pack;
6812
6813 #region Packet Session and User Check
6814 if (m_checkPackets)
6815 {
6816 if (msgpack.AgentData.SessionID != SessionId ||
6817 msgpack.AgentData.AgentID != AgentId)
6818 return true;
6819 }
6820 #endregion
6821
6822 string IMfromName = Util.FieldToString(msgpack.MessageBlock.FromAgentName);
6823 string IMmessage = Utils.BytesToString(msgpack.MessageBlock.Message);
6824 ImprovedInstantMessage handlerInstantMessage = OnInstantMessage;
6825
6826 if (handlerInstantMessage != null)
6827 {
6828 GridInstantMessage im = new GridInstantMessage(Scene,
6829 msgpack.AgentData.AgentID,
6830 IMfromName,
6831 msgpack.MessageBlock.ToAgentID,
6832 msgpack.MessageBlock.Dialog,
6833 msgpack.MessageBlock.FromGroup,
6834 IMmessage,
6835 msgpack.MessageBlock.ID,
6836 msgpack.MessageBlock.Offline != 0 ? true : false,
6837 msgpack.MessageBlock.Position,
6838 msgpack.MessageBlock.BinaryBucket,
6839 true);
6840
6841 handlerInstantMessage(this, im);
6842 }
6843 return true;
6844
6845 }
6846
6847 private bool HandlerAcceptFriendship(IClientAPI sender, Packet Pack)
6848 {
6849 AcceptFriendshipPacket afriendpack = (AcceptFriendshipPacket)Pack;
6850
6851 #region Packet Session and User Check
6852 if (m_checkPackets)
6853 {
6854 if (afriendpack.AgentData.SessionID != SessionId ||
6855 afriendpack.AgentData.AgentID != AgentId)
6856 return true;
6857 }
6858 #endregion
6859
6860 // My guess is this is the folder to stick the calling card into
6861 List<UUID> callingCardFolders = new List<UUID>();
6862
6863 UUID transactionID = afriendpack.TransactionBlock.TransactionID;
6864
6865 for (int fi = 0; fi < afriendpack.FolderData.Length; fi++)
6866 {
6867 callingCardFolders.Add(afriendpack.FolderData[fi].FolderID);
6868 }
6869
6870 FriendActionDelegate handlerApproveFriendRequest = OnApproveFriendRequest;
6871 if (handlerApproveFriendRequest != null)
6872 {
6873 handlerApproveFriendRequest(this, transactionID, callingCardFolders);
6874 }
6875
6876 return true;
6877 }
6878
6879 private bool HandlerDeclineFriendship(IClientAPI sender, Packet Pack)
6880 {
6881 DeclineFriendshipPacket dfriendpack = (DeclineFriendshipPacket)Pack;
6882
6883 #region Packet Session and User Check
6884 if (m_checkPackets)
6885 {
6886 if (dfriendpack.AgentData.SessionID != SessionId ||
6887 dfriendpack.AgentData.AgentID != AgentId)
6888 return true;
6889 }
6890 #endregion
6891
6892 if (OnDenyFriendRequest != null)
6893 {
6894 OnDenyFriendRequest(this,
6895 dfriendpack.TransactionBlock.TransactionID,
6896 null);
6897 }
6898 return true;
6899 }
6900
6901 private bool HandlerTerminateFriendship(IClientAPI sender, Packet Pack)
6902 {
6903 TerminateFriendshipPacket tfriendpack = (TerminateFriendshipPacket)Pack;
6904
6905 #region Packet Session and User Check
6906 if (m_checkPackets)
6907 {
6908 if (tfriendpack.AgentData.SessionID != SessionId ||
6909 tfriendpack.AgentData.AgentID != AgentId)
6910 return true;
6911 }
6912 #endregion
6913
6914 UUID exFriendID = tfriendpack.ExBlock.OtherID;
6915 FriendshipTermination TerminateFriendshipHandler = OnTerminateFriendship;
6916 if (TerminateFriendshipHandler != null)
6917 {
6918 TerminateFriendshipHandler(this, exFriendID);
6919 return true;
6920 }
6921
6922 return false;
6923 }
6924
6925 private bool HandleFindAgent(IClientAPI client, Packet Packet)
6926 {
6927 FindAgentPacket FindAgent =
6928 (FindAgentPacket)Packet;
6929
6930 FindAgentUpdate FindAgentHandler = OnFindAgent;
6931 if (FindAgentHandler != null)
6932 {
6933 FindAgentHandler(this,FindAgent.AgentBlock.Hunter,FindAgent.AgentBlock.Prey);
6934 return true;
6935 }
6936 return false;
6937 }
6938
6939 private bool HandleTrackAgent(IClientAPI client, Packet Packet)
6940 {
6941 TrackAgentPacket TrackAgent =
6942 (TrackAgentPacket)Packet;
6943
6944 TrackAgentUpdate TrackAgentHandler = OnTrackAgent;
6945 if (TrackAgentHandler != null)
6946 {
6947 TrackAgentHandler(this,
6948 TrackAgent.AgentData.AgentID,
6949 TrackAgent.TargetData.PreyID);
6950 return true;
6951 }
6952 return false;
6953 }
6954
6955 private bool HandlerRezObject(IClientAPI sender, Packet Pack)
6956 {
6957 RezObjectPacket rezPacket = (RezObjectPacket)Pack;
6958
6959 #region Packet Session and User Check
6960 if (m_checkPackets)
6961 {
6962 if (rezPacket.AgentData.SessionID != SessionId ||
6963 rezPacket.AgentData.AgentID != AgentId)
6964 return true;
6965 }
6966 #endregion
6967
6968 RezObject handlerRezObject = OnRezObject;
6969 if (handlerRezObject != null)
6970 {
6971 UUID rezGroupID = rezPacket.AgentData.GroupID;
6972 if(!IsGroupMember(rezGroupID))
6973 rezGroupID = UUID.Zero;
6974 handlerRezObject(this, rezPacket.InventoryData.ItemID, rezGroupID, rezPacket.RezData.RayEnd,
6975 rezPacket.RezData.RayStart, rezPacket.RezData.RayTargetID,
6976 rezPacket.RezData.BypassRaycast, rezPacket.RezData.RayEndIsIntersection,
6977 rezPacket.RezData.RezSelected, rezPacket.RezData.RemoveItem,
6978 rezPacket.RezData.FromTaskID);
6979 }
6980 return true;
6981 }
6982
6983 private bool HandlerDeRezObject(IClientAPI sender, Packet Pack)
6984 {
6985 DeRezObjectPacket DeRezPacket = (DeRezObjectPacket)Pack;
6986
6987 #region Packet Session and User Check
6988 if (m_checkPackets)
6989 {
6990 if (DeRezPacket.AgentData.SessionID != SessionId ||
6991 DeRezPacket.AgentData.AgentID != AgentId)
6992 return true;
6993 }
6994 #endregion
6995
6996 DeRezObject handlerDeRezObject = OnDeRezObject;
6997 if (handlerDeRezObject != null)
6998 {
6999 List<uint> deRezIDs = new List<uint>();
7000
7001 foreach (DeRezObjectPacket.ObjectDataBlock data in
7002 DeRezPacket.ObjectData)
7003 {
7004 deRezIDs.Add(data.ObjectLocalID);
7005 }
7006 // It just so happens that the values on the DeRezAction enumerator match the Destination
7007 // values given by a Second Life client
7008 handlerDeRezObject(this, deRezIDs,
7009 DeRezPacket.AgentBlock.GroupID,
7010 (DeRezAction)DeRezPacket.AgentBlock.Destination,
7011 DeRezPacket.AgentBlock.DestinationID);
7012
7013 }
7014 return true;
7015 }
7016
7017 private bool HandlerRezRestoreToWorld(IClientAPI sender, Packet Pack)
7018 {
7019 RezRestoreToWorldPacket restore = (RezRestoreToWorldPacket)Pack;
7020
7021 #region Packet Session and User Check
7022 if (m_checkPackets)
7023 {
7024 if (restore.AgentData.SessionID != SessionId ||
7025 restore.AgentData.AgentID != AgentId)
7026 return true;
7027 }
7028 #endregion
7029
7030 RezRestoreToWorld handlerRezRestoreToWorld = OnRezRestoreToWorld;
7031 if (handlerRezRestoreToWorld != null)
7032 handlerRezRestoreToWorld(this, restore.InventoryData.ItemID);
7033
7034 return true;
7035 }
7036
7037 private bool HandlerModifyLand(IClientAPI sender, Packet Pack)
7038 {
7039 ModifyLandPacket modify = (ModifyLandPacket)Pack;
7040
7041 #region Packet Session and User Check
7042 if (m_checkPackets)
7043 {
7044 if (modify.AgentData.SessionID != SessionId ||
7045 modify.AgentData.AgentID != AgentId)
7046 return true;
7047 }
7048
7049 #endregion
7050 //m_log.Info("[LAND]: LAND:" + modify.ToString());
7051 if (modify.ParcelData.Length > 0)
7052 {
7053 // Note: the ModifyTerrain event handler sends out updated packets before the end of this event. Therefore,
7054 // a simple boolean value should work and perhaps queue up just a few terrain patch packets at the end of the edit.
7055 if (OnModifyTerrain != null)
7056 {
7057 for (int i = 0; i < modify.ParcelData.Length; i++)
7058 {
7059 ModifyTerrain handlerModifyTerrain = OnModifyTerrain;
7060 if (handlerModifyTerrain != null)
7061 {
7062 handlerModifyTerrain(AgentId, modify.ModifyBlock.Height, modify.ModifyBlock.Seconds,
7063 modify.ModifyBlock.BrushSize,
7064 modify.ModifyBlock.Action, modify.ParcelData[i].North,
7065 modify.ParcelData[i].West, modify.ParcelData[i].South,
7066 modify.ParcelData[i].East, AgentId);
7067 }
7068 }
7069 }
7070 }
7071
7072 return true;
7073 }
7074
7075 private bool HandlerRegionHandshakeReply(IClientAPI sender, Packet Pack)
7076 {
7077 Action<IClientAPI> handlerRegionHandShakeReply = OnRegionHandShakeReply;
7078 if (handlerRegionHandShakeReply != null)
7079 {
7080 handlerRegionHandShakeReply(this);
7081 }
7082
7083 return true;
7084 }
7085
7086 private bool HandlerAgentWearablesRequest(IClientAPI sender, Packet Pack)
7087 {
7088 GenericCall1 handlerRequestWearables = OnRequestWearables;
7089
7090 if (handlerRequestWearables != null)
7091 {
7092 handlerRequestWearables(sender);
7093 }
7094
7095 Action<IClientAPI> handlerRequestAvatarsData = OnRequestAvatarsData;
7096
7097 if (handlerRequestAvatarsData != null)
7098 {
7099 handlerRequestAvatarsData(this);
7100 }
7101
7102 return true;
7103 }
7104
7105 private bool HandlerAgentSetAppearance(IClientAPI sender, Packet Pack)
7106 {
7107 AgentSetAppearancePacket appear = (AgentSetAppearancePacket)Pack;
7108
7109 #region Packet Session and User Check
7110 if (m_checkPackets)
7111 {
7112 if (appear.AgentData.SessionID != SessionId ||
7113 appear.AgentData.AgentID != AgentId)
7114 return true;
7115 }
7116 #endregion
7117
7118 SetAppearance handlerSetAppearance = OnSetAppearance;
7119 if (handlerSetAppearance != null)
7120 {
7121 // Temporarily protect ourselves from the mantis #951 failure.
7122 // However, we could do this for several other handlers where a failure isn't terminal
7123 // for the client session anyway, in order to protect ourselves against bad code in plugins
7124 Vector3 avSize = appear.AgentData.Size;
7125 try
7126 {
7127 byte[] visualparams = new byte[appear.VisualParam.Length];
7128 for (int i = 0; i < appear.VisualParam.Length; i++)
7129 visualparams[i] = appear.VisualParam[i].ParamValue;
7130 //var b = appear.WearableData[0];
7131
7132 Primitive.TextureEntry te = null;
7133 if (appear.ObjectData.TextureEntry.Length > 1)
7134 te = new Primitive.TextureEntry(appear.ObjectData.TextureEntry, 0, appear.ObjectData.TextureEntry.Length);
7135
7136 WearableCacheItem[] cacheitems = new WearableCacheItem[appear.WearableData.Length];
7137 for (int i=0; i<appear.WearableData.Length;i++)
7138 cacheitems[i] = new WearableCacheItem(){
7139 CacheId = appear.WearableData[i].CacheID,
7140 TextureIndex=Convert.ToUInt32(appear.WearableData[i].TextureIndex)
7141 };
7142
7143
7144
7145 handlerSetAppearance(sender, te, visualparams,avSize, cacheitems);
7146 }
7147 catch (Exception e)
7148 {
7149 m_log.ErrorFormat(
7150 "[CLIENT VIEW]: AgentSetApperance packet handler threw an exception, {0}",
7151 e);
7152 }
7153 }
7154
7155 return true;
7156 }
7157
7158 private bool HandlerAgentIsNowWearing(IClientAPI sender, Packet Pack)
7159 {
7160 if (OnAvatarNowWearing != null)
7161 {
7162 AgentIsNowWearingPacket nowWearing = (AgentIsNowWearingPacket)Pack;
7163
7164 #region Packet Session and User Check
7165 if (m_checkPackets)
7166 {
7167 if (nowWearing.AgentData.SessionID != SessionId ||
7168 nowWearing.AgentData.AgentID != AgentId)
7169 return true;
7170 }
7171 #endregion
7172
7173 AvatarWearingArgs wearingArgs = new AvatarWearingArgs();
7174 for (int i = 0; i < nowWearing.WearableData.Length; i++)
7175 {
7176 //m_log.DebugFormat("[XXX]: Wearable type {0} item {1}", nowWearing.WearableData[i].WearableType, nowWearing.WearableData[i].ItemID);
7177 AvatarWearingArgs.Wearable wearable =
7178 new AvatarWearingArgs.Wearable(nowWearing.WearableData[i].ItemID,
7179 nowWearing.WearableData[i].WearableType);
7180 wearingArgs.NowWearing.Add(wearable);
7181 }
7182
7183 AvatarNowWearing handlerAvatarNowWearing = OnAvatarNowWearing;
7184 if (handlerAvatarNowWearing != null)
7185 {
7186 handlerAvatarNowWearing(this, wearingArgs);
7187 }
7188 }
7189 return true;
7190 }
7191
7192 private bool HandlerRezSingleAttachmentFromInv(IClientAPI sender, Packet Pack)
7193 {
7194 RezSingleAttachmentFromInv handlerRezSingleAttachment = OnRezSingleAttachmentFromInv;
7195 if (handlerRezSingleAttachment != null)
7196 {
7197 RezSingleAttachmentFromInvPacket rez = (RezSingleAttachmentFromInvPacket)Pack;
7198
7199 #region Packet Session and User Check
7200 if (m_checkPackets)
7201 {
7202 if (rez.AgentData.SessionID != SessionId ||
7203 rez.AgentData.AgentID != AgentId)
7204 return true;
7205 }
7206 #endregion
7207
7208 handlerRezSingleAttachment(this, rez.ObjectData.ItemID,
7209 rez.ObjectData.AttachmentPt);
7210 }
7211
7212 return true;
7213 }
7214
7215 private bool HandleRezMultipleAttachmentsFromInv(IClientAPI sender, Packet Pack)
7216 {
7217 RezMultipleAttachmentsFromInv handlerRezMultipleAttachments = OnRezMultipleAttachmentsFromInv;
7218 if (handlerRezMultipleAttachments != null)
7219 {
7220 List<KeyValuePair<UUID, uint>> rezlist = new List<KeyValuePair<UUID, uint>>();
7221 foreach (RezMultipleAttachmentsFromInvPacket.ObjectDataBlock obj in ((RezMultipleAttachmentsFromInvPacket)Pack).ObjectData)
7222 rezlist.Add(new KeyValuePair<UUID, uint>(obj.ItemID, obj.AttachmentPt));
7223 handlerRezMultipleAttachments(this, rezlist);
7224 }
7225
7226 return true;
7227 }
7228
7229 private bool HandleDetachAttachmentIntoInv(IClientAPI sender, Packet Pack)
7230 {
7231 UUIDNameRequest handlerDetachAttachmentIntoInv = OnDetachAttachmentIntoInv;
7232 if (handlerDetachAttachmentIntoInv != null)
7233 {
7234 DetachAttachmentIntoInvPacket detachtoInv = (DetachAttachmentIntoInvPacket)Pack;
7235
7236 #region Packet Session and User Check
7237 // UNSUPPORTED ON THIS PACKET
7238 #endregion
7239
7240 UUID itemID = detachtoInv.ObjectData.ItemID;
7241 // UUID ATTACH_agentID = detachtoInv.ObjectData.AgentID;
7242
7243 handlerDetachAttachmentIntoInv(itemID, this);
7244 }
7245 return true;
7246 }
7247
7248 private bool HandleObjectAttach(IClientAPI sender, Packet Pack)
7249 {
7250 if (OnObjectAttach != null)
7251 {
7252 ObjectAttachPacket att = (ObjectAttachPacket)Pack;
7253
7254 #region Packet Session and User Check
7255 if (m_checkPackets)
7256 {
7257 if (att.AgentData.SessionID != SessionId ||
7258 att.AgentData.AgentID != AgentId)
7259 return true;
7260 }
7261 #endregion
7262
7263 ObjectAttach handlerObjectAttach = OnObjectAttach;
7264
7265 if (handlerObjectAttach != null)
7266 {
7267 if (att.ObjectData.Length > 0)
7268 {
7269 handlerObjectAttach(this, att.ObjectData[0].ObjectLocalID, att.AgentData.AttachmentPoint, false);
7270 }
7271 }
7272 }
7273 return true;
7274 }
7275
7276 private bool HandleObjectDetach(IClientAPI sender, Packet Pack)
7277 {
7278 ObjectDetachPacket dett = (ObjectDetachPacket)Pack;
7279
7280 #region Packet Session and User Check
7281 if (m_checkPackets)
7282 {
7283 if (dett.AgentData.SessionID != SessionId ||
7284 dett.AgentData.AgentID != AgentId)
7285 return true;
7286 }
7287 #endregion
7288
7289 for (int j = 0; j < dett.ObjectData.Length; j++)
7290 {
7291 uint obj = dett.ObjectData[j].ObjectLocalID;
7292 ObjectDeselect handlerObjectDetach = OnObjectDetach;
7293 if (handlerObjectDetach != null)
7294 {
7295 handlerObjectDetach(obj, this);
7296 }
7297
7298 }
7299 return true;
7300 }
7301
7302 private bool HandleObjectDrop(IClientAPI sender, Packet Pack)
7303 {
7304 ObjectDropPacket dropp = (ObjectDropPacket)Pack;
7305
7306 #region Packet Session and User Check
7307 if (m_checkPackets)
7308 {
7309 if (dropp.AgentData.SessionID != SessionId ||
7310 dropp.AgentData.AgentID != AgentId)
7311 return true;
7312 }
7313 #endregion
7314
7315 for (int j = 0; j < dropp.ObjectData.Length; j++)
7316 {
7317 uint obj = dropp.ObjectData[j].ObjectLocalID;
7318 ObjectDrop handlerObjectDrop = OnObjectDrop;
7319 if (handlerObjectDrop != null)
7320 {
7321 handlerObjectDrop(obj, this);
7322 }
7323 }
7324 return true;
7325 }
7326
7327 private bool HandleSetAlwaysRun(IClientAPI sender, Packet Pack)
7328 {
7329 SetAlwaysRunPacket run = (SetAlwaysRunPacket)Pack;
7330
7331 #region Packet Session and User Check
7332 if (m_checkPackets)
7333 {
7334 if (run.AgentData.SessionID != SessionId ||
7335 run.AgentData.AgentID != AgentId)
7336 return true;
7337 }
7338 #endregion
7339
7340 SetAlwaysRun handlerSetAlwaysRun = OnSetAlwaysRun;
7341 if (handlerSetAlwaysRun != null)
7342 handlerSetAlwaysRun(this, run.AgentData.AlwaysRun);
7343
7344 return true;
7345 }
7346
7347 private bool HandleCompleteAgentMovement(IClientAPI sender, Packet Pack)
7348 {
7349 m_log.DebugFormat("[LLClientView] HandleCompleteAgentMovement");
7350
7351 Action<IClientAPI, bool> handlerCompleteMovementToRegion = OnCompleteMovementToRegion;
7352 if (handlerCompleteMovementToRegion != null)
7353 {
7354 handlerCompleteMovementToRegion(sender, true);
7355 }
7356 else
7357 m_log.Debug("HandleCompleteAgentMovement NULL handler");
7358
7359 handlerCompleteMovementToRegion = null;
7360
7361 return true;
7362 }
7363
7364 private bool HandleAgentAnimation(IClientAPI sender, Packet Pack)
7365 {
7366 AgentAnimationPacket AgentAni = (AgentAnimationPacket)Pack;
7367
7368 #region Packet Session and User Check
7369 if (m_checkPackets)
7370 {
7371 if (AgentAni.AgentData.SessionID != SessionId ||
7372 AgentAni.AgentData.AgentID != AgentId)
7373 return true;
7374 }
7375 #endregion
7376/*
7377 StartAnim handlerStartAnim = null;
7378 StopAnim handlerStopAnim = null;
7379
7380 for (int i = 0; i < AgentAni.AnimationList.Length; i++)
7381 {
7382 if (AgentAni.AnimationList[i].StartAnim)
7383 {
7384 handlerStartAnim = OnStartAnim;
7385 if (handlerStartAnim != null)
7386 {
7387 handlerStartAnim(this, AgentAni.AnimationList[i].AnimID);
7388 }
7389 }
7390 else
7391 {
7392 handlerStopAnim = OnStopAnim;
7393 if (handlerStopAnim != null)
7394 {
7395 handlerStopAnim(this, AgentAni.AnimationList[i].AnimID);
7396 }
7397 }
7398 }
7399 return true;
7400*/
7401 ChangeAnim handlerChangeAnim = null;
7402
7403 for (int i = 0; i < AgentAni.AnimationList.Length; i++)
7404 {
7405 handlerChangeAnim = OnChangeAnim;
7406 if (handlerChangeAnim != null)
7407 {
7408 handlerChangeAnim(AgentAni.AnimationList[i].AnimID, AgentAni.AnimationList[i].StartAnim, false);
7409 }
7410 }
7411
7412 handlerChangeAnim = OnChangeAnim;
7413 if (handlerChangeAnim != null)
7414 {
7415 handlerChangeAnim(UUID.Zero, false, true);
7416 }
7417
7418 return true;
7419 }
7420
7421 private bool HandleAgentRequestSit(IClientAPI sender, Packet Pack)
7422 {
7423 if (OnAgentRequestSit != null)
7424 {
7425 AgentRequestSitPacket agentRequestSit = (AgentRequestSitPacket)Pack;
7426
7427 #region Packet Session and User Check
7428 if (m_checkPackets)
7429 {
7430 if (agentRequestSit.AgentData.SessionID != SessionId ||
7431 agentRequestSit.AgentData.AgentID != AgentId)
7432 return true;
7433 }
7434 #endregion
7435
7436 if (SceneAgent.IsChildAgent)
7437 {
7438 SendCantSitBecauseChildAgentResponse();
7439 return true;
7440 }
7441
7442 AgentRequestSit handlerAgentRequestSit = OnAgentRequestSit;
7443
7444 if (handlerAgentRequestSit != null)
7445 handlerAgentRequestSit(this, agentRequestSit.AgentData.AgentID,
7446 agentRequestSit.TargetObject.TargetID, agentRequestSit.TargetObject.Offset);
7447 }
7448 return true;
7449 }
7450
7451 private bool HandleAgentSit(IClientAPI sender, Packet Pack)
7452 {
7453 if (OnAgentSit != null)
7454 {
7455 AgentSitPacket agentSit = (AgentSitPacket)Pack;
7456
7457 #region Packet Session and User Check
7458 if (m_checkPackets)
7459 {
7460 if (agentSit.AgentData.SessionID != SessionId ||
7461 agentSit.AgentData.AgentID != AgentId)
7462 return true;
7463 }
7464 #endregion
7465
7466 if (SceneAgent.IsChildAgent)
7467 {
7468 SendCantSitBecauseChildAgentResponse();
7469 return true;
7470 }
7471
7472 AgentSit handlerAgentSit = OnAgentSit;
7473 if (handlerAgentSit != null)
7474 {
7475 OnAgentSit(this, agentSit.AgentData.AgentID);
7476 }
7477 }
7478 return true;
7479 }
7480
7481 /// <summary>
7482 /// Used when a child agent gets a sit response which should not be fulfilled.
7483 /// </summary>
7484 private void SendCantSitBecauseChildAgentResponse()
7485 {
7486 SendAlertMessage("Try moving closer. Can't sit on object because it is not in the same region as you.");
7487 }
7488
7489 private bool HandleSoundTrigger(IClientAPI sender, Packet Pack)
7490 {
7491 SoundTriggerPacket soundTriggerPacket = (SoundTriggerPacket)Pack;
7492
7493 #region Packet Session and User Check
7494 if (m_checkPackets)
7495 {
7496 // UNSUPPORTED ON THIS PACKET
7497 }
7498 #endregion
7499
7500 SoundTrigger handlerSoundTrigger = OnSoundTrigger;
7501 if (handlerSoundTrigger != null)
7502 {
7503 // UUIDS are sent as zeroes by the client, substitute agent's id
7504 handlerSoundTrigger(soundTriggerPacket.SoundData.SoundID, AgentId,
7505 AgentId, AgentId,
7506 soundTriggerPacket.SoundData.Gain, soundTriggerPacket.SoundData.Position,
7507 soundTriggerPacket.SoundData.Handle, 0);
7508
7509 }
7510 return true;
7511 }
7512
7513 private bool HandleAvatarPickerRequest(IClientAPI sender, Packet Pack)
7514 {
7515 AvatarPickerRequestPacket avRequestQuery = (AvatarPickerRequestPacket)Pack;
7516
7517 #region Packet Session and User Check
7518 if (m_checkPackets)
7519 {
7520 if (avRequestQuery.AgentData.SessionID != SessionId ||
7521 avRequestQuery.AgentData.AgentID != AgentId)
7522 return true;
7523 }
7524 #endregion
7525
7526 AvatarPickerRequestPacket.AgentDataBlock Requestdata = avRequestQuery.AgentData;
7527 AvatarPickerRequestPacket.DataBlock querydata = avRequestQuery.Data;
7528 //m_log.Debug("Agent Sends:" + Utils.BytesToString(querydata.Name));
7529
7530 AvatarPickerRequest handlerAvatarPickerRequest = OnAvatarPickerRequest;
7531 if (handlerAvatarPickerRequest != null)
7532 {
7533 handlerAvatarPickerRequest(this, Requestdata.AgentID, Requestdata.QueryID,
7534 Utils.BytesToString(querydata.Name));
7535 }
7536 return true;
7537 }
7538
7539 private bool HandleAgentDataUpdateRequest(IClientAPI sender, Packet Pack)
7540 {
7541 AgentDataUpdateRequestPacket avRequestDataUpdatePacket = (AgentDataUpdateRequestPacket)Pack;
7542
7543 #region Packet Session and User Check
7544 if (m_checkPackets)
7545 {
7546 if (avRequestDataUpdatePacket.AgentData.SessionID != SessionId ||
7547 avRequestDataUpdatePacket.AgentData.AgentID != AgentId)
7548 return true;
7549 }
7550 #endregion
7551
7552 FetchInventory handlerAgentDataUpdateRequest = OnAgentDataUpdateRequest;
7553
7554 if (handlerAgentDataUpdateRequest != null)
7555 {
7556 handlerAgentDataUpdateRequest(this, avRequestDataUpdatePacket.AgentData.AgentID, avRequestDataUpdatePacket.AgentData.SessionID);
7557 }
7558
7559 return true;
7560 }
7561
7562 private bool HandleUserInfoRequest(IClientAPI sender, Packet Pack)
7563 {
7564 UserInfoRequest handlerUserInfoRequest = OnUserInfoRequest;
7565 if (handlerUserInfoRequest != null)
7566 {
7567 handlerUserInfoRequest(this);
7568 }
7569 else
7570 {
7571 SendUserInfoReply(false, true, "");
7572 }
7573 return true;
7574 }
7575
7576 private bool HandleUpdateUserInfo(IClientAPI sender, Packet Pack)
7577 {
7578 UpdateUserInfoPacket updateUserInfo = (UpdateUserInfoPacket)Pack;
7579
7580 #region Packet Session and User Check
7581 if (m_checkPackets)
7582 {
7583 if (updateUserInfo.AgentData.SessionID != SessionId ||
7584 updateUserInfo.AgentData.AgentID != AgentId)
7585 return true;
7586 }
7587 #endregion
7588
7589 UpdateUserInfo handlerUpdateUserInfo = OnUpdateUserInfo;
7590 if (handlerUpdateUserInfo != null)
7591 {
7592 bool visible = true;
7593 string DirectoryVisibility =
7594 Utils.BytesToString(updateUserInfo.UserData.DirectoryVisibility);
7595 if (DirectoryVisibility == "hidden")
7596 visible = false;
7597
7598 handlerUpdateUserInfo(
7599 updateUserInfo.UserData.IMViaEMail,
7600 visible, this);
7601 }
7602 return true;
7603 }
7604
7605 private bool HandleSetStartLocationRequest(IClientAPI sender, Packet Pack)
7606 {
7607 SetStartLocationRequestPacket avSetStartLocationRequestPacket = (SetStartLocationRequestPacket)Pack;
7608
7609 #region Packet Session and User Check
7610 if (m_checkPackets)
7611 {
7612 if (avSetStartLocationRequestPacket.AgentData.SessionID != SessionId ||
7613 avSetStartLocationRequestPacket.AgentData.AgentID != AgentId)
7614 return true;
7615 }
7616 #endregion
7617
7618 if (avSetStartLocationRequestPacket.AgentData.AgentID == AgentId && avSetStartLocationRequestPacket.AgentData.SessionID == SessionId)
7619 {
7620 // Linden Client limitation..
7621 if (avSetStartLocationRequestPacket.StartLocationData.LocationPos.X == 255.5f
7622 || avSetStartLocationRequestPacket.StartLocationData.LocationPos.Y == 255.5f)
7623 {
7624 ScenePresence avatar = null;
7625 if (((Scene)m_scene).TryGetScenePresence(AgentId, out avatar))
7626 {
7627 if (avSetStartLocationRequestPacket.StartLocationData.LocationPos.X == 255.5f)
7628 {
7629 avSetStartLocationRequestPacket.StartLocationData.LocationPos.X = avatar.AbsolutePosition.X;
7630 }
7631 if (avSetStartLocationRequestPacket.StartLocationData.LocationPos.Y == 255.5f)
7632 {
7633 avSetStartLocationRequestPacket.StartLocationData.LocationPos.Y = avatar.AbsolutePosition.Y;
7634 }
7635 }
7636
7637 }
7638 TeleportLocationRequest handlerSetStartLocationRequest = OnSetStartLocationRequest;
7639 if (handlerSetStartLocationRequest != null)
7640 {
7641 handlerSetStartLocationRequest(this, 0, avSetStartLocationRequestPacket.StartLocationData.LocationPos,
7642 avSetStartLocationRequestPacket.StartLocationData.LocationLookAt,
7643 avSetStartLocationRequestPacket.StartLocationData.LocationID);
7644 }
7645 }
7646 return true;
7647 }
7648
7649 private bool HandleAgentThrottle(IClientAPI sender, Packet Pack)
7650 {
7651 AgentThrottlePacket atpack = (AgentThrottlePacket)Pack;
7652
7653 #region Packet Session and User Check
7654 if (m_checkPackets)
7655 {
7656 if (atpack.AgentData.SessionID != SessionId ||
7657 atpack.AgentData.AgentID != AgentId)
7658 return true;
7659 }
7660 #endregion
7661
7662 m_udpClient.SetThrottles(atpack.Throttle.Throttles);
7663 GenericCall2 handler = OnUpdateThrottles;
7664 if (handler != null)
7665 {
7666 handler();
7667 }
7668 return true;
7669 }
7670
7671 private bool HandleAgentPause(IClientAPI sender, Packet Pack)
7672 {
7673 m_udpClient.IsPaused = true;
7674 return true;
7675 }
7676
7677 private bool HandleAgentResume(IClientAPI sender, Packet Pack)
7678 {
7679 m_udpClient.IsPaused = false;
7680 SendStartPingCheck(m_udpClient.CurrentPingSequence++);
7681 return true;
7682 }
7683
7684 private bool HandleForceScriptControlRelease(IClientAPI sender, Packet Pack)
7685 {
7686 ForceReleaseControls handlerForceReleaseControls = OnForceReleaseControls;
7687 if (handlerForceReleaseControls != null)
7688 {
7689 handlerForceReleaseControls(this, AgentId);
7690 }
7691 return true;
7692 }
7693
7694 #endregion Scene/Avatar
7695
7696 #region Objects/m_sceneObjects
7697
7698 private bool HandleObjectLink(IClientAPI sender, Packet Pack)
7699 {
7700 ObjectLinkPacket link = (ObjectLinkPacket)Pack;
7701
7702 #region Packet Session and User Check
7703 if (m_checkPackets)
7704 {
7705 if (link.AgentData.SessionID != SessionId ||
7706 link.AgentData.AgentID != AgentId)
7707 return true;
7708 }
7709 #endregion
7710
7711 uint parentprimid = 0;
7712 List<uint> childrenprims = new List<uint>();
7713 if (link.ObjectData.Length > 1)
7714 {
7715 parentprimid = link.ObjectData[0].ObjectLocalID;
7716
7717 for (int i = 1; i < link.ObjectData.Length; i++)
7718 {
7719 childrenprims.Add(link.ObjectData[i].ObjectLocalID);
7720 }
7721 }
7722 LinkObjects handlerLinkObjects = OnLinkObjects;
7723 if (handlerLinkObjects != null)
7724 {
7725 handlerLinkObjects(this, parentprimid, childrenprims);
7726 }
7727 return true;
7728 }
7729
7730 private bool HandleObjectDelink(IClientAPI sender, Packet Pack)
7731 {
7732 ObjectDelinkPacket delink = (ObjectDelinkPacket)Pack;
7733
7734 #region Packet Session and User Check
7735 if (m_checkPackets)
7736 {
7737 if (delink.AgentData.SessionID != SessionId ||
7738 delink.AgentData.AgentID != AgentId)
7739 return true;
7740 }
7741 #endregion
7742
7743 // It appears the prim at index 0 is not always the root prim (for
7744 // instance, when one prim of a link set has been edited independently
7745 // of the others). Therefore, we'll pass all the ids onto the delink
7746 // method for it to decide which is the root.
7747 List<uint> prims = new List<uint>();
7748 for (int i = 0; i < delink.ObjectData.Length; i++)
7749 {
7750 prims.Add(delink.ObjectData[i].ObjectLocalID);
7751 }
7752 DelinkObjects handlerDelinkObjects = OnDelinkObjects;
7753 if (handlerDelinkObjects != null)
7754 {
7755 handlerDelinkObjects(prims, this);
7756 }
7757
7758 return true;
7759 }
7760
7761 private bool HandleObjectAdd(IClientAPI sender, Packet Pack)
7762 {
7763 if (OnAddPrim != null)
7764 {
7765 ObjectAddPacket addPacket = (ObjectAddPacket)Pack;
7766
7767 #region Packet Session and User Check
7768 if (m_checkPackets)
7769 {
7770 if (addPacket.AgentData.SessionID != SessionId ||
7771 addPacket.AgentData.AgentID != AgentId)
7772 return true;
7773 }
7774 #endregion
7775
7776 PrimitiveBaseShape shape = GetShapeFromAddPacket(addPacket);
7777 // m_log.Info("[REZData]: " + addPacket.ToString());
7778 //BypassRaycast: 1
7779 //RayStart: <69.79469, 158.2652, 98.40343>
7780 //RayEnd: <61.97724, 141.995, 92.58341>
7781 //RayTargetID: 00000000-0000-0000-0000-000000000000
7782
7783 //Check to see if adding the prim is allowed; useful for any module wanting to restrict the
7784 //object from rezing initially
7785
7786 AddNewPrim handlerAddPrim = OnAddPrim;
7787 if (handlerAddPrim != null)
7788 handlerAddPrim(AgentId, addPacket.AgentData.GroupID, addPacket.ObjectData.RayEnd, addPacket.ObjectData.Rotation, shape, addPacket.ObjectData.BypassRaycast, addPacket.ObjectData.RayStart, addPacket.ObjectData.RayTargetID, addPacket.ObjectData.RayEndIsIntersection);
7789 }
7790 return true;
7791 }
7792
7793 private bool HandleObjectShape(IClientAPI sender, Packet Pack)
7794 {
7795 ObjectShapePacket shapePacket = (ObjectShapePacket)Pack;
7796
7797 #region Packet Session and User Check
7798 if (m_checkPackets)
7799 {
7800 if (shapePacket.AgentData.SessionID != SessionId ||
7801 shapePacket.AgentData.AgentID != AgentId)
7802 return true;
7803 }
7804 #endregion
7805
7806 UpdateShape handlerUpdatePrimShape = null;
7807 for (int i = 0; i < shapePacket.ObjectData.Length; i++)
7808 {
7809 handlerUpdatePrimShape = OnUpdatePrimShape;
7810 if (handlerUpdatePrimShape != null)
7811 {
7812 UpdateShapeArgs shapeData = new UpdateShapeArgs();
7813 shapeData.ObjectLocalID = shapePacket.ObjectData[i].ObjectLocalID;
7814 shapeData.PathBegin = shapePacket.ObjectData[i].PathBegin;
7815 shapeData.PathCurve = shapePacket.ObjectData[i].PathCurve;
7816 shapeData.PathEnd = shapePacket.ObjectData[i].PathEnd;
7817 shapeData.PathRadiusOffset = shapePacket.ObjectData[i].PathRadiusOffset;
7818 shapeData.PathRevolutions = shapePacket.ObjectData[i].PathRevolutions;
7819 shapeData.PathScaleX = shapePacket.ObjectData[i].PathScaleX;
7820 shapeData.PathScaleY = shapePacket.ObjectData[i].PathScaleY;
7821 shapeData.PathShearX = shapePacket.ObjectData[i].PathShearX;
7822 shapeData.PathShearY = shapePacket.ObjectData[i].PathShearY;
7823 shapeData.PathSkew = shapePacket.ObjectData[i].PathSkew;
7824 shapeData.PathTaperX = shapePacket.ObjectData[i].PathTaperX;
7825 shapeData.PathTaperY = shapePacket.ObjectData[i].PathTaperY;
7826 shapeData.PathTwist = shapePacket.ObjectData[i].PathTwist;
7827 shapeData.PathTwistBegin = shapePacket.ObjectData[i].PathTwistBegin;
7828 shapeData.ProfileBegin = shapePacket.ObjectData[i].ProfileBegin;
7829 shapeData.ProfileCurve = shapePacket.ObjectData[i].ProfileCurve;
7830 shapeData.ProfileEnd = shapePacket.ObjectData[i].ProfileEnd;
7831 shapeData.ProfileHollow = shapePacket.ObjectData[i].ProfileHollow;
7832
7833 handlerUpdatePrimShape(m_agentId, shapePacket.ObjectData[i].ObjectLocalID,
7834 shapeData);
7835 }
7836 }
7837 return true;
7838 }
7839
7840 private bool HandleObjectExtraParams(IClientAPI sender, Packet Pack)
7841 {
7842 ObjectExtraParamsPacket extraPar = (ObjectExtraParamsPacket)Pack;
7843
7844 #region Packet Session and User Check
7845 if (m_checkPackets)
7846 {
7847 if (extraPar.AgentData.SessionID != SessionId ||
7848 extraPar.AgentData.AgentID != AgentId)
7849 return true;
7850 }
7851 #endregion
7852
7853 ObjectExtraParams handlerUpdateExtraParams = OnUpdateExtraParams;
7854 if (handlerUpdateExtraParams != null)
7855 {
7856 for (int i = 0; i < extraPar.ObjectData.Length; i++)
7857 {
7858 handlerUpdateExtraParams(m_agentId, extraPar.ObjectData[i].ObjectLocalID,
7859 extraPar.ObjectData[i].ParamType,
7860 extraPar.ObjectData[i].ParamInUse, extraPar.ObjectData[i].ParamData);
7861 }
7862 }
7863 return true;
7864 }
7865
7866 private bool HandleObjectDuplicate(IClientAPI sender, Packet Pack)
7867 {
7868 ObjectDuplicatePacket dupe = (ObjectDuplicatePacket)Pack;
7869
7870 #region Packet Session and User Check
7871 if (m_checkPackets)
7872 {
7873 if (dupe.AgentData.SessionID != SessionId ||
7874 dupe.AgentData.AgentID != AgentId)
7875 return true;
7876 }
7877 #endregion
7878
7879// ObjectDuplicatePacket.AgentDataBlock AgentandGroupData = dupe.AgentData;
7880
7881 ObjectDuplicate handlerObjectDuplicate = null;
7882
7883 handlerObjectDuplicate = OnObjectDuplicate;
7884 if (handlerObjectDuplicate != null)
7885 {
7886 for (int i = 0; i < dupe.ObjectData.Length; i++)
7887 {
7888 UUID rezGroupID = dupe.AgentData.GroupID;
7889 if(!IsGroupMember(rezGroupID))
7890 rezGroupID = UUID.Zero;
7891 handlerObjectDuplicate(dupe.ObjectData[i].ObjectLocalID, dupe.SharedData.Offset,
7892 dupe.SharedData.DuplicateFlags, AgentId,
7893 rezGroupID);
7894 }
7895 }
7896
7897 return true;
7898 }
7899
7900 private bool HandleRequestMultipleObjects(IClientAPI sender, Packet Pack)
7901 {
7902 RequestMultipleObjectsPacket incomingRequest = (RequestMultipleObjectsPacket)Pack;
7903
7904 #region Packet Session and User Check
7905 if (m_checkPackets)
7906 {
7907 if (incomingRequest.AgentData.SessionID != SessionId ||
7908 incomingRequest.AgentData.AgentID != AgentId)
7909 return true;
7910 }
7911 #endregion
7912
7913 ObjectRequest handlerObjectRequest = null;
7914
7915 for (int i = 0; i < incomingRequest.ObjectData.Length; i++)
7916 {
7917 handlerObjectRequest = OnObjectRequest;
7918 if (handlerObjectRequest != null)
7919 {
7920 handlerObjectRequest(incomingRequest.ObjectData[i].ID, this);
7921 }
7922 }
7923 return true;
7924 }
7925
7926 private bool HandleObjectSelect(IClientAPI sender, Packet Pack)
7927 {
7928 ObjectSelectPacket incomingselect = (ObjectSelectPacket)Pack;
7929
7930 #region Packet Session and User Check
7931 if (m_checkPackets)
7932 {
7933 if (incomingselect.AgentData.SessionID != SessionId ||
7934 incomingselect.AgentData.AgentID != AgentId)
7935 return true;
7936 }
7937 #endregion
7938 List<uint> thisSelection = new List<uint>();
7939 ObjectSelect handlerObjectSelect = null;
7940 uint objID;
7941 handlerObjectSelect = OnObjectSelect;
7942 if (handlerObjectSelect != null)
7943 {
7944 for (int i = 0; i < incomingselect.ObjectData.Length; i++)
7945 {
7946 objID = incomingselect.ObjectData[i].ObjectLocalID;
7947 thisSelection.Add(objID);
7948 }
7949
7950 handlerObjectSelect(thisSelection, this);
7951 }
7952 return true;
7953 }
7954
7955 private bool HandleObjectDeselect(IClientAPI sender, Packet Pack)
7956 {
7957 ObjectDeselectPacket incomingdeselect = (ObjectDeselectPacket)Pack;
7958
7959 #region Packet Session and User Check
7960 if (m_checkPackets)
7961 {
7962 if (incomingdeselect.AgentData.SessionID != SessionId ||
7963 incomingdeselect.AgentData.AgentID != AgentId)
7964 return true;
7965 }
7966 #endregion
7967
7968 ObjectDeselect handlerObjectDeselect = null;
7969 uint objID;
7970 for (int i = 0; i < incomingdeselect.ObjectData.Length; i++)
7971 {
7972 objID = incomingdeselect.ObjectData[i].ObjectLocalID;
7973
7974 handlerObjectDeselect = OnObjectDeselect;
7975 if (handlerObjectDeselect != null)
7976 {
7977 OnObjectDeselect(objID, this);
7978 }
7979 }
7980 return true;
7981 }
7982
7983 private bool HandleObjectPosition(IClientAPI sender, Packet Pack)
7984 {
7985 // DEPRECATED: but till libsecondlife removes it, people will use it
7986 ObjectPositionPacket position = (ObjectPositionPacket)Pack;
7987
7988 #region Packet Session and User Check
7989 if (m_checkPackets)
7990 {
7991 if (position.AgentData.SessionID != SessionId ||
7992 position.AgentData.AgentID != AgentId)
7993 return true;
7994 }
7995 #endregion
7996
7997
7998 for (int i = 0; i < position.ObjectData.Length; i++)
7999 {
8000 UpdateVector handlerUpdateVector = OnUpdatePrimGroupPosition;
8001 if (handlerUpdateVector != null)
8002 handlerUpdateVector(position.ObjectData[i].ObjectLocalID, position.ObjectData[i].Position, this);
8003 }
8004
8005 return true;
8006 }
8007
8008 private bool HandleObjectScale(IClientAPI sender, Packet Pack)
8009 {
8010 // DEPRECATED: but till libsecondlife removes it, people will use it
8011 ObjectScalePacket scale = (ObjectScalePacket)Pack;
8012
8013 #region Packet Session and User Check
8014 if (m_checkPackets)
8015 {
8016 if (scale.AgentData.SessionID != SessionId ||
8017 scale.AgentData.AgentID != AgentId)
8018 return true;
8019 }
8020 #endregion
8021
8022 for (int i = 0; i < scale.ObjectData.Length; i++)
8023 {
8024 UpdateVector handlerUpdatePrimGroupScale = OnUpdatePrimGroupScale;
8025 if (handlerUpdatePrimGroupScale != null)
8026 handlerUpdatePrimGroupScale(scale.ObjectData[i].ObjectLocalID, scale.ObjectData[i].Scale, this);
8027 }
8028
8029 return true;
8030 }
8031
8032 private bool HandleObjectRotation(IClientAPI sender, Packet Pack)
8033 {
8034 // DEPRECATED: but till libsecondlife removes it, people will use it
8035 ObjectRotationPacket rotation = (ObjectRotationPacket)Pack;
8036
8037 #region Packet Session and User Check
8038 if (m_checkPackets)
8039 {
8040 if (rotation.AgentData.SessionID != SessionId ||
8041 rotation.AgentData.AgentID != AgentId)
8042 return true;
8043 }
8044 #endregion
8045
8046 for (int i = 0; i < rotation.ObjectData.Length; i++)
8047 {
8048 UpdatePrimRotation handlerUpdatePrimRotation = OnUpdatePrimGroupRotation;
8049 if (handlerUpdatePrimRotation != null)
8050 handlerUpdatePrimRotation(rotation.ObjectData[i].ObjectLocalID, rotation.ObjectData[i].Rotation, this);
8051 }
8052
8053 return true;
8054 }
8055
8056 private bool HandleObjectFlagUpdate(IClientAPI sender, Packet Pack)
8057 {
8058 ObjectFlagUpdatePacket flags = (ObjectFlagUpdatePacket)Pack;
8059
8060 #region Packet Session and User Check
8061 if (m_checkPackets)
8062 {
8063 if (flags.AgentData.SessionID != SessionId ||
8064 flags.AgentData.AgentID != AgentId)
8065 return true;
8066 }
8067 #endregion
8068
8069 UpdatePrimFlags handlerUpdatePrimFlags = OnUpdatePrimFlags;
8070
8071 if (handlerUpdatePrimFlags != null)
8072 {
8073// byte[] data = Pack.ToBytes();
8074 // 46,47,48 are special positions within the packet
8075 // This may change so perhaps we need a better way
8076 // of storing this (OMV.FlagUpdatePacket.UsePhysics,etc?)
8077 /*
8078 bool UsePhysics = (data[46] != 0) ? true : false;
8079 bool IsTemporary = (data[47] != 0) ? true : false;
8080 bool IsPhantom = (data[48] != 0) ? true : false;
8081 handlerUpdatePrimFlags(flags.AgentData.ObjectLocalID, UsePhysics, IsTemporary, IsPhantom, this);
8082 */
8083 bool UsePhysics = flags.AgentData.UsePhysics;
8084 bool IsPhantom = flags.AgentData.IsPhantom;
8085 bool IsTemporary = flags.AgentData.IsTemporary;
8086 ObjectFlagUpdatePacket.ExtraPhysicsBlock[] blocks = flags.ExtraPhysics;
8087 ExtraPhysicsData physdata = new ExtraPhysicsData();
8088
8089 if (blocks == null || blocks.Length == 0)
8090 {
8091 physdata.PhysShapeType = PhysShapeType.invalid;
8092 }
8093 else
8094 {
8095 ObjectFlagUpdatePacket.ExtraPhysicsBlock phsblock = blocks[0];
8096 physdata.PhysShapeType = (PhysShapeType)phsblock.PhysicsShapeType;
8097 physdata.Bounce = phsblock.Restitution;
8098 physdata.Density = phsblock.Density;
8099 physdata.Friction = phsblock.Friction;
8100 physdata.GravitationModifier = phsblock.GravityMultiplier;
8101 }
8102
8103 handlerUpdatePrimFlags(flags.AgentData.ObjectLocalID, UsePhysics, IsTemporary, IsPhantom, physdata, this);
8104 }
8105 return true;
8106 }
8107
8108 Dictionary<uint, uint> objImageSeqs = null;
8109 double lastobjImageSeqsMS = 0.0;
8110
8111 private bool HandleObjectImage(IClientAPI sender, Packet Pack)
8112 {
8113 ObjectImagePacket imagePack = (ObjectImagePacket)Pack;
8114
8115 UpdatePrimTexture handlerUpdatePrimTexture = OnUpdatePrimTexture;
8116 if (handlerUpdatePrimTexture == null)
8117 return true;
8118
8119 double now = Util.GetTimeStampMS();
8120 if(objImageSeqs == null || ( now - lastobjImageSeqsMS > 30000.0))
8121 {
8122 objImageSeqs = null; // yeah i know superstition...
8123 objImageSeqs = new Dictionary<uint, uint>(16);
8124 }
8125
8126 lastobjImageSeqsMS = now;
8127 uint seq = Pack.Header.Sequence;
8128 uint id;
8129 uint lastseq;
8130
8131 ObjectImagePacket.ObjectDataBlock o;
8132 for (int i = 0; i < imagePack.ObjectData.Length; i++)
8133 {
8134 o = imagePack.ObjectData[i];
8135 id = o.ObjectLocalID;
8136 if(objImageSeqs.TryGetValue(id, out lastseq))
8137 {
8138 if(seq <= lastseq)
8139 continue;
8140 }
8141 objImageSeqs[id] = seq;
8142 handlerUpdatePrimTexture(id, o.TextureEntry, this);
8143 }
8144 return true;
8145 }
8146
8147 private bool HandleObjectGrab(IClientAPI sender, Packet Pack)
8148 {
8149 ObjectGrabPacket grab = (ObjectGrabPacket)Pack;
8150
8151 #region Packet Session and User Check
8152 if (m_checkPackets)
8153 {
8154 if (grab.AgentData.SessionID != SessionId ||
8155 grab.AgentData.AgentID != AgentId)
8156 return true;
8157 }
8158 #endregion
8159
8160 GrabObject handlerGrabObject = OnGrabObject;
8161
8162 if (handlerGrabObject != null)
8163 {
8164 List<SurfaceTouchEventArgs> touchArgs = new List<SurfaceTouchEventArgs>();
8165 if ((grab.SurfaceInfo != null) && (grab.SurfaceInfo.Length > 0))
8166 {
8167 foreach (ObjectGrabPacket.SurfaceInfoBlock surfaceInfo in grab.SurfaceInfo)
8168 {
8169 SurfaceTouchEventArgs arg = new SurfaceTouchEventArgs();
8170 arg.Binormal = surfaceInfo.Binormal;
8171 arg.FaceIndex = surfaceInfo.FaceIndex;
8172 arg.Normal = surfaceInfo.Normal;
8173 arg.Position = surfaceInfo.Position;
8174 arg.STCoord = surfaceInfo.STCoord;
8175 arg.UVCoord = surfaceInfo.UVCoord;
8176 touchArgs.Add(arg);
8177 }
8178 }
8179 handlerGrabObject(grab.ObjectData.LocalID, grab.ObjectData.GrabOffset, this, touchArgs);
8180 }
8181 return true;
8182 }
8183
8184 private bool HandleObjectGrabUpdate(IClientAPI sender, Packet Pack)
8185 {
8186 ObjectGrabUpdatePacket grabUpdate = (ObjectGrabUpdatePacket)Pack;
8187
8188 #region Packet Session and User Check
8189 if (m_checkPackets)
8190 {
8191 if (grabUpdate.AgentData.SessionID != SessionId ||
8192 grabUpdate.AgentData.AgentID != AgentId)
8193 return true;
8194 }
8195 #endregion
8196
8197 MoveObject handlerGrabUpdate = OnGrabUpdate;
8198
8199 if (handlerGrabUpdate != null)
8200 {
8201 List<SurfaceTouchEventArgs> touchArgs = new List<SurfaceTouchEventArgs>();
8202 if ((grabUpdate.SurfaceInfo != null) && (grabUpdate.SurfaceInfo.Length > 0))
8203 {
8204 foreach (ObjectGrabUpdatePacket.SurfaceInfoBlock surfaceInfo in grabUpdate.SurfaceInfo)
8205 {
8206 SurfaceTouchEventArgs arg = new SurfaceTouchEventArgs();
8207 arg.Binormal = surfaceInfo.Binormal;
8208 arg.FaceIndex = surfaceInfo.FaceIndex;
8209 arg.Normal = surfaceInfo.Normal;
8210 arg.Position = surfaceInfo.Position;
8211 arg.STCoord = surfaceInfo.STCoord;
8212 arg.UVCoord = surfaceInfo.UVCoord;
8213 touchArgs.Add(arg);
8214 }
8215 }
8216
8217 handlerGrabUpdate(grabUpdate.ObjectData.ObjectID, grabUpdate.ObjectData.GrabOffsetInitial,
8218 grabUpdate.ObjectData.GrabPosition, this, touchArgs);
8219 }
8220 return true;
8221 }
8222
8223 private bool HandleObjectDeGrab(IClientAPI sender, Packet Pack)
8224 {
8225 ObjectDeGrabPacket deGrab = (ObjectDeGrabPacket)Pack;
8226
8227 #region Packet Session and User Check
8228 if (m_checkPackets)
8229 {
8230 if (deGrab.AgentData.SessionID != SessionId ||
8231 deGrab.AgentData.AgentID != AgentId)
8232 return true;
8233 }
8234 #endregion
8235
8236 DeGrabObject handlerDeGrabObject = OnDeGrabObject;
8237 if (handlerDeGrabObject != null)
8238 {
8239 List<SurfaceTouchEventArgs> touchArgs = new List<SurfaceTouchEventArgs>();
8240 if ((deGrab.SurfaceInfo != null) && (deGrab.SurfaceInfo.Length > 0))
8241 {
8242 foreach (ObjectDeGrabPacket.SurfaceInfoBlock surfaceInfo in deGrab.SurfaceInfo)
8243 {
8244 SurfaceTouchEventArgs arg = new SurfaceTouchEventArgs();
8245 arg.Binormal = surfaceInfo.Binormal;
8246 arg.FaceIndex = surfaceInfo.FaceIndex;
8247 arg.Normal = surfaceInfo.Normal;
8248 arg.Position = surfaceInfo.Position;
8249 arg.STCoord = surfaceInfo.STCoord;
8250 arg.UVCoord = surfaceInfo.UVCoord;
8251 touchArgs.Add(arg);
8252 }
8253 }
8254 handlerDeGrabObject(deGrab.ObjectData.LocalID, this, touchArgs);
8255 }
8256 return true;
8257 }
8258
8259 private bool HandleObjectSpinStart(IClientAPI sender, Packet Pack)
8260 {
8261 //m_log.Warn("[CLIENT]: unhandled ObjectSpinStart packet");
8262 ObjectSpinStartPacket spinStart = (ObjectSpinStartPacket)Pack;
8263
8264 #region Packet Session and User Check
8265 if (m_checkPackets)
8266 {
8267 if (spinStart.AgentData.SessionID != SessionId ||
8268 spinStart.AgentData.AgentID != AgentId)
8269 return true;
8270 }
8271 #endregion
8272
8273 SpinStart handlerSpinStart = OnSpinStart;
8274 if (handlerSpinStart != null)
8275 {
8276 handlerSpinStart(spinStart.ObjectData.ObjectID, this);
8277 }
8278 return true;
8279 }
8280
8281 private bool HandleObjectSpinUpdate(IClientAPI sender, Packet Pack)
8282 {
8283 //m_log.Warn("[CLIENT]: unhandled ObjectSpinUpdate packet");
8284 ObjectSpinUpdatePacket spinUpdate = (ObjectSpinUpdatePacket)Pack;
8285
8286 #region Packet Session and User Check
8287 if (m_checkPackets)
8288 {
8289 if (spinUpdate.AgentData.SessionID != SessionId ||
8290 spinUpdate.AgentData.AgentID != AgentId)
8291 return true;
8292 }
8293 #endregion
8294
8295 Vector3 axis;
8296 float angle;
8297 spinUpdate.ObjectData.Rotation.GetAxisAngle(out axis, out angle);
8298 //m_log.Warn("[CLIENT]: ObjectSpinUpdate packet rot axis:" + axis + " angle:" + angle);
8299
8300 SpinObject handlerSpinUpdate = OnSpinUpdate;
8301 if (handlerSpinUpdate != null)
8302 {
8303 handlerSpinUpdate(spinUpdate.ObjectData.ObjectID, spinUpdate.ObjectData.Rotation, this);
8304 }
8305 return true;
8306 }
8307
8308 private bool HandleObjectSpinStop(IClientAPI sender, Packet Pack)
8309 {
8310 //m_log.Warn("[CLIENT]: unhandled ObjectSpinStop packet");
8311 ObjectSpinStopPacket spinStop = (ObjectSpinStopPacket)Pack;
8312
8313 #region Packet Session and User Check
8314 if (m_checkPackets)
8315 {
8316 if (spinStop.AgentData.SessionID != SessionId ||
8317 spinStop.AgentData.AgentID != AgentId)
8318 return true;
8319 }
8320 #endregion
8321
8322 SpinStop handlerSpinStop = OnSpinStop;
8323 if (handlerSpinStop != null)
8324 {
8325 handlerSpinStop(spinStop.ObjectData.ObjectID, this);
8326 }
8327 return true;
8328 }
8329
8330 private bool HandleObjectDescription(IClientAPI sender, Packet Pack)
8331 {
8332 ObjectDescriptionPacket objDes = (ObjectDescriptionPacket)Pack;
8333
8334 #region Packet Session and User Check
8335 if (m_checkPackets)
8336 {
8337 if (objDes.AgentData.SessionID != SessionId ||
8338 objDes.AgentData.AgentID != AgentId)
8339 return true;
8340 }
8341 #endregion
8342
8343 GenericCall7 handlerObjectDescription = null;
8344
8345 for (int i = 0; i < objDes.ObjectData.Length; i++)
8346 {
8347 handlerObjectDescription = OnObjectDescription;
8348 if (handlerObjectDescription != null)
8349 {
8350 handlerObjectDescription(this, objDes.ObjectData[i].LocalID,
8351 Util.FieldToString(objDes.ObjectData[i].Description));
8352 }
8353 }
8354 return true;
8355 }
8356
8357 private bool HandleObjectName(IClientAPI sender, Packet Pack)
8358 {
8359 ObjectNamePacket objName = (ObjectNamePacket)Pack;
8360
8361 #region Packet Session and User Check
8362 if (m_checkPackets)
8363 {
8364 if (objName.AgentData.SessionID != SessionId ||
8365 objName.AgentData.AgentID != AgentId)
8366 return true;
8367 }
8368 #endregion
8369
8370 GenericCall7 handlerObjectName = null;
8371 for (int i = 0; i < objName.ObjectData.Length; i++)
8372 {
8373 handlerObjectName = OnObjectName;
8374 if (handlerObjectName != null)
8375 {
8376 handlerObjectName(this, objName.ObjectData[i].LocalID,
8377 Util.FieldToString(objName.ObjectData[i].Name));
8378 }
8379 }
8380 return true;
8381 }
8382
8383 private bool HandleObjectPermissions(IClientAPI sender, Packet Pack)
8384 {
8385 if (OnObjectPermissions != null)
8386 {
8387 ObjectPermissionsPacket newobjPerms = (ObjectPermissionsPacket)Pack;
8388
8389 #region Packet Session and User Check
8390 if (m_checkPackets)
8391 {
8392 if (newobjPerms.AgentData.SessionID != SessionId ||
8393 newobjPerms.AgentData.AgentID != AgentId)
8394 return true;
8395 }
8396 #endregion
8397
8398 UUID AgentID = newobjPerms.AgentData.AgentID;
8399 UUID SessionID = newobjPerms.AgentData.SessionID;
8400
8401 ObjectPermissions handlerObjectPermissions = null;
8402
8403 for (int i = 0; i < newobjPerms.ObjectData.Length; i++)
8404 {
8405 ObjectPermissionsPacket.ObjectDataBlock permChanges = newobjPerms.ObjectData[i];
8406
8407 byte field = permChanges.Field;
8408 uint localID = permChanges.ObjectLocalID;
8409 uint mask = permChanges.Mask;
8410 byte set = permChanges.Set;
8411
8412 handlerObjectPermissions = OnObjectPermissions;
8413
8414 if (handlerObjectPermissions != null)
8415 handlerObjectPermissions(this, AgentID, SessionID, field, localID, mask, set);
8416 }
8417 }
8418
8419 // Here's our data,
8420 // PermField contains the field the info goes into
8421 // PermField determines which mask we're changing
8422 //
8423 // chmask is the mask of the change
8424 // setTF is whether we're adding it or taking it away
8425 //
8426 // objLocalID is the localID of the object.
8427
8428 // Unfortunately, we have to pass the event the packet because objData is an array
8429 // That means multiple object perms may be updated in a single packet.
8430
8431 return true;
8432 }
8433
8434 private bool HandleUndo(IClientAPI sender, Packet Pack)
8435 {
8436 UndoPacket undoitem = (UndoPacket)Pack;
8437
8438 #region Packet Session and User Check
8439 if (m_checkPackets)
8440 {
8441 if (undoitem.AgentData.SessionID != SessionId ||
8442 undoitem.AgentData.AgentID != AgentId)
8443 return true;
8444 }
8445 #endregion
8446
8447 if (undoitem.ObjectData.Length > 0)
8448 {
8449 for (int i = 0; i < undoitem.ObjectData.Length; i++)
8450 {
8451 UUID objiD = undoitem.ObjectData[i].ObjectID;
8452 AgentSit handlerOnUndo = OnUndo;
8453 if (handlerOnUndo != null)
8454 {
8455 handlerOnUndo(this, objiD);
8456 }
8457
8458 }
8459 }
8460 return true;
8461 }
8462
8463 private bool HandleLandUndo(IClientAPI sender, Packet Pack)
8464 {
8465 UndoLandPacket undolanditem = (UndoLandPacket)Pack;
8466
8467 #region Packet Session and User Check
8468 if (m_checkPackets)
8469 {
8470 if (undolanditem.AgentData.SessionID != SessionId ||
8471 undolanditem.AgentData.AgentID != AgentId)
8472 return true;
8473 }
8474 #endregion
8475
8476 LandUndo handlerOnUndo = OnLandUndo;
8477 if (handlerOnUndo != null)
8478 {
8479 handlerOnUndo(this);
8480 }
8481 return true;
8482 }
8483
8484 private bool HandleRedo(IClientAPI sender, Packet Pack)
8485 {
8486 RedoPacket redoitem = (RedoPacket)Pack;
8487
8488 #region Packet Session and User Check
8489 if (m_checkPackets)
8490 {
8491 if (redoitem.AgentData.SessionID != SessionId ||
8492 redoitem.AgentData.AgentID != AgentId)
8493 return true;
8494 }
8495 #endregion
8496
8497 if (redoitem.ObjectData.Length > 0)
8498 {
8499 for (int i = 0; i < redoitem.ObjectData.Length; i++)
8500 {
8501 UUID objiD = redoitem.ObjectData[i].ObjectID;
8502 AgentSit handlerOnRedo = OnRedo;
8503 if (handlerOnRedo != null)
8504 {
8505 handlerOnRedo(this, objiD);
8506 }
8507
8508 }
8509 }
8510 return true;
8511 }
8512
8513 private bool HandleObjectDuplicateOnRay(IClientAPI sender, Packet Pack)
8514 {
8515 ObjectDuplicateOnRayPacket dupeOnRay = (ObjectDuplicateOnRayPacket)Pack;
8516
8517 #region Packet Session and User Check
8518 if (m_checkPackets)
8519 {
8520 if (dupeOnRay.AgentData.SessionID != SessionId ||
8521 dupeOnRay.AgentData.AgentID != AgentId)
8522 return true;
8523 }
8524 #endregion
8525
8526 ObjectDuplicateOnRay handlerObjectDuplicateOnRay = null;
8527
8528 for (int i = 0; i < dupeOnRay.ObjectData.Length; i++)
8529 {
8530 handlerObjectDuplicateOnRay = OnObjectDuplicateOnRay;
8531 if (handlerObjectDuplicateOnRay != null)
8532 {
8533
8534 UUID rezGroupID = dupeOnRay.AgentData.GroupID;
8535 if(!IsGroupMember(rezGroupID))
8536 rezGroupID = UUID.Zero;
8537
8538 handlerObjectDuplicateOnRay(dupeOnRay.ObjectData[i].ObjectLocalID,
8539 dupeOnRay.AgentData.DuplicateFlags, AgentId, rezGroupID,
8540 dupeOnRay.AgentData.RayTargetID, dupeOnRay.AgentData.RayEnd,
8541 dupeOnRay.AgentData.RayStart, dupeOnRay.AgentData.BypassRaycast,
8542 dupeOnRay.AgentData.RayEndIsIntersection,
8543 dupeOnRay.AgentData.CopyCenters, dupeOnRay.AgentData.CopyRotates);
8544 }
8545 }
8546
8547 return true;
8548 }
8549
8550 private bool HandleRequestObjectPropertiesFamily(IClientAPI sender, Packet Pack)
8551 {
8552 //This powers the little tooltip that appears when you move your mouse over an object
8553 RequestObjectPropertiesFamilyPacket packToolTip = (RequestObjectPropertiesFamilyPacket)Pack;
8554
8555 #region Packet Session and User Check
8556 if (m_checkPackets)
8557 {
8558 if (packToolTip.AgentData.SessionID != SessionId ||
8559 packToolTip.AgentData.AgentID != AgentId)
8560 return true;
8561 }
8562 #endregion
8563
8564 RequestObjectPropertiesFamilyPacket.ObjectDataBlock packObjBlock = packToolTip.ObjectData;
8565
8566 RequestObjectPropertiesFamily handlerRequestObjectPropertiesFamily = OnRequestObjectPropertiesFamily;
8567
8568 if (handlerRequestObjectPropertiesFamily != null)
8569 {
8570 handlerRequestObjectPropertiesFamily(this, m_agentId, packObjBlock.RequestFlags,
8571 packObjBlock.ObjectID);
8572 }
8573
8574 return true;
8575 }
8576
8577 private bool HandleObjectIncludeInSearch(IClientAPI sender, Packet Pack)
8578 {
8579 //This lets us set objects to appear in search (stuff like DataSnapshot, etc)
8580 ObjectIncludeInSearchPacket packInSearch = (ObjectIncludeInSearchPacket)Pack;
8581 ObjectIncludeInSearch handlerObjectIncludeInSearch = null;
8582
8583 #region Packet Session and User Check
8584 if (m_checkPackets)
8585 {
8586 if (packInSearch.AgentData.SessionID != SessionId ||
8587 packInSearch.AgentData.AgentID != AgentId)
8588 return true;
8589 }
8590 #endregion
8591
8592 foreach (ObjectIncludeInSearchPacket.ObjectDataBlock objData in packInSearch.ObjectData)
8593 {
8594 bool inSearch = objData.IncludeInSearch;
8595 uint localID = objData.ObjectLocalID;
8596
8597 handlerObjectIncludeInSearch = OnObjectIncludeInSearch;
8598
8599 if (handlerObjectIncludeInSearch != null)
8600 {
8601 handlerObjectIncludeInSearch(this, inSearch, localID);
8602 }
8603 }
8604 return true;
8605 }
8606
8607 private bool HandleScriptAnswerYes(IClientAPI sender, Packet Pack)
8608 {
8609 ScriptAnswerYesPacket scriptAnswer = (ScriptAnswerYesPacket)Pack;
8610
8611 #region Packet Session and User Check
8612 if (m_checkPackets)
8613 {
8614 if (scriptAnswer.AgentData.SessionID != SessionId ||
8615 scriptAnswer.AgentData.AgentID != AgentId)
8616 return true;
8617 }
8618 #endregion
8619
8620 ScriptAnswer handlerScriptAnswer = OnScriptAnswer;
8621 if (handlerScriptAnswer != null)
8622 {
8623 handlerScriptAnswer(this, scriptAnswer.Data.TaskID, scriptAnswer.Data.ItemID, scriptAnswer.Data.Questions);
8624 }
8625 return true;
8626 }
8627
8628 private bool HandleObjectClickAction(IClientAPI sender, Packet Pack)
8629 {
8630 ObjectClickActionPacket ocpacket = (ObjectClickActionPacket)Pack;
8631
8632 #region Packet Session and User Check
8633 if (m_checkPackets)
8634 {
8635 if (ocpacket.AgentData.SessionID != SessionId ||
8636 ocpacket.AgentData.AgentID != AgentId)
8637 return true;
8638 }
8639 #endregion
8640
8641 GenericCall7 handlerObjectClickAction = OnObjectClickAction;
8642 if (handlerObjectClickAction != null)
8643 {
8644 foreach (ObjectClickActionPacket.ObjectDataBlock odata in ocpacket.ObjectData)
8645 {
8646 byte action = odata.ClickAction;
8647 uint localID = odata.ObjectLocalID;
8648 handlerObjectClickAction(this, localID, action.ToString());
8649 }
8650 }
8651 return true;
8652 }
8653
8654 private bool HandleObjectMaterial(IClientAPI sender, Packet Pack)
8655 {
8656 ObjectMaterialPacket ompacket = (ObjectMaterialPacket)Pack;
8657
8658 #region Packet Session and User Check
8659 if (m_checkPackets)
8660 {
8661 if (ompacket.AgentData.SessionID != SessionId ||
8662 ompacket.AgentData.AgentID != AgentId)
8663 return true;
8664 }
8665 #endregion
8666
8667 GenericCall7 handlerObjectMaterial = OnObjectMaterial;
8668 if (handlerObjectMaterial != null)
8669 {
8670 foreach (ObjectMaterialPacket.ObjectDataBlock odata in ompacket.ObjectData)
8671 {
8672 byte material = odata.Material;
8673 uint localID = odata.ObjectLocalID;
8674 handlerObjectMaterial(this, localID, material.ToString());
8675 }
8676 }
8677 return true;
8678 }
8679
8680 #endregion Objects/m_sceneObjects
8681
8682 #region Inventory/Asset/Other related packets
8683
8684 private bool HandleRequestImage(IClientAPI sender, Packet Pack)
8685 {
8686 RequestImagePacket imageRequest = (RequestImagePacket)Pack;
8687 //m_log.Debug("image request: " + Pack.ToString());
8688
8689 #region Packet Session and User Check
8690 if (m_checkPackets)
8691 {
8692 if (imageRequest.AgentData.SessionID != SessionId ||
8693 imageRequest.AgentData.AgentID != AgentId)
8694 return true;
8695 }
8696 #endregion
8697
8698 //handlerTextureRequest = null;
8699 for (int i = 0; i < imageRequest.RequestImage.Length; i++)
8700 {
8701 TextureRequestArgs args = new TextureRequestArgs();
8702
8703 RequestImagePacket.RequestImageBlock block = imageRequest.RequestImage[i];
8704
8705 args.RequestedAssetID = block.Image;
8706 args.DiscardLevel = block.DiscardLevel;
8707 args.PacketNumber = block.Packet;
8708 args.Priority = block.DownloadPriority;
8709 args.requestSequence = imageRequest.Header.Sequence;
8710
8711 // NOTE: This is not a built in part of the LLUDP protocol, but we double the
8712 // priority of avatar textures to get avatars rezzing in faster than the
8713 // surrounding scene
8714 if ((ImageType)block.Type == ImageType.Baked)
8715 args.Priority *= 2.0f;
8716
8717 ImageManager.EnqueueReq(args);
8718 }
8719
8720 return true;
8721 }
8722
8723 /// <summary>
8724 /// This is the entry point for the UDP route by which the client can retrieve asset data. If the request
8725 /// is successful then a TransferInfo packet will be sent back, followed by one or more TransferPackets
8726 /// </summary>
8727 /// <param name="sender"></param>
8728 /// <param name="Pack"></param>
8729 /// <returns>This parameter may be ignored since we appear to return true whatever happens</returns>
8730 private bool HandleTransferRequest(IClientAPI sender, Packet Pack)
8731 {
8732 //m_log.Debug("ClientView.ProcessPackets.cs:ProcessInPacket() - Got transfer request");
8733
8734 TransferRequestPacket transfer = (TransferRequestPacket)Pack;
8735 UUID taskID = UUID.Zero;
8736 if (transfer.TransferInfo.SourceType == (int)SourceType.SimInventoryItem)
8737 {
8738 if (!(((Scene)m_scene).Permissions.BypassPermissions()))
8739 {
8740 // We're spawning a thread because the permissions check can block this thread
8741 Util.FireAndForget(delegate
8742 {
8743 // This requests the asset if needed
8744 HandleSimInventoryTransferRequestWithPermsCheck(sender, transfer);
8745 }, null, "LLClientView.HandleTransferRequest");
8746
8747 return true;
8748 }
8749 }
8750 else if (transfer.TransferInfo.SourceType == (int)SourceType.SimEstate)
8751 {
8752 //TransferRequestPacket does not include covenant uuid?
8753 //get scene covenant uuid
8754 taskID = m_scene.RegionInfo.RegionSettings.Covenant;
8755 }
8756
8757 // This is non-blocking
8758 MakeAssetRequest(transfer, taskID);
8759
8760 return true;
8761 }
8762
8763 private void HandleSimInventoryTransferRequestWithPermsCheck(IClientAPI sender, TransferRequestPacket transfer)
8764 {
8765 UUID taskID = new UUID(transfer.TransferInfo.Params, 48);
8766 UUID itemID = new UUID(transfer.TransferInfo.Params, 64);
8767 UUID requestID = new UUID(transfer.TransferInfo.Params, 80);
8768
8769 //m_log.DebugFormat(
8770 // "[CLIENT]: Got request for asset {0} from item {1} in prim {2} by {3}",
8771 // requestID, itemID, taskID, Name);
8772
8773 //m_log.Debug("Transfer Request: " + transfer.ToString());
8774 // Validate inventory transfers
8775 // Has to be done here, because AssetCache can't do it
8776 //
8777 if (taskID != UUID.Zero) // Prim
8778 {
8779 SceneObjectPart part = ((Scene)m_scene).GetSceneObjectPart(taskID);
8780
8781 if (part == null)
8782 {
8783 m_log.WarnFormat(
8784 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but prim does not exist",
8785 Name, requestID, itemID, taskID);
8786 return;
8787 }
8788
8789 TaskInventoryItem tii = part.Inventory.GetInventoryItem(itemID);
8790 if (tii == null)
8791 {
8792 m_log.WarnFormat(
8793 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item does not exist",
8794 Name, requestID, itemID, taskID);
8795 return;
8796 }
8797
8798 if (tii.Type == (int)AssetType.LSLText)
8799 {
8800 if (!((Scene)m_scene).Permissions.CanEditScript(itemID, taskID, AgentId))
8801 return;
8802 }
8803 else if (tii.Type == (int)AssetType.Notecard)
8804 {
8805 if (!((Scene)m_scene).Permissions.CanEditNotecard(itemID, taskID, AgentId))
8806 return;
8807 }
8808 else
8809 {
8810 // TODO: Change this code to allow items other than notecards and scripts to be successfully
8811 // shared with group. In fact, this whole block of permissions checking should move to an IPermissionsModule
8812 if (part.OwnerID != AgentId)
8813 {
8814 m_log.WarnFormat(
8815 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the prim is owned by {4}",
8816 Name, requestID, itemID, taskID, part.OwnerID);
8817 return;
8818 }
8819
8820 if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0)
8821 {
8822 m_log.WarnFormat(
8823 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but modify permissions are not set",
8824 Name, requestID, itemID, taskID);
8825 return;
8826 }
8827
8828 if (tii.OwnerID != AgentId)
8829 {
8830 m_log.WarnFormat(
8831 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the item is owned by {4}",
8832 Name, requestID, itemID, taskID, tii.OwnerID);
8833 return;
8834 }
8835
8836 if ((
8837 tii.CurrentPermissions & ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer))
8838 != ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer))
8839 {
8840 m_log.WarnFormat(
8841 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item permissions are not modify/copy/transfer",
8842 Name, requestID, itemID, taskID);
8843 return;
8844 }
8845
8846 if (tii.AssetID != requestID)
8847 {
8848 m_log.WarnFormat(
8849 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but this does not match item's asset {4}",
8850 Name, requestID, itemID, taskID, tii.AssetID);
8851 return;
8852 }
8853 }
8854 }
8855 else // Agent
8856 {
8857 IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>();
8858 if (invAccess != null)
8859 {
8860 if (!invAccess.CanGetAgentInventoryItem(this, itemID, requestID))
8861 return;
8862 }
8863 else
8864 {
8865 return;
8866 }
8867 }
8868
8869 // Permissions out of the way, let's request the asset
8870 MakeAssetRequest(transfer, taskID);
8871
8872 }
8873
8874
8875 private bool HandleAssetUploadRequest(IClientAPI sender, Packet Pack)
8876 {
8877 AssetUploadRequestPacket request = (AssetUploadRequestPacket)Pack;
8878
8879 // m_log.Debug("upload request " + request.ToString());
8880 // m_log.Debug("upload request was for assetid: " + request.AssetBlock.TransactionID.Combine(this.SecureSessionId).ToString());
8881 UUID temp = UUID.Combine(request.AssetBlock.TransactionID, SecureSessionId);
8882
8883 UDPAssetUploadRequest handlerAssetUploadRequest = OnAssetUploadRequest;
8884
8885 if (handlerAssetUploadRequest != null)
8886 {
8887 handlerAssetUploadRequest(this, temp,
8888 request.AssetBlock.TransactionID, request.AssetBlock.Type,
8889 request.AssetBlock.AssetData, request.AssetBlock.StoreLocal,
8890 request.AssetBlock.Tempfile);
8891 }
8892 return true;
8893 }
8894
8895 private bool HandleRequestXfer(IClientAPI sender, Packet Pack)
8896 {
8897 RequestXferPacket xferReq = (RequestXferPacket)Pack;
8898
8899 RequestXfer handlerRequestXfer = OnRequestXfer;
8900
8901 if (handlerRequestXfer != null)
8902 {
8903 handlerRequestXfer(this, xferReq.XferID.ID, Util.FieldToString(xferReq.XferID.Filename));
8904 }
8905 return true;
8906 }
8907
8908 private bool HandleSendXferPacket(IClientAPI sender, Packet Pack)
8909 {
8910 SendXferPacketPacket xferRec = (SendXferPacketPacket)Pack;
8911
8912 XferReceive handlerXferReceive = OnXferReceive;
8913 if (handlerXferReceive != null)
8914 {
8915 handlerXferReceive(this, xferRec.XferID.ID, xferRec.XferID.Packet, xferRec.DataPacket.Data);
8916 }
8917 return true;
8918 }
8919
8920 private bool HandleConfirmXferPacket(IClientAPI sender, Packet Pack)
8921 {
8922 ConfirmXferPacketPacket confirmXfer = (ConfirmXferPacketPacket)Pack;
8923
8924 ConfirmXfer handlerConfirmXfer = OnConfirmXfer;
8925 if (handlerConfirmXfer != null)
8926 {
8927 handlerConfirmXfer(this, confirmXfer.XferID.ID, confirmXfer.XferID.Packet);
8928 }
8929 return true;
8930 }
8931
8932 private bool HandleAbortXfer(IClientAPI sender, Packet Pack)
8933 {
8934 AbortXferPacket abortXfer = (AbortXferPacket)Pack;
8935 AbortXfer handlerAbortXfer = OnAbortXfer;
8936 if (handlerAbortXfer != null)
8937 {
8938 handlerAbortXfer(this, abortXfer.XferID.ID);
8939 }
8940
8941 return true;
8942 }
8943
8944 private bool HandleCreateInventoryFolder(IClientAPI sender, Packet Pack)
8945 {
8946 CreateInventoryFolderPacket invFolder = (CreateInventoryFolderPacket)Pack;
8947
8948 #region Packet Session and User Check
8949 if (m_checkPackets)
8950 {
8951 if (invFolder.AgentData.SessionID != SessionId ||
8952 invFolder.AgentData.AgentID != AgentId)
8953 return true;
8954 }
8955 #endregion
8956
8957 CreateInventoryFolder handlerCreateInventoryFolder = OnCreateNewInventoryFolder;
8958 if (handlerCreateInventoryFolder != null)
8959 {
8960 handlerCreateInventoryFolder(this, invFolder.FolderData.FolderID,
8961 (ushort)invFolder.FolderData.Type,
8962 Util.FieldToString(invFolder.FolderData.Name),
8963 invFolder.FolderData.ParentID);
8964 }
8965 return true;
8966 }
8967
8968 private bool HandleUpdateInventoryFolder(IClientAPI sender, Packet Pack)
8969 {
8970 if (OnUpdateInventoryFolder != null)
8971 {
8972 UpdateInventoryFolderPacket invFolderx = (UpdateInventoryFolderPacket)Pack;
8973
8974 #region Packet Session and User Check
8975 if (m_checkPackets)
8976 {
8977 if (invFolderx.AgentData.SessionID != SessionId ||
8978 invFolderx.AgentData.AgentID != AgentId)
8979 return true;
8980 }
8981 #endregion
8982
8983 UpdateInventoryFolder handlerUpdateInventoryFolder = null;
8984
8985 for (int i = 0; i < invFolderx.FolderData.Length; i++)
8986 {
8987 handlerUpdateInventoryFolder = OnUpdateInventoryFolder;
8988 if (handlerUpdateInventoryFolder != null)
8989 {
8990 OnUpdateInventoryFolder(this, invFolderx.FolderData[i].FolderID,
8991 (ushort)invFolderx.FolderData[i].Type,
8992 Util.FieldToString(invFolderx.FolderData[i].Name),
8993 invFolderx.FolderData[i].ParentID);
8994 }
8995 }
8996 }
8997 return true;
8998 }
8999
9000 private bool HandleMoveInventoryFolder(IClientAPI sender, Packet Pack)
9001 {
9002 if (OnMoveInventoryFolder != null)
9003 {
9004 MoveInventoryFolderPacket invFoldery = (MoveInventoryFolderPacket)Pack;
9005
9006 #region Packet Session and User Check
9007 if (m_checkPackets)
9008 {
9009 if (invFoldery.AgentData.SessionID != SessionId ||
9010 invFoldery.AgentData.AgentID != AgentId)
9011 return true;
9012 }
9013 #endregion
9014
9015 MoveInventoryFolder handlerMoveInventoryFolder = null;
9016
9017 for (int i = 0; i < invFoldery.InventoryData.Length; i++)
9018 {
9019 handlerMoveInventoryFolder = OnMoveInventoryFolder;
9020 if (handlerMoveInventoryFolder != null)
9021 {
9022 OnMoveInventoryFolder(this, invFoldery.InventoryData[i].FolderID,
9023 invFoldery.InventoryData[i].ParentID);
9024 }
9025 }
9026 }
9027 return true;
9028 }
9029
9030 private bool HandleCreateInventoryItem(IClientAPI sender, Packet Pack)
9031 {
9032 CreateInventoryItemPacket createItem = (CreateInventoryItemPacket)Pack;
9033
9034 #region Packet Session and User Check
9035 if (m_checkPackets)
9036 {
9037 if (createItem.AgentData.SessionID != SessionId ||
9038 createItem.AgentData.AgentID != AgentId)
9039 return true;
9040 }
9041 #endregion
9042
9043 CreateNewInventoryItem handlerCreateNewInventoryItem = OnCreateNewInventoryItem;
9044 if (handlerCreateNewInventoryItem != null)
9045 {
9046 handlerCreateNewInventoryItem(this, createItem.InventoryBlock.TransactionID,
9047 createItem.InventoryBlock.FolderID,
9048 createItem.InventoryBlock.CallbackID,
9049 Util.FieldToString(createItem.InventoryBlock.Description),
9050 Util.FieldToString(createItem.InventoryBlock.Name),
9051 createItem.InventoryBlock.InvType,
9052 createItem.InventoryBlock.Type,
9053 createItem.InventoryBlock.WearableType,
9054 createItem.InventoryBlock.NextOwnerMask,
9055 Util.UnixTimeSinceEpoch());
9056 }
9057 return true;
9058 }
9059
9060 private bool HandleLinkInventoryItem(IClientAPI sender, Packet Pack)
9061 {
9062 LinkInventoryItemPacket createLink = (LinkInventoryItemPacket)Pack;
9063
9064 #region Packet Session and User Check
9065 if (m_checkPackets)
9066 {
9067 if (createLink.AgentData.SessionID != SessionId ||
9068 createLink.AgentData.AgentID != AgentId)
9069 return true;
9070 }
9071 #endregion
9072
9073 LinkInventoryItem linkInventoryItem = OnLinkInventoryItem;
9074
9075 if (linkInventoryItem != null)
9076 {
9077 linkInventoryItem(
9078 this,
9079 createLink.InventoryBlock.TransactionID,
9080 createLink.InventoryBlock.FolderID,
9081 createLink.InventoryBlock.CallbackID,
9082 Util.FieldToString(createLink.InventoryBlock.Description),
9083 Util.FieldToString(createLink.InventoryBlock.Name),
9084 createLink.InventoryBlock.InvType,
9085 createLink.InventoryBlock.Type,
9086 createLink.InventoryBlock.OldItemID);
9087 }
9088
9089 return true;
9090 }
9091
9092 private bool HandleFetchInventory(IClientAPI sender, Packet Pack)
9093 {
9094 if (OnFetchInventory != null)
9095 {
9096 FetchInventoryPacket FetchInventoryx = (FetchInventoryPacket)Pack;
9097
9098 #region Packet Session and User Check
9099 if (m_checkPackets)
9100 {
9101 if (FetchInventoryx.AgentData.SessionID != SessionId ||
9102 FetchInventoryx.AgentData.AgentID != AgentId)
9103 return true;
9104 }
9105 #endregion
9106
9107 FetchInventory handlerFetchInventory = null;
9108
9109 for (int i = 0; i < FetchInventoryx.InventoryData.Length; i++)
9110 {
9111 handlerFetchInventory = OnFetchInventory;
9112
9113 if (handlerFetchInventory != null)
9114 {
9115 OnFetchInventory(this, FetchInventoryx.InventoryData[i].ItemID,
9116 FetchInventoryx.InventoryData[i].OwnerID);
9117 }
9118 }
9119 }
9120 return true;
9121 }
9122
9123 private bool HandleFetchInventoryDescendents(IClientAPI sender, Packet Pack)
9124 {
9125 FetchInventoryDescendentsPacket Fetch = (FetchInventoryDescendentsPacket)Pack;
9126
9127 #region Packet Session and User Check
9128 if (m_checkPackets)
9129 {
9130 if (Fetch.AgentData.SessionID != SessionId ||
9131 Fetch.AgentData.AgentID != AgentId)
9132 return true;
9133 }
9134 #endregion
9135
9136 FetchInventoryDescendents handlerFetchInventoryDescendents = OnFetchInventoryDescendents;
9137 if (handlerFetchInventoryDescendents != null)
9138 {
9139 handlerFetchInventoryDescendents(this, Fetch.InventoryData.FolderID, Fetch.InventoryData.OwnerID,
9140 Fetch.InventoryData.FetchFolders, Fetch.InventoryData.FetchItems,
9141 Fetch.InventoryData.SortOrder);
9142 }
9143 return true;
9144 }
9145
9146 private bool HandlePurgeInventoryDescendents(IClientAPI sender, Packet Pack)
9147 {
9148 PurgeInventoryDescendentsPacket Purge = (PurgeInventoryDescendentsPacket)Pack;
9149
9150 #region Packet Session and User Check
9151 if (m_checkPackets)
9152 {
9153 if (Purge.AgentData.SessionID != SessionId ||
9154 Purge.AgentData.AgentID != AgentId)
9155 return true;
9156 }
9157 #endregion
9158
9159 PurgeInventoryDescendents handlerPurgeInventoryDescendents = OnPurgeInventoryDescendents;
9160 if (handlerPurgeInventoryDescendents != null)
9161 {
9162 handlerPurgeInventoryDescendents(this, Purge.InventoryData.FolderID);
9163 }
9164 return true;
9165 }
9166
9167 private bool HandleUpdateInventoryItem(IClientAPI sender, Packet Pack)
9168 {
9169 UpdateInventoryItemPacket inventoryItemUpdate = (UpdateInventoryItemPacket)Pack;
9170
9171 #region Packet Session and User Check
9172 if (m_checkPackets)
9173 {
9174 if (inventoryItemUpdate.AgentData.SessionID != SessionId ||
9175 inventoryItemUpdate.AgentData.AgentID != AgentId)
9176 return true;
9177 }
9178 #endregion
9179
9180 if (OnUpdateInventoryItem != null)
9181 {
9182 UpdateInventoryItem handlerUpdateInventoryItem = null;
9183 for (int i = 0; i < inventoryItemUpdate.InventoryData.Length; i++)
9184 {
9185 handlerUpdateInventoryItem = OnUpdateInventoryItem;
9186
9187 if (handlerUpdateInventoryItem != null)
9188 {
9189 InventoryItemBase itemUpd = new InventoryItemBase();
9190 itemUpd.ID = inventoryItemUpdate.InventoryData[i].ItemID;
9191 itemUpd.Name = Util.FieldToString(inventoryItemUpdate.InventoryData[i].Name);
9192 itemUpd.Description = Util.FieldToString(inventoryItemUpdate.InventoryData[i].Description);
9193 itemUpd.GroupID = inventoryItemUpdate.InventoryData[i].GroupID;
9194 itemUpd.GroupOwned = inventoryItemUpdate.InventoryData[i].GroupOwned;
9195 itemUpd.GroupPermissions = inventoryItemUpdate.InventoryData[i].GroupMask;
9196 itemUpd.NextPermissions = inventoryItemUpdate.InventoryData[i].NextOwnerMask;
9197 itemUpd.EveryOnePermissions = inventoryItemUpdate.InventoryData[i].EveryoneMask;
9198 itemUpd.CreationDate = inventoryItemUpdate.InventoryData[i].CreationDate;
9199 itemUpd.Folder = inventoryItemUpdate.InventoryData[i].FolderID;
9200 itemUpd.InvType = inventoryItemUpdate.InventoryData[i].InvType;
9201 itemUpd.SalePrice = inventoryItemUpdate.InventoryData[i].SalePrice;
9202 itemUpd.SaleType = inventoryItemUpdate.InventoryData[i].SaleType;
9203 itemUpd.Flags = inventoryItemUpdate.InventoryData[i].Flags;
9204
9205 OnUpdateInventoryItem(this, inventoryItemUpdate.InventoryData[i].TransactionID,
9206 inventoryItemUpdate.InventoryData[i].ItemID,
9207 itemUpd);
9208 }
9209 }
9210 }
9211 return true;
9212 }
9213
9214 private bool HandleCopyInventoryItem(IClientAPI sender, Packet Pack)
9215 {
9216 CopyInventoryItemPacket copyitem = (CopyInventoryItemPacket)Pack;
9217
9218 #region Packet Session and User Check
9219 if (m_checkPackets)
9220 {
9221 if (copyitem.AgentData.SessionID != SessionId ||
9222 copyitem.AgentData.AgentID != AgentId)
9223 return true;
9224 }
9225 #endregion
9226
9227 CopyInventoryItem handlerCopyInventoryItem = null;
9228 if (OnCopyInventoryItem != null)
9229 {
9230 foreach (CopyInventoryItemPacket.InventoryDataBlock datablock in copyitem.InventoryData)
9231 {
9232 handlerCopyInventoryItem = OnCopyInventoryItem;
9233 if (handlerCopyInventoryItem != null)
9234 {
9235 handlerCopyInventoryItem(this, datablock.CallbackID, datablock.OldAgentID,
9236 datablock.OldItemID, datablock.NewFolderID,
9237 Util.FieldToString(datablock.NewName));
9238 }
9239 }
9240 }
9241 return true;
9242 }
9243
9244 private bool HandleMoveInventoryItem(IClientAPI sender, Packet Pack)
9245 {
9246 MoveInventoryItemPacket moveitem = (MoveInventoryItemPacket)Pack;
9247
9248 #region Packet Session and User Check
9249 if (m_checkPackets)
9250 {
9251 if (moveitem.AgentData.SessionID != SessionId ||
9252 moveitem.AgentData.AgentID != AgentId)
9253 return true;
9254 }
9255 #endregion
9256
9257 if (OnMoveInventoryItem != null)
9258 {
9259 MoveInventoryItem handlerMoveInventoryItem = null;
9260 InventoryItemBase itm = null;
9261 List<InventoryItemBase> items = new List<InventoryItemBase>();
9262 foreach (MoveInventoryItemPacket.InventoryDataBlock datablock in moveitem.InventoryData)
9263 {
9264 itm = new InventoryItemBase(datablock.ItemID, AgentId);
9265 itm.Folder = datablock.FolderID;
9266 itm.Name = Util.FieldToString(datablock.NewName);
9267 // weird, comes out as empty string
9268 //m_log.DebugFormat("[XXX] new name: {0}", itm.Name);
9269 items.Add(itm);
9270 }
9271 handlerMoveInventoryItem = OnMoveInventoryItem;
9272 if (handlerMoveInventoryItem != null)
9273 {
9274 handlerMoveInventoryItem(this, items);
9275 }
9276 }
9277 return true;
9278 }
9279
9280 private bool HandleRemoveInventoryItem(IClientAPI sender, Packet Pack)
9281 {
9282 RemoveInventoryItemPacket removeItem = (RemoveInventoryItemPacket)Pack;
9283
9284 #region Packet Session and User Check
9285 if (m_checkPackets)
9286 {
9287 if (removeItem.AgentData.SessionID != SessionId ||
9288 removeItem.AgentData.AgentID != AgentId)
9289 return true;
9290 }
9291 #endregion
9292
9293 if (OnRemoveInventoryItem != null)
9294 {
9295 RemoveInventoryItem handlerRemoveInventoryItem = null;
9296 List<UUID> uuids = new List<UUID>();
9297 foreach (RemoveInventoryItemPacket.InventoryDataBlock datablock in removeItem.InventoryData)
9298 {
9299 uuids.Add(datablock.ItemID);
9300 }
9301 handlerRemoveInventoryItem = OnRemoveInventoryItem;
9302 if (handlerRemoveInventoryItem != null)
9303 {
9304 handlerRemoveInventoryItem(this, uuids);
9305 }
9306
9307 }
9308 return true;
9309 }
9310
9311 private bool HandleRemoveInventoryFolder(IClientAPI sender, Packet Pack)
9312 {
9313 RemoveInventoryFolderPacket removeFolder = (RemoveInventoryFolderPacket)Pack;
9314
9315 #region Packet Session and User Check
9316 if (m_checkPackets)
9317 {
9318 if (removeFolder.AgentData.SessionID != SessionId ||
9319 removeFolder.AgentData.AgentID != AgentId)
9320 return true;
9321 }
9322 #endregion
9323
9324 if (OnRemoveInventoryFolder != null)
9325 {
9326 RemoveInventoryFolder handlerRemoveInventoryFolder = null;
9327 List<UUID> uuids = new List<UUID>();
9328 foreach (RemoveInventoryFolderPacket.FolderDataBlock datablock in removeFolder.FolderData)
9329 {
9330 uuids.Add(datablock.FolderID);
9331 }
9332 handlerRemoveInventoryFolder = OnRemoveInventoryFolder;
9333 if (handlerRemoveInventoryFolder != null)
9334 {
9335 handlerRemoveInventoryFolder(this, uuids);
9336 }
9337 }
9338 return true;
9339 }
9340
9341 private bool HandleRemoveInventoryObjects(IClientAPI sender, Packet Pack)
9342 {
9343 RemoveInventoryObjectsPacket removeObject = (RemoveInventoryObjectsPacket)Pack;
9344 #region Packet Session and User Check
9345 if (m_checkPackets)
9346 {
9347 if (removeObject.AgentData.SessionID != SessionId ||
9348 removeObject.AgentData.AgentID != AgentId)
9349 return true;
9350 }
9351 #endregion
9352 if (OnRemoveInventoryFolder != null)
9353 {
9354 RemoveInventoryFolder handlerRemoveInventoryFolder = null;
9355 List<UUID> uuids = new List<UUID>();
9356 foreach (RemoveInventoryObjectsPacket.FolderDataBlock datablock in removeObject.FolderData)
9357 {
9358 uuids.Add(datablock.FolderID);
9359 }
9360 handlerRemoveInventoryFolder = OnRemoveInventoryFolder;
9361 if (handlerRemoveInventoryFolder != null)
9362 {
9363 handlerRemoveInventoryFolder(this, uuids);
9364 }
9365 }
9366
9367 if (OnRemoveInventoryItem != null)
9368 {
9369 RemoveInventoryItem handlerRemoveInventoryItem = null;
9370 List<UUID> uuids = new List<UUID>();
9371 foreach (RemoveInventoryObjectsPacket.ItemDataBlock datablock in removeObject.ItemData)
9372 {
9373 uuids.Add(datablock.ItemID);
9374 }
9375 handlerRemoveInventoryItem = OnRemoveInventoryItem;
9376 if (handlerRemoveInventoryItem != null)
9377 {
9378 handlerRemoveInventoryItem(this, uuids);
9379 }
9380 }
9381 return true;
9382 }
9383
9384 private bool HandleRequestTaskInventory(IClientAPI sender, Packet Pack)
9385 {
9386 RequestTaskInventoryPacket requesttask = (RequestTaskInventoryPacket)Pack;
9387
9388 #region Packet Session and User Check
9389 if (m_checkPackets)
9390 {
9391 if (requesttask.AgentData.SessionID != SessionId ||
9392 requesttask.AgentData.AgentID != AgentId)
9393 return true;
9394 }
9395 #endregion
9396
9397 RequestTaskInventory handlerRequestTaskInventory = OnRequestTaskInventory;
9398 if (handlerRequestTaskInventory != null)
9399 {
9400 handlerRequestTaskInventory(this, requesttask.InventoryData.LocalID);
9401 }
9402 return true;
9403 }
9404
9405 private bool HandleUpdateTaskInventory(IClientAPI sender, Packet Pack)
9406 {
9407 UpdateTaskInventoryPacket updatetask = (UpdateTaskInventoryPacket)Pack;
9408
9409 #region Packet Session and User Check
9410 if (m_checkPackets)
9411 {
9412 if (updatetask.AgentData.SessionID != SessionId ||
9413 updatetask.AgentData.AgentID != AgentId)
9414 return true;
9415 }
9416 #endregion
9417
9418 if (OnUpdateTaskInventory != null)
9419 {
9420 if (updatetask.UpdateData.Key == 0)
9421 {
9422 UpdateTaskInventory handlerUpdateTaskInventory = OnUpdateTaskInventory;
9423 if (handlerUpdateTaskInventory != null)
9424 {
9425 TaskInventoryItem newTaskItem = new TaskInventoryItem();
9426 newTaskItem.ItemID = updatetask.InventoryData.ItemID;
9427 newTaskItem.ParentID = updatetask.InventoryData.FolderID;
9428 newTaskItem.CreatorID = updatetask.InventoryData.CreatorID;
9429 newTaskItem.OwnerID = updatetask.InventoryData.OwnerID;
9430 newTaskItem.GroupID = updatetask.InventoryData.GroupID;
9431 newTaskItem.BasePermissions = updatetask.InventoryData.BaseMask;
9432 newTaskItem.CurrentPermissions = updatetask.InventoryData.OwnerMask;
9433 newTaskItem.GroupPermissions = updatetask.InventoryData.GroupMask;
9434 newTaskItem.EveryonePermissions = updatetask.InventoryData.EveryoneMask;
9435 newTaskItem.NextPermissions = updatetask.InventoryData.NextOwnerMask;
9436
9437 // Unused? Clicking share with group sets GroupPermissions instead, so perhaps this is something
9438 // different
9439 //newTaskItem.GroupOwned=updatetask.InventoryData.GroupOwned;
9440 newTaskItem.Type = updatetask.InventoryData.Type;
9441 newTaskItem.InvType = updatetask.InventoryData.InvType;
9442 newTaskItem.Flags = updatetask.InventoryData.Flags;
9443 //newTaskItem.SaleType=updatetask.InventoryData.SaleType;
9444 //newTaskItem.SalePrice=updatetask.InventoryData.SalePrice;
9445 newTaskItem.Name = Util.FieldToString(updatetask.InventoryData.Name);
9446 newTaskItem.Description = Util.FieldToString(updatetask.InventoryData.Description);
9447 newTaskItem.CreationDate = (uint)updatetask.InventoryData.CreationDate;
9448 handlerUpdateTaskInventory(this, updatetask.InventoryData.TransactionID,
9449 newTaskItem, updatetask.UpdateData.LocalID);
9450 }
9451 }
9452 }
9453
9454 return true;
9455 }
9456
9457 private bool HandleRemoveTaskInventory(IClientAPI sender, Packet Pack)
9458 {
9459 RemoveTaskInventoryPacket removeTask = (RemoveTaskInventoryPacket)Pack;
9460
9461 #region Packet Session and User Check
9462 if (m_checkPackets)
9463 {
9464 if (removeTask.AgentData.SessionID != SessionId ||
9465 removeTask.AgentData.AgentID != AgentId)
9466 return true;
9467 }
9468 #endregion
9469
9470 RemoveTaskInventory handlerRemoveTaskItem = OnRemoveTaskItem;
9471
9472 if (handlerRemoveTaskItem != null)
9473 {
9474 handlerRemoveTaskItem(this, removeTask.InventoryData.ItemID, removeTask.InventoryData.LocalID);
9475 }
9476
9477 return true;
9478 }
9479
9480 private bool HandleMoveTaskInventory(IClientAPI sender, Packet Pack)
9481 {
9482 MoveTaskInventoryPacket moveTaskInventoryPacket = (MoveTaskInventoryPacket)Pack;
9483
9484 #region Packet Session and User Check
9485 if (m_checkPackets)
9486 {
9487 if (moveTaskInventoryPacket.AgentData.SessionID != SessionId ||
9488 moveTaskInventoryPacket.AgentData.AgentID != AgentId)
9489 return true;
9490 }
9491 #endregion
9492
9493 MoveTaskInventory handlerMoveTaskItem = OnMoveTaskItem;
9494
9495 if (handlerMoveTaskItem != null)
9496 {
9497 handlerMoveTaskItem(
9498 this, moveTaskInventoryPacket.AgentData.FolderID,
9499 moveTaskInventoryPacket.InventoryData.LocalID,
9500 moveTaskInventoryPacket.InventoryData.ItemID);
9501 }
9502
9503 return true;
9504 }
9505
9506 private bool HandleRezScript(IClientAPI sender, Packet Pack)
9507 {
9508 //m_log.Debug(Pack.ToString());
9509 RezScriptPacket rezScriptx = (RezScriptPacket)Pack;
9510
9511 #region Packet Session and User Check
9512 if (m_checkPackets)
9513 {
9514 if (rezScriptx.AgentData.SessionID != SessionId ||
9515 rezScriptx.AgentData.AgentID != AgentId)
9516 return true;
9517 }
9518 #endregion
9519
9520 RezScript handlerRezScript = OnRezScript;
9521 InventoryItemBase item = new InventoryItemBase();
9522 item.ID = rezScriptx.InventoryBlock.ItemID;
9523 item.Folder = rezScriptx.InventoryBlock.FolderID;
9524 item.CreatorId = rezScriptx.InventoryBlock.CreatorID.ToString();
9525 item.Owner = rezScriptx.InventoryBlock.OwnerID;
9526 item.BasePermissions = rezScriptx.InventoryBlock.BaseMask;
9527 item.CurrentPermissions = rezScriptx.InventoryBlock.OwnerMask;
9528 item.EveryOnePermissions = rezScriptx.InventoryBlock.EveryoneMask;
9529 item.NextPermissions = rezScriptx.InventoryBlock.NextOwnerMask;
9530 item.GroupPermissions = rezScriptx.InventoryBlock.GroupMask;
9531 item.GroupOwned = rezScriptx.InventoryBlock.GroupOwned;
9532 item.GroupID = rezScriptx.InventoryBlock.GroupID;
9533 item.AssetType = rezScriptx.InventoryBlock.Type;
9534 item.InvType = rezScriptx.InventoryBlock.InvType;
9535 item.Flags = rezScriptx.InventoryBlock.Flags;
9536 item.SaleType = rezScriptx.InventoryBlock.SaleType;
9537 item.SalePrice = rezScriptx.InventoryBlock.SalePrice;
9538 item.Name = Util.FieldToString(rezScriptx.InventoryBlock.Name);
9539 item.Description = Util.FieldToString(rezScriptx.InventoryBlock.Description);
9540 item.CreationDate = rezScriptx.InventoryBlock.CreationDate;
9541
9542 if (handlerRezScript != null)
9543 {
9544 handlerRezScript(this, item, rezScriptx.InventoryBlock.TransactionID, rezScriptx.UpdateBlock.ObjectLocalID);
9545 }
9546 return true;
9547 }
9548
9549 private bool HandleMapLayerRequest(IClientAPI sender, Packet Pack)
9550 {
9551 RequestMapLayer();
9552 return true;
9553 }
9554
9555 private bool HandleMapBlockRequest(IClientAPI sender, Packet Pack)
9556 {
9557 MapBlockRequestPacket MapRequest = (MapBlockRequestPacket)Pack;
9558
9559 #region Packet Session and User Check
9560 if (m_checkPackets)
9561 {
9562 if (MapRequest.AgentData.SessionID != SessionId ||
9563 MapRequest.AgentData.AgentID != AgentId)
9564 return true;
9565 }
9566 #endregion
9567
9568 RequestMapBlocks handlerRequestMapBlocks = OnRequestMapBlocks;
9569 if (handlerRequestMapBlocks != null)
9570 {
9571 handlerRequestMapBlocks(this, MapRequest.PositionData.MinX, MapRequest.PositionData.MinY,
9572 MapRequest.PositionData.MaxX, MapRequest.PositionData.MaxY, MapRequest.AgentData.Flags);
9573 }
9574 return true;
9575 }
9576
9577 private bool HandleMapNameRequest(IClientAPI sender, Packet Pack)
9578 {
9579 MapNameRequestPacket map = (MapNameRequestPacket)Pack;
9580
9581 #region Packet Session and User Check
9582 if (m_checkPackets)
9583 {
9584 if (map.AgentData.SessionID != SessionId ||
9585 map.AgentData.AgentID != AgentId)
9586 return true;
9587 }
9588 #endregion
9589 string mapName = (map.NameData.Name.Length == 0) ? m_scene.RegionInfo.RegionName :
9590 Util.UTF8.GetString(map.NameData.Name, 0, map.NameData.Name.Length - 1);
9591 RequestMapName handlerMapNameRequest = OnMapNameRequest;
9592 if (handlerMapNameRequest != null)
9593 {
9594 handlerMapNameRequest(this, mapName, map.AgentData.Flags);
9595 }
9596 return true;
9597 }
9598
9599 private bool HandleTeleportLandmarkRequest(IClientAPI sender, Packet Pack)
9600 {
9601 TeleportLandmarkRequestPacket tpReq = (TeleportLandmarkRequestPacket)Pack;
9602
9603 #region Packet Session and User Check
9604 if (m_checkPackets)
9605 {
9606 if (tpReq.Info.SessionID != SessionId ||
9607 tpReq.Info.AgentID != AgentId)
9608 return true;
9609 }
9610 #endregion
9611
9612 UUID lmid = tpReq.Info.LandmarkID;
9613 AssetLandmark lm;
9614 if (lmid != UUID.Zero)
9615 {
9616
9617 //AssetBase lma = m_assetCache.GetAsset(lmid, false);
9618 AssetBase lma = m_assetService.Get(lmid.ToString());
9619
9620 if (lma == null)
9621 {
9622 // Failed to find landmark
9623
9624 // Let's try to search in the user's home asset server
9625 lma = FindAssetInUserAssetServer(lmid.ToString());
9626
9627 if (lma == null)
9628 {
9629 // Really doesn't exist
9630 TeleportCancelPacket tpCancel = (TeleportCancelPacket)PacketPool.Instance.GetPacket(PacketType.TeleportCancel);
9631 tpCancel.Info.SessionID = tpReq.Info.SessionID;
9632 tpCancel.Info.AgentID = tpReq.Info.AgentID;
9633 OutPacket(tpCancel, ThrottleOutPacketType.Task);
9634 }
9635 }
9636
9637 try
9638 {
9639 lm = new AssetLandmark(lma);
9640 }
9641 catch (NullReferenceException)
9642 {
9643 // asset not found generates null ref inside the assetlandmark constructor.
9644 TeleportCancelPacket tpCancel = (TeleportCancelPacket)PacketPool.Instance.GetPacket(PacketType.TeleportCancel);
9645 tpCancel.Info.SessionID = tpReq.Info.SessionID;
9646 tpCancel.Info.AgentID = tpReq.Info.AgentID;
9647 OutPacket(tpCancel, ThrottleOutPacketType.Task);
9648 return true;
9649 }
9650 }
9651 else
9652 {
9653 // Teleport home request
9654 UUIDNameRequest handlerTeleportHomeRequest = OnTeleportHomeRequest;
9655 if (handlerTeleportHomeRequest != null)
9656 {
9657 handlerTeleportHomeRequest(AgentId, this);
9658 }
9659 return true;
9660 }
9661
9662 TeleportLandmarkRequest handlerTeleportLandmarkRequest = OnTeleportLandmarkRequest;
9663 if (handlerTeleportLandmarkRequest != null)
9664 {
9665 handlerTeleportLandmarkRequest(this, lm);
9666 }
9667 else
9668 {
9669 //no event handler so cancel request
9670 TeleportCancelPacket tpCancel = (TeleportCancelPacket)PacketPool.Instance.GetPacket(PacketType.TeleportCancel);
9671 tpCancel.Info.AgentID = tpReq.Info.AgentID;
9672 tpCancel.Info.SessionID = tpReq.Info.SessionID;
9673 OutPacket(tpCancel, ThrottleOutPacketType.Task);
9674
9675 }
9676 return true;
9677 }
9678
9679 private bool HandleTeleportCancel(IClientAPI sender, Packet Pack)
9680 {
9681 TeleportCancel handlerTeleportCancel = OnTeleportCancel;
9682 if (handlerTeleportCancel != null)
9683 {
9684 handlerTeleportCancel(this);
9685 }
9686 return true;
9687 }
9688
9689 private AssetBase FindAssetInUserAssetServer(string id)
9690 {
9691 AgentCircuitData aCircuit = ((Scene)Scene).AuthenticateHandler.GetAgentCircuitData(CircuitCode);
9692 if (aCircuit != null && aCircuit.ServiceURLs != null && aCircuit.ServiceURLs.ContainsKey("AssetServerURI"))
9693 {
9694 string assetServer = aCircuit.ServiceURLs["AssetServerURI"].ToString();
9695 if (!string.IsNullOrEmpty(assetServer))
9696 return ((Scene)Scene).AssetService.Get(assetServer + "/" + id);
9697 }
9698
9699 return null;
9700 }
9701
9702 private bool HandleTeleportLocationRequest(IClientAPI sender, Packet Pack)
9703 {
9704 TeleportLocationRequestPacket tpLocReq = (TeleportLocationRequestPacket)Pack;
9705 // m_log.Debug(tpLocReq.ToString());
9706
9707 #region Packet Session and User Check
9708 if (m_checkPackets)
9709 {
9710 if (tpLocReq.AgentData.SessionID != SessionId ||
9711 tpLocReq.AgentData.AgentID != AgentId)
9712 return true;
9713 }
9714 #endregion
9715
9716 TeleportLocationRequest handlerTeleportLocationRequest = OnTeleportLocationRequest;
9717 if (handlerTeleportLocationRequest != null)
9718 {
9719 // Adjust teleport location to base of a larger region if requested to teleport to a sub-region
9720 uint locX, locY;
9721 Util.RegionHandleToWorldLoc(tpLocReq.Info.RegionHandle, out locX, out locY);
9722 if ((locX >= m_scene.RegionInfo.WorldLocX)
9723 && (locX < (m_scene.RegionInfo.WorldLocX + m_scene.RegionInfo.RegionSizeX))
9724 && (locY >= m_scene.RegionInfo.WorldLocY)
9725 && (locY < (m_scene.RegionInfo.WorldLocY + m_scene.RegionInfo.RegionSizeY)))
9726 {
9727 tpLocReq.Info.RegionHandle = m_scene.RegionInfo.RegionHandle;
9728 tpLocReq.Info.Position.X += locX - m_scene.RegionInfo.WorldLocX;
9729 tpLocReq.Info.Position.Y += locY - m_scene.RegionInfo.WorldLocY;
9730 }
9731
9732 handlerTeleportLocationRequest(this, tpLocReq.Info.RegionHandle, tpLocReq.Info.Position,
9733 tpLocReq.Info.LookAt, 16);
9734 }
9735 else
9736 {
9737 //no event handler so cancel request
9738 TeleportCancelPacket tpCancel = (TeleportCancelPacket)PacketPool.Instance.GetPacket(PacketType.TeleportCancel);
9739 tpCancel.Info.SessionID = tpLocReq.AgentData.SessionID;
9740 tpCancel.Info.AgentID = tpLocReq.AgentData.AgentID;
9741 OutPacket(tpCancel, ThrottleOutPacketType.Task);
9742 }
9743 return true;
9744 }
9745
9746 #endregion Inventory/Asset/Other related packets
9747
9748 private bool HandleUUIDNameRequest(IClientAPI sender, Packet Pack)
9749 {
9750 ScenePresence sp = (ScenePresence)SceneAgent;
9751 if(sp == null || sp.IsDeleted || (sp.IsInTransit && !sp.IsInLocalTransit))
9752 return true;
9753
9754 UUIDNameRequestPacket incoming = (UUIDNameRequestPacket)Pack;
9755
9756 foreach (UUIDNameRequestPacket.UUIDNameBlockBlock UUIDBlock in incoming.UUIDNameBlock)
9757 {
9758 UUIDNameRequest handlerNameRequest = OnNameFromUUIDRequest;
9759 if (handlerNameRequest != null)
9760 {
9761 handlerNameRequest(UUIDBlock.ID, this);
9762 }
9763 }
9764 return true;
9765 }
9766
9767 #region Parcel related packets
9768
9769 private bool HandleRegionHandleRequest(IClientAPI sender, Packet Pack)
9770 {
9771 RegionHandleRequest handlerRegionHandleRequest = OnRegionHandleRequest;
9772
9773 if (handlerRegionHandleRequest != null)
9774 {
9775 RegionHandleRequestPacket rhrPack = (RegionHandleRequestPacket)Pack;
9776 handlerRegionHandleRequest(this, rhrPack.RequestBlock.RegionID);
9777 }
9778
9779 return true;
9780 }
9781
9782 private bool HandleParcelInfoRequest(IClientAPI sender, Packet Pack)
9783 {
9784 ParcelInfoRequestPacket pirPack = (ParcelInfoRequestPacket)Pack;
9785
9786 #region Packet Session and User Check
9787 if (m_checkPackets)
9788 {
9789 if (pirPack.AgentData.SessionID != SessionId ||
9790 pirPack.AgentData.AgentID != AgentId)
9791 return true;
9792 }
9793 #endregion
9794
9795 ParcelInfoRequest handlerParcelInfoRequest = OnParcelInfoRequest;
9796 if (handlerParcelInfoRequest != null)
9797 {
9798 handlerParcelInfoRequest(this, pirPack.Data.ParcelID);
9799 }
9800 return true;
9801 }
9802
9803 private bool HandleParcelAccessListRequest(IClientAPI sender, Packet Pack)
9804 {
9805 ParcelAccessListRequestPacket requestPacket = (ParcelAccessListRequestPacket)Pack;
9806
9807 #region Packet Session and User Check
9808 if (m_checkPackets)
9809 {
9810 if (requestPacket.AgentData.SessionID != SessionId ||
9811 requestPacket.AgentData.AgentID != AgentId)
9812 return true;
9813 }
9814 #endregion
9815
9816 ParcelAccessListRequest handlerParcelAccessListRequest = OnParcelAccessListRequest;
9817
9818 if (handlerParcelAccessListRequest != null)
9819 {
9820 handlerParcelAccessListRequest(requestPacket.AgentData.AgentID, requestPacket.AgentData.SessionID,
9821 requestPacket.Data.Flags, requestPacket.Data.SequenceID,
9822 requestPacket.Data.LocalID, this);
9823 }
9824 return true;
9825 }
9826
9827 private bool HandleParcelAccessListUpdate(IClientAPI sender, Packet Pack)
9828 {
9829 ParcelAccessListUpdatePacket updatePacket = (ParcelAccessListUpdatePacket)Pack;
9830
9831 #region Packet Session and User Check
9832 if (m_checkPackets)
9833 {
9834 if (updatePacket.AgentData.SessionID != SessionId ||
9835 updatePacket.AgentData.AgentID != AgentId)
9836 return true;
9837 }
9838 #endregion
9839
9840 List<LandAccessEntry> entries = new List<LandAccessEntry>();
9841 foreach (ParcelAccessListUpdatePacket.ListBlock block in updatePacket.List)
9842 {
9843 LandAccessEntry entry = new LandAccessEntry();
9844 entry.AgentID = block.ID;
9845 entry.Flags = (AccessList)block.Flags;
9846 entry.Expires = block.Time;
9847 entries.Add(entry);
9848 }
9849
9850 ParcelAccessListUpdateRequest handlerParcelAccessListUpdateRequest = OnParcelAccessListUpdateRequest;
9851 if (handlerParcelAccessListUpdateRequest != null)
9852 {
9853 handlerParcelAccessListUpdateRequest(updatePacket.AgentData.AgentID,
9854 updatePacket.Data.Flags,
9855 updatePacket.Data.LocalID,
9856 updatePacket.Data.TransactionID,
9857 updatePacket.Data.SequenceID,
9858 updatePacket.Data.Sections,
9859 entries, this);
9860 }
9861 return true;
9862 }
9863
9864 private bool HandleParcelPropertiesRequest(IClientAPI sender, Packet Pack)
9865 {
9866 ParcelPropertiesRequestPacket propertiesRequest = (ParcelPropertiesRequestPacket)Pack;
9867
9868 #region Packet Session and User Check
9869 if (m_checkPackets)
9870 {
9871 if (propertiesRequest.AgentData.SessionID != SessionId ||
9872 propertiesRequest.AgentData.AgentID != AgentId)
9873 return true;
9874 }
9875 #endregion
9876
9877 ParcelPropertiesRequest handlerParcelPropertiesRequest = OnParcelPropertiesRequest;
9878 if (handlerParcelPropertiesRequest != null)
9879 {
9880 handlerParcelPropertiesRequest((int)Math.Round(propertiesRequest.ParcelData.West),
9881 (int)Math.Round(propertiesRequest.ParcelData.South),
9882 (int)Math.Round(propertiesRequest.ParcelData.East),
9883 (int)Math.Round(propertiesRequest.ParcelData.North),
9884 propertiesRequest.ParcelData.SequenceID,
9885 propertiesRequest.ParcelData.SnapSelection, this);
9886 }
9887 return true;
9888 }
9889
9890 private bool HandleParcelDivide(IClientAPI sender, Packet Pack)
9891 {
9892 ParcelDividePacket landDivide = (ParcelDividePacket)Pack;
9893
9894 #region Packet Session and User Check
9895 if (m_checkPackets)
9896 {
9897 if (landDivide.AgentData.SessionID != SessionId ||
9898 landDivide.AgentData.AgentID != AgentId)
9899 return true;
9900 }
9901 #endregion
9902
9903 ParcelDivideRequest handlerParcelDivideRequest = OnParcelDivideRequest;
9904 if (handlerParcelDivideRequest != null)
9905 {
9906 handlerParcelDivideRequest((int)Math.Round(landDivide.ParcelData.West),
9907 (int)Math.Round(landDivide.ParcelData.South),
9908 (int)Math.Round(landDivide.ParcelData.East),
9909 (int)Math.Round(landDivide.ParcelData.North), this);
9910 }
9911 return true;
9912 }
9913
9914 private bool HandleParcelJoin(IClientAPI sender, Packet Pack)
9915 {
9916 ParcelJoinPacket landJoin = (ParcelJoinPacket)Pack;
9917
9918 #region Packet Session and User Check
9919 if (m_checkPackets)
9920 {
9921 if (landJoin.AgentData.SessionID != SessionId ||
9922 landJoin.AgentData.AgentID != AgentId)
9923 return true;
9924 }
9925 #endregion
9926
9927 ParcelJoinRequest handlerParcelJoinRequest = OnParcelJoinRequest;
9928
9929 if (handlerParcelJoinRequest != null)
9930 {
9931 handlerParcelJoinRequest((int)Math.Round(landJoin.ParcelData.West),
9932 (int)Math.Round(landJoin.ParcelData.South),
9933 (int)Math.Round(landJoin.ParcelData.East),
9934 (int)Math.Round(landJoin.ParcelData.North), this);
9935 }
9936 return true;
9937 }
9938
9939 private bool HandleParcelPropertiesUpdate(IClientAPI sender, Packet Pack)
9940 {
9941 ParcelPropertiesUpdatePacket parcelPropertiesPacket = (ParcelPropertiesUpdatePacket)Pack;
9942
9943 #region Packet Session and User Check
9944 if (m_checkPackets)
9945 {
9946 if (parcelPropertiesPacket.AgentData.SessionID != SessionId ||
9947 parcelPropertiesPacket.AgentData.AgentID != AgentId)
9948 return true;
9949 }
9950 #endregion
9951
9952 ParcelPropertiesUpdateRequest handlerParcelPropertiesUpdateRequest = OnParcelPropertiesUpdateRequest;
9953
9954 if (handlerParcelPropertiesUpdateRequest != null)
9955 {
9956 LandUpdateArgs args = new LandUpdateArgs();
9957
9958 args.AuthBuyerID = parcelPropertiesPacket.ParcelData.AuthBuyerID;
9959 args.Category = (ParcelCategory)parcelPropertiesPacket.ParcelData.Category;
9960 args.Desc = Utils.BytesToString(parcelPropertiesPacket.ParcelData.Desc);
9961 args.GroupID = parcelPropertiesPacket.ParcelData.GroupID;
9962 args.LandingType = parcelPropertiesPacket.ParcelData.LandingType;
9963 args.MediaAutoScale = parcelPropertiesPacket.ParcelData.MediaAutoScale;
9964 args.MediaID = parcelPropertiesPacket.ParcelData.MediaID;
9965 args.MediaURL = Utils.BytesToString(parcelPropertiesPacket.ParcelData.MediaURL);
9966 args.MusicURL = Utils.BytesToString(parcelPropertiesPacket.ParcelData.MusicURL);
9967 args.Name = Utils.BytesToString(parcelPropertiesPacket.ParcelData.Name);
9968 args.ParcelFlags = parcelPropertiesPacket.ParcelData.ParcelFlags;
9969 args.PassHours = parcelPropertiesPacket.ParcelData.PassHours;
9970 args.PassPrice = parcelPropertiesPacket.ParcelData.PassPrice;
9971 args.SalePrice = parcelPropertiesPacket.ParcelData.SalePrice;
9972 args.SnapshotID = parcelPropertiesPacket.ParcelData.SnapshotID;
9973 args.UserLocation = parcelPropertiesPacket.ParcelData.UserLocation;
9974 args.UserLookAt = parcelPropertiesPacket.ParcelData.UserLookAt;
9975 handlerParcelPropertiesUpdateRequest(args, parcelPropertiesPacket.ParcelData.LocalID, this);
9976 }
9977 return true;
9978 }
9979
9980 private bool HandleParcelSelectObjects(IClientAPI sender, Packet Pack)
9981 {
9982 ParcelSelectObjectsPacket selectPacket = (ParcelSelectObjectsPacket)Pack;
9983
9984 #region Packet Session and User Check
9985 if (m_checkPackets)
9986 {
9987 if (selectPacket.AgentData.SessionID != SessionId ||
9988 selectPacket.AgentData.AgentID != AgentId)
9989 return true;
9990 }
9991 #endregion
9992
9993 List<UUID> returnIDs = new List<UUID>();
9994
9995 foreach (ParcelSelectObjectsPacket.ReturnIDsBlock rb in
9996 selectPacket.ReturnIDs)
9997 {
9998 returnIDs.Add(rb.ReturnID);
9999 }
10000
10001 ParcelSelectObjects handlerParcelSelectObjects = OnParcelSelectObjects;
10002
10003 if (handlerParcelSelectObjects != null)
10004 {
10005 handlerParcelSelectObjects(selectPacket.ParcelData.LocalID,
10006 Convert.ToInt32(selectPacket.ParcelData.ReturnType), returnIDs, this);
10007 }
10008 return true;
10009 }
10010
10011 private bool HandleParcelObjectOwnersRequest(IClientAPI sender, Packet Pack)
10012 {
10013 ParcelObjectOwnersRequestPacket reqPacket = (ParcelObjectOwnersRequestPacket)Pack;
10014
10015 #region Packet Session and User Check
10016 if (m_checkPackets)
10017 {
10018 if (reqPacket.AgentData.SessionID != SessionId ||
10019 reqPacket.AgentData.AgentID != AgentId)
10020 return true;
10021 }
10022 #endregion
10023
10024 ParcelObjectOwnerRequest handlerParcelObjectOwnerRequest = OnParcelObjectOwnerRequest;
10025
10026 if (handlerParcelObjectOwnerRequest != null)
10027 {
10028 handlerParcelObjectOwnerRequest(reqPacket.ParcelData.LocalID, this);
10029 }
10030 return true;
10031
10032 }
10033
10034 private bool HandleParcelGodForceOwner(IClientAPI sender, Packet Pack)
10035 {
10036 ParcelGodForceOwnerPacket godForceOwnerPacket = (ParcelGodForceOwnerPacket)Pack;
10037
10038 #region Packet Session and User Check
10039 if (m_checkPackets)
10040 {
10041 if (godForceOwnerPacket.AgentData.SessionID != SessionId ||
10042 godForceOwnerPacket.AgentData.AgentID != AgentId)
10043 return true;
10044 }
10045 #endregion
10046
10047 ParcelGodForceOwner handlerParcelGodForceOwner = OnParcelGodForceOwner;
10048 if (handlerParcelGodForceOwner != null)
10049 {
10050 handlerParcelGodForceOwner(godForceOwnerPacket.Data.LocalID, godForceOwnerPacket.Data.OwnerID, this);
10051 }
10052 return true;
10053 }
10054
10055 private bool HandleParcelRelease(IClientAPI sender, Packet Pack)
10056 {
10057 ParcelReleasePacket releasePacket = (ParcelReleasePacket)Pack;
10058
10059 #region Packet Session and User Check
10060 if (m_checkPackets)
10061 {
10062 if (releasePacket.AgentData.SessionID != SessionId ||
10063 releasePacket.AgentData.AgentID != AgentId)
10064 return true;
10065 }
10066 #endregion
10067
10068 ParcelAbandonRequest handlerParcelAbandonRequest = OnParcelAbandonRequest;
10069 if (handlerParcelAbandonRequest != null)
10070 {
10071 handlerParcelAbandonRequest(releasePacket.Data.LocalID, this);
10072 }
10073 return true;
10074 }
10075
10076 private bool HandleParcelReclaim(IClientAPI sender, Packet Pack)
10077 {
10078 ParcelReclaimPacket reclaimPacket = (ParcelReclaimPacket)Pack;
10079
10080 #region Packet Session and User Check
10081 if (m_checkPackets)
10082 {
10083 if (reclaimPacket.AgentData.SessionID != SessionId ||
10084 reclaimPacket.AgentData.AgentID != AgentId)
10085 return true;
10086 }
10087 #endregion
10088
10089 ParcelReclaim handlerParcelReclaim = OnParcelReclaim;
10090 if (handlerParcelReclaim != null)
10091 {
10092 handlerParcelReclaim(reclaimPacket.Data.LocalID, this);
10093 }
10094 return true;
10095 }
10096
10097 private bool HandleParcelReturnObjects(IClientAPI sender, Packet Pack)
10098 {
10099 ParcelReturnObjectsPacket parcelReturnObjects = (ParcelReturnObjectsPacket)Pack;
10100
10101 #region Packet Session and User Check
10102 if (m_checkPackets)
10103 {
10104 if (parcelReturnObjects.AgentData.SessionID != SessionId ||
10105 parcelReturnObjects.AgentData.AgentID != AgentId)
10106 return true;
10107 }
10108 #endregion
10109
10110 UUID[] puserselectedOwnerIDs = new UUID[parcelReturnObjects.OwnerIDs.Length];
10111 for (int parceliterator = 0; parceliterator < parcelReturnObjects.OwnerIDs.Length; parceliterator++)
10112 puserselectedOwnerIDs[parceliterator] = parcelReturnObjects.OwnerIDs[parceliterator].OwnerID;
10113
10114 UUID[] puserselectedTaskIDs = new UUID[parcelReturnObjects.TaskIDs.Length];
10115
10116 for (int parceliterator = 0; parceliterator < parcelReturnObjects.TaskIDs.Length; parceliterator++)
10117 puserselectedTaskIDs[parceliterator] = parcelReturnObjects.TaskIDs[parceliterator].TaskID;
10118
10119 ParcelReturnObjectsRequest handlerParcelReturnObjectsRequest = OnParcelReturnObjectsRequest;
10120 if (handlerParcelReturnObjectsRequest != null)
10121 {
10122 handlerParcelReturnObjectsRequest(parcelReturnObjects.ParcelData.LocalID, parcelReturnObjects.ParcelData.ReturnType, puserselectedOwnerIDs, puserselectedTaskIDs, this);
10123
10124 }
10125 return true;
10126 }
10127
10128 private bool HandleParcelSetOtherCleanTime(IClientAPI sender, Packet Pack)
10129 {
10130 ParcelSetOtherCleanTimePacket parcelSetOtherCleanTimePacket = (ParcelSetOtherCleanTimePacket)Pack;
10131
10132 #region Packet Session and User Check
10133 if (m_checkPackets)
10134 {
10135 if (parcelSetOtherCleanTimePacket.AgentData.SessionID != SessionId ||
10136 parcelSetOtherCleanTimePacket.AgentData.AgentID != AgentId)
10137 return true;
10138 }
10139 #endregion
10140
10141 ParcelSetOtherCleanTime handlerParcelSetOtherCleanTime = OnParcelSetOtherCleanTime;
10142 if (handlerParcelSetOtherCleanTime != null)
10143 {
10144 handlerParcelSetOtherCleanTime(this,
10145 parcelSetOtherCleanTimePacket.ParcelData.LocalID,
10146 parcelSetOtherCleanTimePacket.ParcelData.OtherCleanTime);
10147 }
10148 return true;
10149 }
10150
10151 private bool HandleLandStatRequest(IClientAPI sender, Packet Pack)
10152 {
10153 LandStatRequestPacket lsrp = (LandStatRequestPacket)Pack;
10154
10155 #region Packet Session and User Check
10156 if (m_checkPackets)
10157 {
10158 if (lsrp.AgentData.SessionID != SessionId ||
10159 lsrp.AgentData.AgentID != AgentId)
10160 return true;
10161 }
10162 #endregion
10163
10164 GodLandStatRequest handlerLandStatRequest = OnLandStatRequest;
10165 if (handlerLandStatRequest != null)
10166 {
10167 handlerLandStatRequest(lsrp.RequestData.ParcelLocalID, lsrp.RequestData.ReportType, lsrp.RequestData.RequestFlags, Utils.BytesToString(lsrp.RequestData.Filter), this);
10168 }
10169 return true;
10170 }
10171
10172 private bool HandleParcelDwellRequest(IClientAPI sender, Packet Pack)
10173 {
10174 ParcelDwellRequestPacket dwellrq =
10175 (ParcelDwellRequestPacket)Pack;
10176
10177 #region Packet Session and User Check
10178 if (m_checkPackets)
10179 {
10180 if (dwellrq.AgentData.SessionID != SessionId ||
10181 dwellrq.AgentData.AgentID != AgentId)
10182 return true;
10183 }
10184 #endregion
10185
10186 ParcelDwellRequest handlerParcelDwellRequest = OnParcelDwellRequest;
10187 if (handlerParcelDwellRequest != null)
10188 {
10189 handlerParcelDwellRequest(dwellrq.Data.LocalID, this);
10190 }
10191 return true;
10192 }
10193
10194 #endregion Parcel related packets
10195
10196 #region Estate Packets
10197
10198 private bool HandleEstateOwnerMessage(IClientAPI sender, Packet Pack)
10199 {
10200 EstateOwnerMessagePacket messagePacket = (EstateOwnerMessagePacket)Pack;
10201 // m_log.InfoFormat("[LLCLIENTVIEW]: Packet: {0}", Utils.BytesToString(messagePacket.MethodData.Method));
10202 GodLandStatRequest handlerLandStatRequest;
10203
10204 #region Packet Session and User Check
10205 if (m_checkPackets)
10206 {
10207 if (messagePacket.AgentData.SessionID != SessionId ||
10208 messagePacket.AgentData.AgentID != AgentId)
10209 return true;
10210 }
10211 #endregion
10212
10213 string method = Utils.BytesToString(messagePacket.MethodData.Method);
10214
10215 switch (method)
10216 {
10217 case "getinfo":
10218 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
10219 {
10220 OnDetailedEstateDataRequest(this, messagePacket.MethodData.Invoice);
10221 }
10222 return true;
10223 case "setregioninfo":
10224 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
10225 {
10226 OnSetEstateFlagsRequest(convertParamStringToBool(messagePacket.ParamList[0].Parameter), convertParamStringToBool(messagePacket.ParamList[1].Parameter),
10227 convertParamStringToBool(messagePacket.ParamList[2].Parameter), !convertParamStringToBool(messagePacket.ParamList[3].Parameter),
10228 Convert.ToInt16(Convert.ToDecimal(Utils.BytesToString(messagePacket.ParamList[4].Parameter), Culture.NumberFormatInfo)),
10229 (float)Convert.ToDecimal(Utils.BytesToString(messagePacket.ParamList[5].Parameter), Culture.NumberFormatInfo),
10230 Convert.ToInt16(Utils.BytesToString(messagePacket.ParamList[6].Parameter)),
10231 convertParamStringToBool(messagePacket.ParamList[7].Parameter), convertParamStringToBool(messagePacket.ParamList[8].Parameter));
10232 }
10233 return true;
10234 // case "texturebase":
10235 // if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
10236 // {
10237 // foreach (EstateOwnerMessagePacket.ParamListBlock block in messagePacket.ParamList)
10238 // {
10239 // string s = Utils.BytesToString(block.Parameter);
10240 // string[] splitField = s.Split(' ');
10241 // if (splitField.Length == 2)
10242 // {
10243 // UUID tempUUID = new UUID(splitField[1]);
10244 // OnSetEstateTerrainBaseTexture(this, Convert.ToInt16(splitField[0]), tempUUID);
10245 // }
10246 // }
10247 // }
10248 // break;
10249 case "texturedetail":
10250 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
10251 {
10252 foreach (EstateOwnerMessagePacket.ParamListBlock block in messagePacket.ParamList)
10253 {
10254 string s = Utils.BytesToString(block.Parameter);
10255 string[] splitField = s.Split(' ');
10256 if (splitField.Length == 2)
10257 {
10258 Int16 corner = Convert.ToInt16(splitField[0]);
10259 UUID textureUUID = new UUID(splitField[1]);
10260
10261 OnSetEstateTerrainDetailTexture(this, corner, textureUUID);
10262 }
10263 }
10264 }
10265
10266 return true;
10267 case "textureheights":
10268 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
10269 {
10270 foreach (EstateOwnerMessagePacket.ParamListBlock block in messagePacket.ParamList)
10271 {
10272 string s = Utils.BytesToString(block.Parameter);
10273 string[] splitField = s.Split(' ');
10274 if (splitField.Length == 3)
10275 {
10276 Int16 corner = Convert.ToInt16(splitField[0]);
10277 float lowValue = (float)Convert.ToDecimal(splitField[1], Culture.NumberFormatInfo);
10278 float highValue = (float)Convert.ToDecimal(splitField[2], Culture.NumberFormatInfo);
10279
10280 OnSetEstateTerrainTextureHeights(this, corner, lowValue, highValue);
10281 }
10282 }
10283 }
10284 return true;
10285 case "texturecommit":
10286 OnCommitEstateTerrainTextureRequest(this);
10287 return true;
10288 case "setregionterrain":
10289 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
10290 {
10291 if (messagePacket.ParamList.Length != 9)
10292 {
10293 m_log.Error("EstateOwnerMessage: SetRegionTerrain method has a ParamList of invalid length");
10294 }
10295 else
10296 {
10297 try
10298 {
10299 string tmp = Utils.BytesToString(messagePacket.ParamList[0].Parameter);
10300 if (!tmp.Contains(".")) tmp += ".00";
10301 float WaterHeight = (float)Convert.ToDecimal(tmp, Culture.NumberFormatInfo);
10302 tmp = Utils.BytesToString(messagePacket.ParamList[1].Parameter);
10303 if (!tmp.Contains(".")) tmp += ".00";
10304 float TerrainRaiseLimit = (float)Convert.ToDecimal(tmp, Culture.NumberFormatInfo);
10305 tmp = Utils.BytesToString(messagePacket.ParamList[2].Parameter);
10306 if (!tmp.Contains(".")) tmp += ".00";
10307 float TerrainLowerLimit = (float)Convert.ToDecimal(tmp, Culture.NumberFormatInfo);
10308 bool UseEstateSun = convertParamStringToBool(messagePacket.ParamList[3].Parameter);
10309 bool UseFixedSun = convertParamStringToBool(messagePacket.ParamList[4].Parameter);
10310 float SunHour = (float)Convert.ToDecimal(Utils.BytesToString(messagePacket.ParamList[5].Parameter), Culture.NumberFormatInfo);
10311 bool UseGlobal = convertParamStringToBool(messagePacket.ParamList[6].Parameter);
10312 bool EstateFixedSun = convertParamStringToBool(messagePacket.ParamList[7].Parameter);
10313 float EstateSunHour = (float)Convert.ToDecimal(Utils.BytesToString(messagePacket.ParamList[8].Parameter), Culture.NumberFormatInfo);
10314
10315 OnSetRegionTerrainSettings(WaterHeight, TerrainRaiseLimit, TerrainLowerLimit, UseEstateSun, UseFixedSun, SunHour, UseGlobal, EstateFixedSun, EstateSunHour);
10316
10317 }
10318 catch (Exception ex)
10319 {
10320 m_log.Error("EstateOwnerMessage: Exception while setting terrain settings: \n" + messagePacket + "\n" + ex);
10321 }
10322 }
10323 }
10324
10325 return true;
10326 case "restart":
10327 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
10328 {
10329 // There's only 1 block in the estateResetSim.. and that's the number of seconds till restart.
10330 foreach (EstateOwnerMessagePacket.ParamListBlock block in messagePacket.ParamList)
10331 {
10332 float timeSeconds;
10333 Utils.TryParseSingle(Utils.BytesToString(block.Parameter), out timeSeconds);
10334 timeSeconds = (int)timeSeconds;
10335 OnEstateRestartSimRequest(this, (int)timeSeconds);
10336
10337 }
10338 }
10339 return true;
10340 case "estatechangecovenantid":
10341 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
10342 {
10343 foreach (EstateOwnerMessagePacket.ParamListBlock block in messagePacket.ParamList)
10344 {
10345 UUID newCovenantID = new UUID(Utils.BytesToString(block.Parameter));
10346 OnEstateChangeCovenantRequest(this, newCovenantID);
10347 }
10348 }
10349 return true;
10350 case "estateaccessdelta": // Estate access delta manages the banlist and allow list too.
10351 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
10352 {
10353 int estateAccessType = Convert.ToInt16(Utils.BytesToString(messagePacket.ParamList[1].Parameter));
10354
10355 OnUpdateEstateAccessDeltaRequest(this, messagePacket.MethodData.Invoice, estateAccessType, new UUID(Utils.BytesToString(messagePacket.ParamList[2].Parameter)));
10356
10357 }
10358 return true;
10359 case "simulatormessage":
10360 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
10361 {
10362 UUID invoice = messagePacket.MethodData.Invoice;
10363 UUID SenderID = new UUID(Utils.BytesToString(messagePacket.ParamList[2].Parameter));
10364 string SenderName = Utils.BytesToString(messagePacket.ParamList[3].Parameter);
10365 string Message = Utils.BytesToString(messagePacket.ParamList[4].Parameter);
10366 UUID sessionID = messagePacket.AgentData.SessionID;
10367 OnSimulatorBlueBoxMessageRequest(this, invoice, SenderID, sessionID, SenderName, Message);
10368 }
10369 return true;
10370 case "instantmessage":
10371 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
10372 {
10373 if (messagePacket.ParamList.Length < 2)
10374 return true;
10375
10376 UUID invoice = messagePacket.MethodData.Invoice;
10377 UUID sessionID = messagePacket.AgentData.SessionID;
10378
10379 UUID SenderID;
10380 string SenderName;
10381 string Message;
10382
10383 if (messagePacket.ParamList.Length < 5)
10384 {
10385 SenderID = AgentId;
10386 SenderName = Utils.BytesToString(messagePacket.ParamList[0].Parameter);
10387 Message = Utils.BytesToString(messagePacket.ParamList[1].Parameter);
10388 }
10389 else
10390 {
10391 SenderID = new UUID(Utils.BytesToString(messagePacket.ParamList[2].Parameter));
10392 SenderName = Utils.BytesToString(messagePacket.ParamList[3].Parameter);
10393 Message = Utils.BytesToString(messagePacket.ParamList[4].Parameter);
10394 }
10395
10396 OnEstateBlueBoxMessageRequest(this, invoice, SenderID, sessionID, SenderName, Message);
10397 }
10398 return true;
10399 case "setregiondebug":
10400 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
10401 {
10402 UUID invoice = messagePacket.MethodData.Invoice;
10403 UUID SenderID = messagePacket.AgentData.AgentID;
10404 bool scripted = convertParamStringToBool(messagePacket.ParamList[0].Parameter);
10405 bool collisionEvents = convertParamStringToBool(messagePacket.ParamList[1].Parameter);
10406 bool physics = convertParamStringToBool(messagePacket.ParamList[2].Parameter);
10407
10408 OnEstateDebugRegionRequest(this, invoice, SenderID, scripted, collisionEvents, physics);
10409 }
10410 return true;
10411 case "teleporthomeuser":
10412 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
10413 {
10414 UUID invoice = messagePacket.MethodData.Invoice;
10415 UUID SenderID = messagePacket.AgentData.AgentID;
10416 UUID Prey;
10417
10418 UUID.TryParse(Utils.BytesToString(messagePacket.ParamList[1].Parameter), out Prey);
10419
10420 OnEstateTeleportOneUserHomeRequest(this, invoice, SenderID, Prey);
10421 }
10422 return true;
10423 case "teleporthomeallusers":
10424 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
10425 {
10426 UUID invoice = messagePacket.MethodData.Invoice;
10427 UUID SenderID = messagePacket.AgentData.AgentID;
10428 OnEstateTeleportAllUsersHomeRequest(this, invoice, SenderID);
10429 }
10430 return true;
10431 case "colliders":
10432 handlerLandStatRequest = OnLandStatRequest;
10433 if (handlerLandStatRequest != null)
10434 {
10435 handlerLandStatRequest(0, 1, 0, "", this);
10436 }
10437 return true;
10438 case "scripts":
10439 handlerLandStatRequest = OnLandStatRequest;
10440 if (handlerLandStatRequest != null)
10441 {
10442 handlerLandStatRequest(0, 0, 0, "", this);
10443 }
10444 return true;
10445 case "terrain":
10446 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
10447 {
10448 if (messagePacket.ParamList.Length > 0)
10449 {
10450 if (Utils.BytesToString(messagePacket.ParamList[0].Parameter) == "bake")
10451 {
10452 BakeTerrain handlerBakeTerrain = OnBakeTerrain;
10453 if (handlerBakeTerrain != null)
10454 {
10455 handlerBakeTerrain(this);
10456 }
10457 }
10458 if (Utils.BytesToString(messagePacket.ParamList[0].Parameter) == "download filename")
10459 {
10460 if (messagePacket.ParamList.Length > 1)
10461 {
10462 RequestTerrain handlerRequestTerrain = OnRequestTerrain;
10463 if (handlerRequestTerrain != null)
10464 {
10465 handlerRequestTerrain(this, Utils.BytesToString(messagePacket.ParamList[1].Parameter));
10466 }
10467 }
10468 }
10469 if (Utils.BytesToString(messagePacket.ParamList[0].Parameter) == "upload filename")
10470 {
10471 if (messagePacket.ParamList.Length > 1)
10472 {
10473 RequestTerrain handlerUploadTerrain = OnUploadTerrain;
10474 if (handlerUploadTerrain != null)
10475 {
10476 handlerUploadTerrain(this, Utils.BytesToString(messagePacket.ParamList[1].Parameter));
10477 }
10478 }
10479 }
10480
10481 }
10482
10483
10484 }
10485 return true;
10486
10487 case "estatechangeinfo":
10488 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
10489 {
10490 UUID invoice = messagePacket.MethodData.Invoice;
10491 UUID SenderID = messagePacket.AgentData.AgentID;
10492 UInt32 param1 = Convert.ToUInt32(Utils.BytesToString(messagePacket.ParamList[1].Parameter));
10493 UInt32 param2 = Convert.ToUInt32(Utils.BytesToString(messagePacket.ParamList[2].Parameter));
10494
10495 EstateChangeInfo handlerEstateChangeInfo = OnEstateChangeInfo;
10496 if (handlerEstateChangeInfo != null)
10497 {
10498 handlerEstateChangeInfo(this, invoice, SenderID, param1, param2);
10499 }
10500 }
10501 return true;
10502
10503 case "telehub":
10504 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
10505 {
10506 UUID invoice = messagePacket.MethodData.Invoice;
10507 UUID SenderID = messagePacket.AgentData.AgentID;
10508 UInt32 param1 = 0u;
10509
10510 string command = (string)Utils.BytesToString(messagePacket.ParamList[0].Parameter);
10511
10512 if (command != "info ui")
10513 {
10514 try
10515 {
10516 param1 = Convert.ToUInt32(Utils.BytesToString(messagePacket.ParamList[1].Parameter));
10517 }
10518 catch
10519 {
10520 }
10521 }
10522
10523 EstateManageTelehub handlerEstateManageTelehub = OnEstateManageTelehub;
10524 if (handlerEstateManageTelehub != null)
10525 {
10526 handlerEstateManageTelehub(this, invoice, SenderID, command, param1);
10527 }
10528 }
10529 return true;
10530
10531 case "kickestate":
10532
10533 if(((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
10534 {
10535 UUID invoice = messagePacket.MethodData.Invoice;
10536 UUID SenderID = messagePacket.AgentData.AgentID;
10537 UUID Prey;
10538
10539 UUID.TryParse(Utils.BytesToString(messagePacket.ParamList[0].Parameter), out Prey);
10540
10541 OnEstateTeleportOneUserHomeRequest(this, invoice, SenderID, Prey);
10542 }
10543 return true;
10544
10545 default:
10546 m_log.WarnFormat(
10547 "[LLCLIENTVIEW]: EstateOwnerMessage: Unknown method {0} requested for {1} in {2}",
10548 method, Name, Scene.Name);
10549
10550 for (int i = 0; i < messagePacket.ParamList.Length; i++)
10551 {
10552 EstateOwnerMessagePacket.ParamListBlock block = messagePacket.ParamList[i];
10553 string data = (string)Utils.BytesToString(block.Parameter);
10554 m_log.DebugFormat("[LLCLIENTVIEW]: Param {0}={1}", i, data);
10555 }
10556
10557 return true;
10558 }
10559
10560 //int parcelID, uint reportType, uint requestflags, string filter
10561
10562 //lsrp.RequestData.ParcelLocalID;
10563 //lsrp.RequestData.ReportType; // 1 = colliders, 0 = scripts
10564 //lsrp.RequestData.RequestFlags;
10565 //lsrp.RequestData.Filter;
10566 }
10567
10568 private bool HandleRequestRegionInfo(IClientAPI sender, Packet Pack)
10569 {
10570 RequestRegionInfoPacket.AgentDataBlock mPacket = ((RequestRegionInfoPacket)Pack).AgentData;
10571
10572 #region Packet Session and User Check
10573 if (m_checkPackets)
10574 {
10575 if (mPacket.SessionID != SessionId ||
10576 mPacket.AgentID != AgentId)
10577 return true;
10578 }
10579 #endregion
10580
10581 RegionInfoRequest handlerRegionInfoRequest = OnRegionInfoRequest;
10582 if (handlerRegionInfoRequest != null)
10583 {
10584 handlerRegionInfoRequest(this);
10585 }
10586 return true;
10587 }
10588
10589 private bool HandleEstateCovenantRequest(IClientAPI sender, Packet Pack)
10590 {
10591
10592 //EstateCovenantRequestPacket.AgentDataBlock epack =
10593 // ((EstateCovenantRequestPacket)Pack).AgentData;
10594
10595 EstateCovenantRequest handlerEstateCovenantRequest = OnEstateCovenantRequest;
10596 if (handlerEstateCovenantRequest != null)
10597 {
10598 handlerEstateCovenantRequest(this);
10599 }
10600 return true;
10601
10602 }
10603
10604 #endregion Estate Packets
10605
10606 #region GodPackets
10607
10608 private bool HandleRequestGodlikePowers(IClientAPI sender, Packet Pack)
10609 {
10610 RequestGodlikePowersPacket rglpPack = (RequestGodlikePowersPacket)Pack;
10611
10612 if (rglpPack.AgentData.SessionID != SessionId ||
10613 rglpPack.AgentData.AgentID != AgentId)
10614 return true;
10615
10616 RequestGodlikePowersPacket.RequestBlockBlock rblock = rglpPack.RequestBlock;
10617 UUID token = rblock.Token;
10618
10619 RequestGodlikePowersPacket.AgentDataBlock ablock = rglpPack.AgentData;
10620
10621 RequestGodlikePowers handlerReqGodlikePowers = OnRequestGodlikePowers;
10622
10623 if (handlerReqGodlikePowers != null)
10624 {
10625 handlerReqGodlikePowers(ablock.AgentID, ablock.SessionID, token, rblock.Godlike);
10626 }
10627
10628 return true;
10629 }
10630
10631 private bool HandleGodUpdateRegionInfoUpdate(IClientAPI client, Packet Packet)
10632 {
10633 GodUpdateRegionInfoPacket GodUpdateRegionInfo =
10634 (GodUpdateRegionInfoPacket)Packet;
10635
10636 if (GodUpdateRegionInfo.AgentData.SessionID != SessionId ||
10637 GodUpdateRegionInfo.AgentData.AgentID != AgentId)
10638 return true;
10639
10640 GodUpdateRegionInfoUpdate handlerGodUpdateRegionInfo = OnGodUpdateRegionInfoUpdate;
10641 if (handlerGodUpdateRegionInfo != null)
10642 {
10643 handlerGodUpdateRegionInfo(this,
10644 GodUpdateRegionInfo.RegionInfo.BillableFactor,
10645 GodUpdateRegionInfo.RegionInfo.EstateID,
10646 GodUpdateRegionInfo.RegionInfo.RegionFlags,
10647 GodUpdateRegionInfo.RegionInfo.SimName,
10648 GodUpdateRegionInfo.RegionInfo.RedirectGridX,
10649 GodUpdateRegionInfo.RegionInfo.RedirectGridY);
10650 return true;
10651 }
10652 return false;
10653 }
10654
10655 private bool HandleSimWideDeletes(IClientAPI client, Packet Packet)
10656 {
10657 SimWideDeletesPacket SimWideDeletesRequest =
10658 (SimWideDeletesPacket)Packet;
10659 SimWideDeletesDelegate handlerSimWideDeletesRequest = OnSimWideDeletes;
10660 if (handlerSimWideDeletesRequest != null)
10661 {
10662 handlerSimWideDeletesRequest(this, SimWideDeletesRequest.AgentData.AgentID,(int)SimWideDeletesRequest.DataBlock.Flags,SimWideDeletesRequest.DataBlock.TargetID);
10663 return true;
10664 }
10665 return false;
10666 }
10667
10668 private bool HandleGodlikeMessage(IClientAPI client, Packet Packet)
10669 {
10670 GodlikeMessagePacket GodlikeMessage =
10671 (GodlikeMessagePacket)Packet;
10672
10673 if (GodlikeMessage.AgentData.SessionID != SessionId ||
10674 GodlikeMessage.AgentData.AgentID != AgentId)
10675 return true;
10676
10677 GodlikeMessage handlerGodlikeMessage = onGodlikeMessage;
10678 if (handlerGodlikeMessage != null)
10679 {
10680 handlerGodlikeMessage(this,
10681 GodlikeMessage.MethodData.Invoice,
10682 GodlikeMessage.MethodData.Method,
10683 GodlikeMessage.ParamList[0].Parameter);
10684 return true;
10685 }
10686 return false;
10687 }
10688
10689 private bool HandleSaveStatePacket(IClientAPI client, Packet Packet)
10690 {
10691 StateSavePacket SaveStateMessage =
10692 (StateSavePacket)Packet;
10693
10694 if (SaveStateMessage.AgentData.SessionID != SessionId ||
10695 SaveStateMessage.AgentData.AgentID != AgentId)
10696 return true;
10697
10698 SaveStateHandler handlerSaveStatePacket = OnSaveState;
10699 if (handlerSaveStatePacket != null)
10700 {
10701 handlerSaveStatePacket(this,SaveStateMessage.AgentData.AgentID);
10702 return true;
10703 }
10704 return false;
10705 }
10706
10707 private bool HandleGodKickUser(IClientAPI sender, Packet Pack)
10708 {
10709 GodKickUserPacket gkupack = (GodKickUserPacket)Pack;
10710
10711 if (gkupack.UserInfo.GodSessionID != SessionId ||
10712 gkupack.UserInfo.GodID != AgentId)
10713 return true;
10714
10715 GodKickUser handlerGodKickUser = OnGodKickUser;
10716 if (handlerGodKickUser != null)
10717 {
10718 handlerGodKickUser(gkupack.UserInfo.GodID, gkupack.UserInfo.AgentID, gkupack.UserInfo.KickFlags, gkupack.UserInfo.Reason);
10719 }
10720
10721 return true;
10722 }
10723 #endregion GodPackets
10724
10725 #region Economy/Transaction Packets
10726
10727 private bool HandleMoneyBalanceRequest(IClientAPI sender, Packet Pack)
10728 {
10729 MoneyBalanceRequestPacket moneybalancerequestpacket = (MoneyBalanceRequestPacket)Pack;
10730
10731 #region Packet Session and User Check
10732 if (m_checkPackets)
10733 {
10734 if (moneybalancerequestpacket.AgentData.SessionID != SessionId ||
10735 moneybalancerequestpacket.AgentData.AgentID != AgentId)
10736 return true;
10737 }
10738 #endregion
10739
10740 MoneyBalanceRequest handlerMoneyBalanceRequest = OnMoneyBalanceRequest;
10741
10742 if (handlerMoneyBalanceRequest != null)
10743 {
10744 handlerMoneyBalanceRequest(this, moneybalancerequestpacket.AgentData.AgentID, moneybalancerequestpacket.AgentData.SessionID, moneybalancerequestpacket.MoneyData.TransactionID);
10745 }
10746
10747 return true;
10748 }
10749 private bool HandleEconomyDataRequest(IClientAPI sender, Packet Pack)
10750 {
10751 EconomyDataRequest handlerEconomoyDataRequest = OnEconomyDataRequest;
10752 if (handlerEconomoyDataRequest != null)
10753 {
10754 handlerEconomoyDataRequest(this);
10755 }
10756 return true;
10757 }
10758 private bool HandleRequestPayPrice(IClientAPI sender, Packet Pack)
10759 {
10760 RequestPayPricePacket requestPayPricePacket = (RequestPayPricePacket)Pack;
10761
10762 RequestPayPrice handlerRequestPayPrice = OnRequestPayPrice;
10763 if (handlerRequestPayPrice != null)
10764 {
10765 handlerRequestPayPrice(this, requestPayPricePacket.ObjectData.ObjectID);
10766 }
10767 return true;
10768 }
10769 private bool HandleObjectSaleInfo(IClientAPI sender, Packet Pack)
10770 {
10771 ObjectSaleInfoPacket objectSaleInfoPacket = (ObjectSaleInfoPacket)Pack;
10772
10773 #region Packet Session and User Check
10774 if (m_checkPackets)
10775 {
10776 if (objectSaleInfoPacket.AgentData.SessionID != SessionId ||
10777 objectSaleInfoPacket.AgentData.AgentID != AgentId)
10778 return true;
10779 }
10780 #endregion
10781
10782 ObjectSaleInfo handlerObjectSaleInfo = OnObjectSaleInfo;
10783 if (handlerObjectSaleInfo != null)
10784 {
10785 foreach (ObjectSaleInfoPacket.ObjectDataBlock d
10786 in objectSaleInfoPacket.ObjectData)
10787 {
10788 handlerObjectSaleInfo(this,
10789 objectSaleInfoPacket.AgentData.AgentID,
10790 objectSaleInfoPacket.AgentData.SessionID,
10791 d.LocalID,
10792 d.SaleType,
10793 d.SalePrice);
10794 }
10795 }
10796 return true;
10797 }
10798 private bool HandleObjectBuy(IClientAPI sender, Packet Pack)
10799 {
10800 ObjectBuyPacket objectBuyPacket = (ObjectBuyPacket)Pack;
10801
10802 #region Packet Session and User Check
10803 if (m_checkPackets)
10804 {
10805 if (objectBuyPacket.AgentData.SessionID != SessionId ||
10806 objectBuyPacket.AgentData.AgentID != AgentId)
10807 return true;
10808 }
10809 #endregion
10810
10811 ObjectBuy handlerObjectBuy = OnObjectBuy;
10812
10813 if (handlerObjectBuy != null)
10814 {
10815 foreach (ObjectBuyPacket.ObjectDataBlock d
10816 in objectBuyPacket.ObjectData)
10817 {
10818 handlerObjectBuy(this,
10819 objectBuyPacket.AgentData.AgentID,
10820 objectBuyPacket.AgentData.SessionID,
10821 objectBuyPacket.AgentData.GroupID,
10822 objectBuyPacket.AgentData.CategoryID,
10823 d.ObjectLocalID,
10824 d.SaleType,
10825 d.SalePrice);
10826 }
10827 }
10828 return true;
10829 }
10830
10831 #endregion Economy/Transaction Packets
10832
10833 #region Script Packets
10834 private bool HandleGetScriptRunning(IClientAPI sender, Packet Pack)
10835 {
10836 GetScriptRunningPacket scriptRunning = (GetScriptRunningPacket)Pack;
10837
10838 GetScriptRunning handlerGetScriptRunning = OnGetScriptRunning;
10839 if (handlerGetScriptRunning != null)
10840 {
10841 handlerGetScriptRunning(this, scriptRunning.Script.ObjectID, scriptRunning.Script.ItemID);
10842 }
10843 return true;
10844 }
10845 private bool HandleSetScriptRunning(IClientAPI sender, Packet Pack)
10846 {
10847 SetScriptRunningPacket setScriptRunning = (SetScriptRunningPacket)Pack;
10848
10849 #region Packet Session and User Check
10850 if (m_checkPackets)
10851 {
10852 if (setScriptRunning.AgentData.SessionID != SessionId ||
10853 setScriptRunning.AgentData.AgentID != AgentId)
10854 return true;
10855 }
10856 #endregion
10857
10858 SetScriptRunning handlerSetScriptRunning = OnSetScriptRunning;
10859 if (handlerSetScriptRunning != null)
10860 {
10861 handlerSetScriptRunning(this, setScriptRunning.Script.ObjectID, setScriptRunning.Script.ItemID, setScriptRunning.Script.Running);
10862 }
10863 return true;
10864 }
10865
10866 private bool HandleScriptReset(IClientAPI sender, Packet Pack)
10867 {
10868 ScriptResetPacket scriptResetPacket = (ScriptResetPacket)Pack;
10869
10870 #region Packet Session and User Check
10871 if (m_checkPackets)
10872 {
10873 if (scriptResetPacket.AgentData.SessionID != SessionId ||
10874 scriptResetPacket.AgentData.AgentID != AgentId)
10875 return true;
10876 }
10877 #endregion
10878
10879 ScriptReset handlerScriptReset = OnScriptReset;
10880 if (handlerScriptReset != null)
10881 {
10882 handlerScriptReset(this, scriptResetPacket.Script.ObjectID, scriptResetPacket.Script.ItemID);
10883 }
10884 return true;
10885 }
10886
10887 #endregion Script Packets
10888
10889 #region Gesture Managment
10890
10891 private bool HandleActivateGestures(IClientAPI sender, Packet Pack)
10892 {
10893 ActivateGesturesPacket activateGesturePacket = (ActivateGesturesPacket)Pack;
10894
10895 #region Packet Session and User Check
10896 if (m_checkPackets)
10897 {
10898 if (activateGesturePacket.AgentData.SessionID != SessionId ||
10899 activateGesturePacket.AgentData.AgentID != AgentId)
10900 return true;
10901 }
10902 #endregion
10903
10904 ActivateGesture handlerActivateGesture = OnActivateGesture;
10905 if (handlerActivateGesture != null)
10906 {
10907 handlerActivateGesture(this,
10908 activateGesturePacket.Data[0].AssetID,
10909 activateGesturePacket.Data[0].ItemID);
10910 }
10911 else m_log.Error("Null pointer for activateGesture");
10912
10913 return true;
10914 }
10915 private bool HandleDeactivateGestures(IClientAPI sender, Packet Pack)
10916 {
10917 DeactivateGesturesPacket deactivateGesturePacket = (DeactivateGesturesPacket)Pack;
10918
10919 #region Packet Session and User Check
10920 if (m_checkPackets)
10921 {
10922 if (deactivateGesturePacket.AgentData.SessionID != SessionId ||
10923 deactivateGesturePacket.AgentData.AgentID != AgentId)
10924 return true;
10925 }
10926 #endregion
10927
10928 DeactivateGesture handlerDeactivateGesture = OnDeactivateGesture;
10929 if (handlerDeactivateGesture != null)
10930 {
10931 handlerDeactivateGesture(this, deactivateGesturePacket.Data[0].ItemID);
10932 }
10933 return true;
10934 }
10935 private bool HandleObjectOwner(IClientAPI sender, Packet Pack)
10936 {
10937 ObjectOwnerPacket objectOwnerPacket = (ObjectOwnerPacket)Pack;
10938
10939 #region Packet Session and User Check
10940 if (m_checkPackets)
10941 {
10942 if (objectOwnerPacket.AgentData.SessionID != SessionId ||
10943 objectOwnerPacket.AgentData.AgentID != AgentId)
10944 return true;
10945 }
10946 #endregion
10947
10948 List<uint> localIDs = new List<uint>();
10949
10950 foreach (ObjectOwnerPacket.ObjectDataBlock d in objectOwnerPacket.ObjectData)
10951 localIDs.Add(d.ObjectLocalID);
10952
10953 ObjectOwner handlerObjectOwner = OnObjectOwner;
10954 if (handlerObjectOwner != null)
10955 {
10956 handlerObjectOwner(this, objectOwnerPacket.HeaderData.OwnerID, objectOwnerPacket.HeaderData.GroupID, localIDs);
10957 }
10958 return true;
10959 }
10960
10961 #endregion Gesture Managment
10962
10963 private bool HandleAgentFOV(IClientAPI sender, Packet Pack)
10964 {
10965 AgentFOVPacket fovPacket = (AgentFOVPacket)Pack;
10966
10967 if (fovPacket.FOVBlock.GenCounter > m_agentFOVCounter)
10968 {
10969 m_agentFOVCounter = fovPacket.FOVBlock.GenCounter;
10970 AgentFOV handlerAgentFOV = OnAgentFOV;
10971 if (handlerAgentFOV != null)
10972 {
10973 handlerAgentFOV(this, fovPacket.FOVBlock.VerticalAngle);
10974 }
10975 }
10976 return true;
10977 }
10978
10979 #region unimplemented handlers
10980
10981 private bool HandleViewerStats(IClientAPI sender, Packet Pack)
10982 {
10983 // TODO: handle this packet
10984 //m_log.Warn("[CLIENT]: unhandled ViewerStats packet");
10985 return true;
10986 }
10987
10988 private bool HandleMapItemRequest(IClientAPI sender, Packet Pack)
10989 {
10990 MapItemRequestPacket mirpk = (MapItemRequestPacket)Pack;
10991
10992 #region Packet Session and User Check
10993 if (m_checkPackets)
10994 {
10995 if (mirpk.AgentData.SessionID != SessionId ||
10996 mirpk.AgentData.AgentID != AgentId)
10997 return true;
10998 }
10999 #endregion
11000
11001 //m_log.Debug(mirpk.ToString());
11002 MapItemRequest handlerMapItemRequest = OnMapItemRequest;
11003 if (handlerMapItemRequest != null)
11004 {
11005 handlerMapItemRequest(this, mirpk.AgentData.Flags, mirpk.AgentData.EstateID,
11006 mirpk.AgentData.Godlike, mirpk.RequestData.ItemType,
11007 mirpk.RequestData.RegionHandle);
11008
11009 }
11010 return true;
11011 }
11012
11013 private bool HandleTransferAbort(IClientAPI sender, Packet Pack)
11014 {
11015 return true;
11016 }
11017
11018 private bool HandleMuteListRequest(IClientAPI sender, Packet Pack)
11019 {
11020 MuteListRequestPacket muteListRequest =
11021 (MuteListRequestPacket)Pack;
11022
11023 #region Packet Session and User Check
11024 if (m_checkPackets)
11025 {
11026 if (muteListRequest.AgentData.SessionID != SessionId ||
11027 muteListRequest.AgentData.AgentID != AgentId)
11028 return true;
11029 }
11030 #endregion
11031
11032 MuteListRequest handlerMuteListRequest = OnMuteListRequest;
11033 if (handlerMuteListRequest != null)
11034 {
11035 handlerMuteListRequest(this, muteListRequest.MuteData.MuteCRC);
11036 }
11037 else
11038 {
11039 if(muteListRequest.MuteData.MuteCRC == 0)
11040 SendEmpytMuteList();
11041 else
11042 SendUseCachedMuteList();
11043 }
11044 return true;
11045 }
11046
11047 private bool HandleUpdateMuteListEntry(IClientAPI client, Packet Packet)
11048 {
11049 UpdateMuteListEntryPacket UpdateMuteListEntry =
11050 (UpdateMuteListEntryPacket)Packet;
11051 MuteListEntryUpdate handlerUpdateMuteListEntry = OnUpdateMuteListEntry;
11052 if (handlerUpdateMuteListEntry != null)
11053 {
11054 handlerUpdateMuteListEntry(this, UpdateMuteListEntry.MuteData.MuteID,
11055 Utils.BytesToString(UpdateMuteListEntry.MuteData.MuteName),
11056 UpdateMuteListEntry.MuteData.MuteType,
11057 UpdateMuteListEntry.MuteData.MuteFlags);
11058 return true;
11059 }
11060 return false;
11061 }
11062
11063 private bool HandleRemoveMuteListEntry(IClientAPI client, Packet Packet)
11064 {
11065 RemoveMuteListEntryPacket RemoveMuteListEntry =
11066 (RemoveMuteListEntryPacket)Packet;
11067 MuteListEntryRemove handlerRemoveMuteListEntry = OnRemoveMuteListEntry;
11068 if (handlerRemoveMuteListEntry != null)
11069 {
11070 handlerRemoveMuteListEntry(this,
11071 RemoveMuteListEntry.MuteData.MuteID,
11072 Utils.BytesToString(RemoveMuteListEntry.MuteData.MuteName));
11073 return true;
11074 }
11075 return false;
11076 }
11077
11078 private bool HandleUserReport(IClientAPI client, Packet Packet)
11079 {
11080 UserReportPacket UserReport =
11081 (UserReportPacket)Packet;
11082
11083 NewUserReport handlerUserReport = OnUserReport;
11084 if (handlerUserReport != null)
11085 {
11086 handlerUserReport(this,
11087 Utils.BytesToString(UserReport.ReportData.AbuseRegionName),
11088 UserReport.ReportData.AbuserID,
11089 UserReport.ReportData.Category,
11090 UserReport.ReportData.CheckFlags,
11091 Utils.BytesToString(UserReport.ReportData.Details),
11092 UserReport.ReportData.ObjectID,
11093 UserReport.ReportData.Position,
11094 UserReport.ReportData.ReportType,
11095 UserReport.ReportData.ScreenshotID,
11096 Utils.BytesToString(UserReport.ReportData.Summary),
11097 UserReport.AgentData.AgentID);
11098 return true;
11099 }
11100 return false;
11101 }
11102
11103 private bool HandleSendPostcard(IClientAPI client, Packet packet)
11104 {
11105// SendPostcardPacket SendPostcard =
11106// (SendPostcardPacket)packet;
11107 SendPostcard handlerSendPostcard = OnSendPostcard;
11108 if (handlerSendPostcard != null)
11109 {
11110 handlerSendPostcard(this);
11111 return true;
11112 }
11113 return false;
11114 }
11115
11116 private bool HandleChangeInventoryItemFlags(IClientAPI client, Packet packet)
11117 {
11118 ChangeInventoryItemFlagsPacket ChangeInventoryItemFlags =
11119 (ChangeInventoryItemFlagsPacket)packet;
11120 ChangeInventoryItemFlags handlerChangeInventoryItemFlags = OnChangeInventoryItemFlags;
11121 if (handlerChangeInventoryItemFlags != null)
11122 {
11123 foreach(ChangeInventoryItemFlagsPacket.InventoryDataBlock b in ChangeInventoryItemFlags.InventoryData)
11124 handlerChangeInventoryItemFlags(this, b.ItemID, b.Flags);
11125 return true;
11126 }
11127 return false;
11128 }
11129
11130 private bool HandleUseCircuitCode(IClientAPI sender, Packet Pack)
11131 {
11132 return true;
11133 }
11134
11135 private bool HandleCreateNewOutfitAttachments(IClientAPI sender, Packet Pack)
11136 {
11137 CreateNewOutfitAttachmentsPacket packet = (CreateNewOutfitAttachmentsPacket)Pack;
11138
11139 #region Packet Session and User Check
11140 if (m_checkPackets)
11141 {
11142 if (packet.AgentData.SessionID != SessionId ||
11143 packet.AgentData.AgentID != AgentId)
11144 return true;
11145 }
11146 #endregion
11147 MoveItemsAndLeaveCopy handlerMoveItemsAndLeaveCopy = null;
11148 List<InventoryItemBase> items = new List<InventoryItemBase>();
11149 foreach (CreateNewOutfitAttachmentsPacket.ObjectDataBlock n in packet.ObjectData)
11150 {
11151 InventoryItemBase b = new InventoryItemBase();
11152 b.ID = n.OldItemID;
11153 b.Folder = n.OldFolderID;
11154 items.Add(b);
11155 }
11156
11157 handlerMoveItemsAndLeaveCopy = OnMoveItemsAndLeaveCopy;
11158 if (handlerMoveItemsAndLeaveCopy != null)
11159 {
11160 handlerMoveItemsAndLeaveCopy(this, items, packet.HeaderData.NewFolderID);
11161 }
11162
11163 return true;
11164 }
11165
11166 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack)
11167 {
11168 return true;
11169 }
11170
11171
11172 private bool HandleInventoryDescendents(IClientAPI sender, Packet Pack)
11173 {
11174 return true;
11175 }
11176
11177 #endregion unimplemented handlers
11178
11179 #region Dir handlers
11180
11181 private bool HandleDirPlacesQuery(IClientAPI sender, Packet Pack)
11182 {
11183 DirPlacesQueryPacket dirPlacesQueryPacket = (DirPlacesQueryPacket)Pack;
11184 //m_log.Debug(dirPlacesQueryPacket.ToString());
11185
11186 #region Packet Session and User Check
11187 if (m_checkPackets)
11188 {
11189 if (dirPlacesQueryPacket.AgentData.SessionID != SessionId ||
11190 dirPlacesQueryPacket.AgentData.AgentID != AgentId)
11191 return true;
11192 }
11193 #endregion
11194
11195 DirPlacesQuery handlerDirPlacesQuery = OnDirPlacesQuery;
11196 if (handlerDirPlacesQuery != null)
11197 {
11198 handlerDirPlacesQuery(this,
11199 dirPlacesQueryPacket.QueryData.QueryID,
11200 Utils.BytesToString(
11201 dirPlacesQueryPacket.QueryData.QueryText),
11202 (int)dirPlacesQueryPacket.QueryData.QueryFlags,
11203 (int)dirPlacesQueryPacket.QueryData.Category,
11204 Utils.BytesToString(
11205 dirPlacesQueryPacket.QueryData.SimName),
11206 dirPlacesQueryPacket.QueryData.QueryStart);
11207 }
11208 return true;
11209 }
11210
11211 private bool HandleDirFindQuery(IClientAPI sender, Packet Pack)
11212 {
11213 DirFindQueryPacket dirFindQueryPacket = (DirFindQueryPacket)Pack;
11214
11215 #region Packet Session and User Check
11216 if (m_checkPackets)
11217 {
11218 if (dirFindQueryPacket.AgentData.SessionID != SessionId ||
11219 dirFindQueryPacket.AgentData.AgentID != AgentId)
11220 return true;
11221 }
11222 #endregion
11223
11224 DirFindQuery handlerDirFindQuery = OnDirFindQuery;
11225 if (handlerDirFindQuery != null)
11226 {
11227 handlerDirFindQuery(this,
11228 dirFindQueryPacket.QueryData.QueryID,
11229 Utils.BytesToString(
11230 dirFindQueryPacket.QueryData.QueryText).Trim(),
11231 dirFindQueryPacket.QueryData.QueryFlags,
11232 dirFindQueryPacket.QueryData.QueryStart);
11233 }
11234 return true;
11235 }
11236
11237 private bool HandleDirLandQuery(IClientAPI sender, Packet Pack)
11238 {
11239 DirLandQueryPacket dirLandQueryPacket = (DirLandQueryPacket)Pack;
11240
11241 #region Packet Session and User Check
11242 if (m_checkPackets)
11243 {
11244 if (dirLandQueryPacket.AgentData.SessionID != SessionId ||
11245 dirLandQueryPacket.AgentData.AgentID != AgentId)
11246 return true;
11247 }
11248 #endregion
11249
11250 DirLandQuery handlerDirLandQuery = OnDirLandQuery;
11251 if (handlerDirLandQuery != null)
11252 {
11253 handlerDirLandQuery(this,
11254 dirLandQueryPacket.QueryData.QueryID,
11255 dirLandQueryPacket.QueryData.QueryFlags,
11256 dirLandQueryPacket.QueryData.SearchType,
11257 dirLandQueryPacket.QueryData.Price,
11258 dirLandQueryPacket.QueryData.Area,
11259 dirLandQueryPacket.QueryData.QueryStart);
11260 }
11261 return true;
11262 }
11263
11264 private bool HandleDirPopularQuery(IClientAPI sender, Packet Pack)
11265 {
11266 DirPopularQueryPacket dirPopularQueryPacket = (DirPopularQueryPacket)Pack;
11267
11268 #region Packet Session and User Check
11269 if (m_checkPackets)
11270 {
11271 if (dirPopularQueryPacket.AgentData.SessionID != SessionId ||
11272 dirPopularQueryPacket.AgentData.AgentID != AgentId)
11273 return true;
11274 }
11275 #endregion
11276
11277 DirPopularQuery handlerDirPopularQuery = OnDirPopularQuery;
11278 if (handlerDirPopularQuery != null)
11279 {
11280 handlerDirPopularQuery(this,
11281 dirPopularQueryPacket.QueryData.QueryID,
11282 dirPopularQueryPacket.QueryData.QueryFlags);
11283 }
11284 return true;
11285 }
11286
11287 private bool HandleDirClassifiedQuery(IClientAPI sender, Packet Pack)
11288 {
11289 DirClassifiedQueryPacket dirClassifiedQueryPacket = (DirClassifiedQueryPacket)Pack;
11290
11291 #region Packet Session and User Check
11292 if (m_checkPackets)
11293 {
11294 if (dirClassifiedQueryPacket.AgentData.SessionID != SessionId ||
11295 dirClassifiedQueryPacket.AgentData.AgentID != AgentId)
11296 return true;
11297 }
11298 #endregion
11299
11300 DirClassifiedQuery handlerDirClassifiedQuery = OnDirClassifiedQuery;
11301 if (handlerDirClassifiedQuery != null)
11302 {
11303 handlerDirClassifiedQuery(this,
11304 dirClassifiedQueryPacket.QueryData.QueryID,
11305 Utils.BytesToString(
11306 dirClassifiedQueryPacket.QueryData.QueryText),
11307 dirClassifiedQueryPacket.QueryData.QueryFlags,
11308 dirClassifiedQueryPacket.QueryData.Category,
11309 dirClassifiedQueryPacket.QueryData.QueryStart);
11310 }
11311 return true;
11312 }
11313
11314 private bool HandleEventInfoRequest(IClientAPI sender, Packet Pack)
11315 {
11316 EventInfoRequestPacket eventInfoRequestPacket = (EventInfoRequestPacket)Pack;
11317
11318 #region Packet Session and User Check
11319 if (m_checkPackets)
11320 {
11321 if (eventInfoRequestPacket.AgentData.SessionID != SessionId ||
11322 eventInfoRequestPacket.AgentData.AgentID != AgentId)
11323 return true;
11324 }
11325 #endregion
11326
11327 if (OnEventInfoRequest != null)
11328 {
11329 OnEventInfoRequest(this, eventInfoRequestPacket.EventData.EventID);
11330 }
11331 return true;
11332 }
11333
11334 #endregion
11335
11336 #region Calling Card
11337
11338 private bool HandleOfferCallingCard(IClientAPI sender, Packet Pack)
11339 {
11340 OfferCallingCardPacket offerCallingCardPacket = (OfferCallingCardPacket)Pack;
11341
11342 #region Packet Session and User Check
11343 if (m_checkPackets)
11344 {
11345 if (offerCallingCardPacket.AgentData.SessionID != SessionId ||
11346 offerCallingCardPacket.AgentData.AgentID != AgentId)
11347 return true;
11348 }
11349 #endregion
11350
11351 if (OnOfferCallingCard != null)
11352 {
11353 OnOfferCallingCard(this,
11354 offerCallingCardPacket.AgentBlock.DestID,
11355 offerCallingCardPacket.AgentBlock.TransactionID);
11356 }
11357 return true;
11358 }
11359
11360 private bool HandleAcceptCallingCard(IClientAPI sender, Packet Pack)
11361 {
11362 AcceptCallingCardPacket acceptCallingCardPacket = (AcceptCallingCardPacket)Pack;
11363
11364 #region Packet Session and User Check
11365 if (m_checkPackets)
11366 {
11367 if (acceptCallingCardPacket.AgentData.SessionID != SessionId ||
11368 acceptCallingCardPacket.AgentData.AgentID != AgentId)
11369 return true;
11370 }
11371 #endregion
11372
11373 // according to http://wiki.secondlife.com/wiki/AcceptCallingCard FolderData should
11374 // contain exactly one entry
11375 if (OnAcceptCallingCard != null && acceptCallingCardPacket.FolderData.Length > 0)
11376 {
11377 OnAcceptCallingCard(this,
11378 acceptCallingCardPacket.TransactionBlock.TransactionID,
11379 acceptCallingCardPacket.FolderData[0].FolderID);
11380 }
11381 return true;
11382 }
11383
11384 private bool HandleDeclineCallingCard(IClientAPI sender, Packet Pack)
11385 {
11386 DeclineCallingCardPacket declineCallingCardPacket = (DeclineCallingCardPacket)Pack;
11387
11388 #region Packet Session and User Check
11389 if (m_checkPackets)
11390 {
11391 if (declineCallingCardPacket.AgentData.SessionID != SessionId ||
11392 declineCallingCardPacket.AgentData.AgentID != AgentId)
11393 return true;
11394 }
11395 #endregion
11396
11397 if (OnDeclineCallingCard != null)
11398 {
11399 OnDeclineCallingCard(this,
11400 declineCallingCardPacket.TransactionBlock.TransactionID);
11401 }
11402 return true;
11403 }
11404
11405 #endregion Calling Card
11406
11407 #region Groups
11408
11409 private bool HandleActivateGroup(IClientAPI sender, Packet Pack)
11410 {
11411 ActivateGroupPacket activateGroupPacket = (ActivateGroupPacket)Pack;
11412
11413 #region Packet Session and User Check
11414 if (m_checkPackets)
11415 {
11416 if (activateGroupPacket.AgentData.SessionID != SessionId ||
11417 activateGroupPacket.AgentData.AgentID != AgentId)
11418 return true;
11419 }
11420 #endregion
11421
11422 if (m_GroupsModule != null)
11423 {
11424 m_GroupsModule.ActivateGroup(this, activateGroupPacket.AgentData.GroupID);
11425 }
11426 return true;
11427
11428 }
11429
11430 private bool HandleGroupVoteHistoryRequest(IClientAPI client, Packet Packet)
11431 {
11432 GroupVoteHistoryRequestPacket GroupVoteHistoryRequest =
11433 (GroupVoteHistoryRequestPacket)Packet;
11434 GroupVoteHistoryRequest handlerGroupVoteHistoryRequest = OnGroupVoteHistoryRequest;
11435 if (handlerGroupVoteHistoryRequest != null)
11436 {
11437 handlerGroupVoteHistoryRequest(this, GroupVoteHistoryRequest.AgentData.AgentID,GroupVoteHistoryRequest.AgentData.SessionID,GroupVoteHistoryRequest.GroupData.GroupID,GroupVoteHistoryRequest.TransactionData.TransactionID);
11438 return true;
11439 }
11440 return false;
11441 }
11442
11443 private bool HandleGroupActiveProposalsRequest(IClientAPI client, Packet Packet)
11444 {
11445 GroupActiveProposalsRequestPacket GroupActiveProposalsRequest =
11446 (GroupActiveProposalsRequestPacket)Packet;
11447 GroupActiveProposalsRequest handlerGroupActiveProposalsRequest = OnGroupActiveProposalsRequest;
11448 if (handlerGroupActiveProposalsRequest != null)
11449 {
11450 handlerGroupActiveProposalsRequest(this, GroupActiveProposalsRequest.AgentData.AgentID,GroupActiveProposalsRequest.AgentData.SessionID,GroupActiveProposalsRequest.GroupData.GroupID,GroupActiveProposalsRequest.TransactionData.TransactionID);
11451 return true;
11452 }
11453 return false;
11454 }
11455
11456 private bool HandleGroupAccountDetailsRequest(IClientAPI client, Packet Packet)
11457 {
11458 GroupAccountDetailsRequestPacket GroupAccountDetailsRequest =
11459 (GroupAccountDetailsRequestPacket)Packet;
11460 GroupAccountDetailsRequest handlerGroupAccountDetailsRequest = OnGroupAccountDetailsRequest;
11461 if (handlerGroupAccountDetailsRequest != null)
11462 {
11463 handlerGroupAccountDetailsRequest(this, GroupAccountDetailsRequest.AgentData.AgentID,GroupAccountDetailsRequest.AgentData.GroupID,GroupAccountDetailsRequest.MoneyData.RequestID,GroupAccountDetailsRequest.AgentData.SessionID);
11464 return true;
11465 }
11466 return false;
11467 }
11468
11469 private bool HandleGroupAccountSummaryRequest(IClientAPI client, Packet Packet)
11470 {
11471 GroupAccountSummaryRequestPacket GroupAccountSummaryRequest =
11472 (GroupAccountSummaryRequestPacket)Packet;
11473 GroupAccountSummaryRequest handlerGroupAccountSummaryRequest = OnGroupAccountSummaryRequest;
11474 if (handlerGroupAccountSummaryRequest != null)
11475 {
11476 handlerGroupAccountSummaryRequest(this, GroupAccountSummaryRequest.AgentData.AgentID,GroupAccountSummaryRequest.AgentData.GroupID);
11477 return true;
11478 }
11479 return false;
11480 }
11481
11482 private bool HandleGroupTransactionsDetailsRequest(IClientAPI client, Packet Packet)
11483 {
11484 GroupAccountTransactionsRequestPacket GroupAccountTransactionsRequest =
11485 (GroupAccountTransactionsRequestPacket)Packet;
11486 GroupAccountTransactionsRequest handlerGroupAccountTransactionsRequest = OnGroupAccountTransactionsRequest;
11487 if (handlerGroupAccountTransactionsRequest != null)
11488 {
11489 handlerGroupAccountTransactionsRequest(this, GroupAccountTransactionsRequest.AgentData.AgentID,GroupAccountTransactionsRequest.AgentData.GroupID,GroupAccountTransactionsRequest.MoneyData.RequestID,GroupAccountTransactionsRequest.AgentData.SessionID);
11490 return true;
11491 }
11492 return false;
11493 }
11494
11495 private bool HandleGroupTitlesRequest(IClientAPI sender, Packet Pack)
11496 {
11497 GroupTitlesRequestPacket groupTitlesRequest =
11498 (GroupTitlesRequestPacket)Pack;
11499
11500 #region Packet Session and User Check
11501 if (m_checkPackets)
11502 {
11503 if (groupTitlesRequest.AgentData.SessionID != SessionId ||
11504 groupTitlesRequest.AgentData.AgentID != AgentId)
11505 return true;
11506 }
11507 #endregion
11508
11509 if (m_GroupsModule != null)
11510 {
11511 GroupTitlesReplyPacket groupTitlesReply = (GroupTitlesReplyPacket)PacketPool.Instance.GetPacket(PacketType.GroupTitlesReply);
11512
11513 groupTitlesReply.AgentData =
11514 new GroupTitlesReplyPacket.AgentDataBlock();
11515
11516 groupTitlesReply.AgentData.AgentID = AgentId;
11517 groupTitlesReply.AgentData.GroupID =
11518 groupTitlesRequest.AgentData.GroupID;
11519
11520 groupTitlesReply.AgentData.RequestID =
11521 groupTitlesRequest.AgentData.RequestID;
11522
11523 List<GroupTitlesData> titles =
11524 m_GroupsModule.GroupTitlesRequest(this,
11525 groupTitlesRequest.AgentData.GroupID);
11526
11527 groupTitlesReply.GroupData =
11528 new GroupTitlesReplyPacket.GroupDataBlock[titles.Count];
11529
11530 int i = 0;
11531 foreach (GroupTitlesData d in titles)
11532 {
11533 groupTitlesReply.GroupData[i] =
11534 new GroupTitlesReplyPacket.GroupDataBlock();
11535
11536 groupTitlesReply.GroupData[i].Title =
11537 Util.StringToBytes256(d.Name);
11538 groupTitlesReply.GroupData[i].RoleID =
11539 d.UUID;
11540 groupTitlesReply.GroupData[i].Selected =
11541 d.Selected;
11542 i++;
11543 }
11544
11545 OutPacket(groupTitlesReply, ThrottleOutPacketType.Task);
11546 }
11547 return true;
11548 }
11549
11550 UUID lastGroupProfileRequestID = UUID.Zero;
11551 double lastGroupProfileRequestTS = Util.GetTimeStampMS();
11552
11553 private bool HandleGroupProfileRequest(IClientAPI sender, Packet Pack)
11554 {
11555 if(m_GroupsModule == null)
11556 return true;
11557
11558 GroupProfileRequestPacket groupProfileRequest =
11559 (GroupProfileRequestPacket)Pack;
11560
11561
11562 #region Packet Session and User Check
11563 if (m_checkPackets)
11564 {
11565 if (groupProfileRequest.AgentData.SessionID != SessionId ||
11566 groupProfileRequest.AgentData.AgentID != AgentId)
11567 return true;
11568 }
11569 #endregion
11570
11571 UUID grpID = groupProfileRequest.GroupData.GroupID;
11572 double ts = Util.GetTimeStampMS();
11573 if(grpID == lastGroupProfileRequestID && ts - lastGroupProfileRequestTS < 10000)
11574 return true;
11575
11576 lastGroupProfileRequestID = grpID;
11577 lastGroupProfileRequestTS = ts;
11578
11579 GroupProfileReplyPacket groupProfileReply = (GroupProfileReplyPacket)PacketPool.Instance.GetPacket(PacketType.GroupProfileReply);
11580
11581 groupProfileReply.AgentData = new GroupProfileReplyPacket.AgentDataBlock();
11582 groupProfileReply.GroupData = new GroupProfileReplyPacket.GroupDataBlock();
11583 groupProfileReply.AgentData.AgentID = AgentId;
11584
11585 GroupProfileData d = m_GroupsModule.GroupProfileRequest(this,
11586 groupProfileRequest.GroupData.GroupID);
11587
11588 if(d.GroupID == UUID.Zero) // don't send broken data
11589 return true;
11590
11591 groupProfileReply.GroupData.GroupID = d.GroupID;
11592 groupProfileReply.GroupData.Name = Util.StringToBytes256(d.Name);
11593 groupProfileReply.GroupData.Charter = Util.StringToBytes1024(d.Charter);
11594 groupProfileReply.GroupData.ShowInList = d.ShowInList;
11595 groupProfileReply.GroupData.MemberTitle = Util.StringToBytes256(d.MemberTitle);
11596 groupProfileReply.GroupData.PowersMask = d.PowersMask;
11597 groupProfileReply.GroupData.InsigniaID = d.InsigniaID;
11598 groupProfileReply.GroupData.FounderID = d.FounderID;
11599 groupProfileReply.GroupData.MembershipFee = d.MembershipFee;
11600 groupProfileReply.GroupData.OpenEnrollment = d.OpenEnrollment;
11601 groupProfileReply.GroupData.Money = d.Money;
11602 groupProfileReply.GroupData.GroupMembershipCount = d.GroupMembershipCount;
11603 groupProfileReply.GroupData.GroupRolesCount = d.GroupRolesCount;
11604 groupProfileReply.GroupData.AllowPublish = d.AllowPublish;
11605 groupProfileReply.GroupData.MaturePublish = d.MaturePublish;
11606 groupProfileReply.GroupData.OwnerRole = d.OwnerRole;
11607
11608 Scene scene = (Scene)m_scene;
11609 if (scene.Permissions.IsGod(sender.AgentId) && (!sender.IsGroupMember(groupProfileRequest.GroupData.GroupID)))
11610 {
11611 ScenePresence p;
11612 if (scene.TryGetScenePresence(sender.AgentId, out p))
11613 {
11614 if (p.IsViewerUIGod)
11615 {
11616 groupProfileReply.GroupData.OpenEnrollment = true;
11617 groupProfileReply.GroupData.MembershipFee = 0;
11618 }
11619 }
11620 }
11621
11622 OutPacket(groupProfileReply, ThrottleOutPacketType.Task);
11623
11624 if(grpID == lastGroupProfileRequestID)
11625 lastGroupProfileRequestTS = Util.GetTimeStampMS() - 7000;
11626
11627 return true;
11628 }
11629 private bool HandleGroupMembersRequest(IClientAPI sender, Packet Pack)
11630 {
11631 GroupMembersRequestPacket groupMembersRequestPacket =
11632 (GroupMembersRequestPacket)Pack;
11633
11634 #region Packet Session and User Check
11635 if (m_checkPackets)
11636 {
11637 if (groupMembersRequestPacket.AgentData.SessionID != SessionId ||
11638 groupMembersRequestPacket.AgentData.AgentID != AgentId)
11639 return true;
11640 }
11641 #endregion
11642
11643 if (m_GroupsModule != null)
11644 {
11645 List<GroupMembersData> members =
11646 m_GroupsModule.GroupMembersRequest(this, groupMembersRequestPacket.GroupData.GroupID);
11647
11648 int memberCount = members.Count;
11649 int indx = 0;
11650 while (indx < memberCount)
11651 {
11652 int blockCount = memberCount - indx;
11653 if (blockCount > 25)
11654 blockCount = 25;
11655
11656 GroupMembersReplyPacket groupMembersReply = (GroupMembersReplyPacket)PacketPool.Instance.GetPacket(PacketType.GroupMembersReply);
11657
11658 groupMembersReply.AgentData =
11659 new GroupMembersReplyPacket.AgentDataBlock();
11660 groupMembersReply.GroupData =
11661 new GroupMembersReplyPacket.GroupDataBlock();
11662 groupMembersReply.MemberData =
11663 new GroupMembersReplyPacket.MemberDataBlock[
11664 blockCount];
11665
11666 groupMembersReply.AgentData.AgentID = AgentId;
11667 groupMembersReply.GroupData.GroupID =
11668 groupMembersRequestPacket.GroupData.GroupID;
11669 groupMembersReply.GroupData.RequestID =
11670 groupMembersRequestPacket.GroupData.RequestID;
11671 groupMembersReply.GroupData.MemberCount = memberCount;
11672
11673 for (int i = 0; i < blockCount; i++)
11674 {
11675 GroupMembersData m = members[indx++];
11676
11677 groupMembersReply.MemberData[i] =
11678 new GroupMembersReplyPacket.MemberDataBlock();
11679 groupMembersReply.MemberData[i].AgentID =
11680 m.AgentID;
11681 groupMembersReply.MemberData[i].Contribution =
11682 m.Contribution;
11683 groupMembersReply.MemberData[i].OnlineStatus =
11684 Util.StringToBytes256(m.OnlineStatus);
11685 groupMembersReply.MemberData[i].AgentPowers =
11686 m.AgentPowers;
11687 groupMembersReply.MemberData[i].Title =
11688 Util.StringToBytes256(m.Title);
11689 groupMembersReply.MemberData[i].IsOwner =
11690 m.IsOwner;
11691 }
11692 OutPacket(groupMembersReply, ThrottleOutPacketType.Task);
11693 }
11694 }
11695 return true;
11696 }
11697 private bool HandleGroupRoleDataRequest(IClientAPI sender, Packet Pack)
11698 {
11699 GroupRoleDataRequestPacket groupRolesRequest =
11700 (GroupRoleDataRequestPacket)Pack;
11701
11702 #region Packet Session and User Check
11703 if (m_checkPackets)
11704 {
11705 if (groupRolesRequest.AgentData.SessionID != SessionId ||
11706 groupRolesRequest.AgentData.AgentID != AgentId)
11707 return true;
11708 }
11709 #endregion
11710
11711 if (m_GroupsModule != null)
11712 {
11713 GroupRoleDataReplyPacket groupRolesReply = (GroupRoleDataReplyPacket)PacketPool.Instance.GetPacket(PacketType.GroupRoleDataReply);
11714
11715 groupRolesReply.AgentData =
11716 new GroupRoleDataReplyPacket.AgentDataBlock();
11717
11718 groupRolesReply.AgentData.AgentID = AgentId;
11719
11720 groupRolesReply.GroupData =
11721 new GroupRoleDataReplyPacket.GroupDataBlock();
11722
11723 groupRolesReply.GroupData.GroupID =
11724 groupRolesRequest.GroupData.GroupID;
11725
11726 groupRolesReply.GroupData.RequestID =
11727 groupRolesRequest.GroupData.RequestID;
11728
11729 List<GroupRolesData> titles =
11730 m_GroupsModule.GroupRoleDataRequest(this,
11731 groupRolesRequest.GroupData.GroupID);
11732
11733 groupRolesReply.GroupData.RoleCount =
11734 titles.Count;
11735
11736 groupRolesReply.RoleData =
11737 new GroupRoleDataReplyPacket.RoleDataBlock[titles.Count];
11738
11739 int i = 0;
11740 foreach (GroupRolesData d in titles)
11741 {
11742 groupRolesReply.RoleData[i] =
11743 new GroupRoleDataReplyPacket.RoleDataBlock();
11744
11745 groupRolesReply.RoleData[i].RoleID =
11746 d.RoleID;
11747 groupRolesReply.RoleData[i].Name =
11748 Util.StringToBytes256(d.Name);
11749 groupRolesReply.RoleData[i].Title =
11750 Util.StringToBytes256(d.Title);
11751 groupRolesReply.RoleData[i].Description =
11752 Util.StringToBytes1024(d.Description);
11753 groupRolesReply.RoleData[i].Powers =
11754 d.Powers;
11755 groupRolesReply.RoleData[i].Members =
11756 (uint)d.Members;
11757
11758 i++;
11759 }
11760
11761 OutPacket(groupRolesReply, ThrottleOutPacketType.Task);
11762 }
11763 return true;
11764 }
11765
11766 private bool HandleGroupRoleMembersRequest(IClientAPI sender, Packet Pack)
11767 {
11768 GroupRoleMembersRequestPacket groupRoleMembersRequest =
11769 (GroupRoleMembersRequestPacket)Pack;
11770
11771 #region Packet Session and User Check
11772 if (m_checkPackets)
11773 {
11774 if (groupRoleMembersRequest.AgentData.SessionID != SessionId ||
11775 groupRoleMembersRequest.AgentData.AgentID != AgentId)
11776 return true;
11777 }
11778 #endregion
11779
11780 if (m_GroupsModule != null)
11781 {
11782 List<GroupRoleMembersData> mappings =
11783 m_GroupsModule.GroupRoleMembersRequest(this,
11784 groupRoleMembersRequest.GroupData.GroupID);
11785
11786 int mappingsCount = mappings.Count;
11787
11788 while (mappings.Count > 0)
11789 {
11790 int pairs = mappings.Count;
11791 if (pairs > 32)
11792 pairs = 32;
11793
11794 GroupRoleMembersReplyPacket groupRoleMembersReply = (GroupRoleMembersReplyPacket)PacketPool.Instance.GetPacket(PacketType.GroupRoleMembersReply);
11795 groupRoleMembersReply.AgentData =
11796 new GroupRoleMembersReplyPacket.AgentDataBlock();
11797 groupRoleMembersReply.AgentData.AgentID =
11798 AgentId;
11799 groupRoleMembersReply.AgentData.GroupID =
11800 groupRoleMembersRequest.GroupData.GroupID;
11801 groupRoleMembersReply.AgentData.RequestID =
11802 groupRoleMembersRequest.GroupData.RequestID;
11803
11804 groupRoleMembersReply.AgentData.TotalPairs =
11805 (uint)mappingsCount;
11806
11807 groupRoleMembersReply.MemberData =
11808 new GroupRoleMembersReplyPacket.MemberDataBlock[pairs];
11809
11810 for (int i = 0; i < pairs; i++)
11811 {
11812 GroupRoleMembersData d = mappings[0];
11813 mappings.RemoveAt(0);
11814
11815 groupRoleMembersReply.MemberData[i] =
11816 new GroupRoleMembersReplyPacket.MemberDataBlock();
11817
11818 groupRoleMembersReply.MemberData[i].RoleID =
11819 d.RoleID;
11820 groupRoleMembersReply.MemberData[i].MemberID =
11821 d.MemberID;
11822 }
11823
11824 OutPacket(groupRoleMembersReply, ThrottleOutPacketType.Task);
11825 }
11826 }
11827 return true;
11828 }
11829 private bool HandleCreateGroupRequest(IClientAPI sender, Packet Pack)
11830 {
11831 CreateGroupRequestPacket createGroupRequest =
11832 (CreateGroupRequestPacket)Pack;
11833
11834 #region Packet Session and User Check
11835 if (m_checkPackets)
11836 {
11837 if (createGroupRequest.AgentData.SessionID != SessionId ||
11838 createGroupRequest.AgentData.AgentID != AgentId)
11839 return true;
11840 }
11841 #endregion
11842
11843 if (m_GroupsModule != null)
11844 {
11845 m_GroupsModule.CreateGroup(this,
11846 Utils.BytesToString(createGroupRequest.GroupData.Name),
11847 Utils.BytesToString(createGroupRequest.GroupData.Charter),
11848 createGroupRequest.GroupData.ShowInList,
11849 createGroupRequest.GroupData.InsigniaID,
11850 createGroupRequest.GroupData.MembershipFee,
11851 createGroupRequest.GroupData.OpenEnrollment,
11852 createGroupRequest.GroupData.AllowPublish,
11853 createGroupRequest.GroupData.MaturePublish);
11854 }
11855 return true;
11856 }
11857 private bool HandleUpdateGroupInfo(IClientAPI sender, Packet Pack)
11858 {
11859 UpdateGroupInfoPacket updateGroupInfo =
11860 (UpdateGroupInfoPacket)Pack;
11861
11862 #region Packet Session and User Check
11863 if (m_checkPackets)
11864 {
11865 if (updateGroupInfo.AgentData.SessionID != SessionId ||
11866 updateGroupInfo.AgentData.AgentID != AgentId)
11867 return true;
11868 }
11869 #endregion
11870
11871 if (m_GroupsModule != null)
11872 {
11873 m_GroupsModule.UpdateGroupInfo(this,
11874 updateGroupInfo.GroupData.GroupID,
11875 Utils.BytesToString(updateGroupInfo.GroupData.Charter),
11876 updateGroupInfo.GroupData.ShowInList,
11877 updateGroupInfo.GroupData.InsigniaID,
11878 updateGroupInfo.GroupData.MembershipFee,
11879 updateGroupInfo.GroupData.OpenEnrollment,
11880 updateGroupInfo.GroupData.AllowPublish,
11881 updateGroupInfo.GroupData.MaturePublish);
11882 }
11883
11884 return true;
11885 }
11886 private bool HandleSetGroupAcceptNotices(IClientAPI sender, Packet Pack)
11887 {
11888 SetGroupAcceptNoticesPacket setGroupAcceptNotices =
11889 (SetGroupAcceptNoticesPacket)Pack;
11890
11891 #region Packet Session and User Check
11892 if (m_checkPackets)
11893 {
11894 if (setGroupAcceptNotices.AgentData.SessionID != SessionId ||
11895 setGroupAcceptNotices.AgentData.AgentID != AgentId)
11896 return true;
11897 }
11898 #endregion
11899
11900 if (m_GroupsModule != null)
11901 {
11902 m_GroupsModule.SetGroupAcceptNotices(this,
11903 setGroupAcceptNotices.Data.GroupID,
11904 setGroupAcceptNotices.Data.AcceptNotices,
11905 setGroupAcceptNotices.NewData.ListInProfile);
11906 }
11907
11908 return true;
11909 }
11910 private bool HandleGroupTitleUpdate(IClientAPI sender, Packet Pack)
11911 {
11912 GroupTitleUpdatePacket groupTitleUpdate =
11913 (GroupTitleUpdatePacket)Pack;
11914
11915 #region Packet Session and User Check
11916 if (m_checkPackets)
11917 {
11918 if (groupTitleUpdate.AgentData.SessionID != SessionId ||
11919 groupTitleUpdate.AgentData.AgentID != AgentId)
11920 return true;
11921 }
11922 #endregion
11923
11924 if (m_GroupsModule != null)
11925 {
11926 m_GroupsModule.GroupTitleUpdate(this,
11927 groupTitleUpdate.AgentData.GroupID,
11928 groupTitleUpdate.AgentData.TitleRoleID);
11929 }
11930
11931 return true;
11932 }
11933 private bool HandleParcelDeedToGroup(IClientAPI sender, Packet Pack)
11934 {
11935 ParcelDeedToGroupPacket parcelDeedToGroup = (ParcelDeedToGroupPacket)Pack;
11936 if (m_GroupsModule != null)
11937 {
11938 ParcelDeedToGroup handlerParcelDeedToGroup = OnParcelDeedToGroup;
11939 if (handlerParcelDeedToGroup != null)
11940 {
11941 handlerParcelDeedToGroup(parcelDeedToGroup.Data.LocalID, parcelDeedToGroup.Data.GroupID, this);
11942
11943 }
11944 }
11945
11946 return true;
11947 }
11948 private bool HandleGroupNoticesListRequest(IClientAPI sender, Packet Pack)
11949 {
11950 GroupNoticesListRequestPacket groupNoticesListRequest =
11951 (GroupNoticesListRequestPacket)Pack;
11952
11953 #region Packet Session and User Check
11954 if (m_checkPackets)
11955 {
11956 if (groupNoticesListRequest.AgentData.SessionID != SessionId ||
11957 groupNoticesListRequest.AgentData.AgentID != AgentId)
11958 return true;
11959 }
11960 #endregion
11961
11962 if (m_GroupsModule != null)
11963 {
11964 GroupNoticeData[] gn =
11965 m_GroupsModule.GroupNoticesListRequest(this,
11966 groupNoticesListRequest.Data.GroupID);
11967
11968 GroupNoticesListReplyPacket groupNoticesListReply = (GroupNoticesListReplyPacket)PacketPool.Instance.GetPacket(PacketType.GroupNoticesListReply);
11969 groupNoticesListReply.AgentData =
11970 new GroupNoticesListReplyPacket.AgentDataBlock();
11971 groupNoticesListReply.AgentData.AgentID = AgentId;
11972 groupNoticesListReply.AgentData.GroupID = groupNoticesListRequest.Data.GroupID;
11973
11974 groupNoticesListReply.Data = new GroupNoticesListReplyPacket.DataBlock[gn.Length];
11975
11976 int i = 0;
11977 foreach (GroupNoticeData g in gn)
11978 {
11979 groupNoticesListReply.Data[i] = new GroupNoticesListReplyPacket.DataBlock();
11980 groupNoticesListReply.Data[i].NoticeID =
11981 g.NoticeID;
11982 groupNoticesListReply.Data[i].Timestamp =
11983 g.Timestamp;
11984 groupNoticesListReply.Data[i].FromName =
11985 Util.StringToBytes256(g.FromName);
11986 groupNoticesListReply.Data[i].Subject =
11987 Util.StringToBytes256(g.Subject);
11988 groupNoticesListReply.Data[i].HasAttachment =
11989 g.HasAttachment;
11990 groupNoticesListReply.Data[i].AssetType =
11991 g.AssetType;
11992 i++;
11993 }
11994
11995 OutPacket(groupNoticesListReply, ThrottleOutPacketType.Task);
11996 }
11997
11998 return true;
11999 }
12000 private bool HandleGroupNoticeRequest(IClientAPI sender, Packet Pack)
12001 {
12002 GroupNoticeRequestPacket groupNoticeRequest =
12003 (GroupNoticeRequestPacket)Pack;
12004
12005 #region Packet Session and User Check
12006 if (m_checkPackets)
12007 {
12008 if (groupNoticeRequest.AgentData.SessionID != SessionId ||
12009 groupNoticeRequest.AgentData.AgentID != AgentId)
12010 return true;
12011 }
12012 #endregion
12013
12014 if (m_GroupsModule != null)
12015 {
12016 m_GroupsModule.GroupNoticeRequest(this,
12017 groupNoticeRequest.Data.GroupNoticeID);
12018 }
12019 return true;
12020 }
12021 private bool HandleGroupRoleUpdate(IClientAPI sender, Packet Pack)
12022 {
12023 GroupRoleUpdatePacket groupRoleUpdate =
12024 (GroupRoleUpdatePacket)Pack;
12025
12026 #region Packet Session and User Check
12027 if (m_checkPackets)
12028 {
12029 if (groupRoleUpdate.AgentData.SessionID != SessionId ||
12030 groupRoleUpdate.AgentData.AgentID != AgentId)
12031 return true;
12032 }
12033 #endregion
12034
12035 if (m_GroupsModule != null)
12036 {
12037 foreach (GroupRoleUpdatePacket.RoleDataBlock d in
12038 groupRoleUpdate.RoleData)
12039 {
12040 m_GroupsModule.GroupRoleUpdate(this,
12041 groupRoleUpdate.AgentData.GroupID,
12042 d.RoleID,
12043 Utils.BytesToString(d.Name),
12044 Utils.BytesToString(d.Description),
12045 Utils.BytesToString(d.Title),
12046 d.Powers,
12047 d.UpdateType);
12048 }
12049 m_GroupsModule.NotifyChange(groupRoleUpdate.AgentData.GroupID);
12050 }
12051 return true;
12052 }
12053 private bool HandleGroupRoleChanges(IClientAPI sender, Packet Pack)
12054 {
12055 GroupRoleChangesPacket groupRoleChanges =
12056 (GroupRoleChangesPacket)Pack;
12057
12058 #region Packet Session and User Check
12059 if (m_checkPackets)
12060 {
12061 if (groupRoleChanges.AgentData.SessionID != SessionId ||
12062 groupRoleChanges.AgentData.AgentID != AgentId)
12063 return true;
12064 }
12065 #endregion
12066
12067 if (m_GroupsModule != null)
12068 {
12069 foreach (GroupRoleChangesPacket.RoleChangeBlock d in
12070 groupRoleChanges.RoleChange)
12071 {
12072 m_GroupsModule.GroupRoleChanges(this,
12073 groupRoleChanges.AgentData.GroupID,
12074 d.RoleID,
12075 d.MemberID,
12076 d.Change);
12077 }
12078 m_GroupsModule.NotifyChange(groupRoleChanges.AgentData.GroupID);
12079 }
12080 return true;
12081 }
12082 private bool HandleJoinGroupRequest(IClientAPI sender, Packet Pack)
12083 {
12084 JoinGroupRequestPacket joinGroupRequest =
12085 (JoinGroupRequestPacket)Pack;
12086
12087 #region Packet Session and User Check
12088 if (m_checkPackets)
12089 {
12090 if (joinGroupRequest.AgentData.SessionID != SessionId ||
12091 joinGroupRequest.AgentData.AgentID != AgentId)
12092 return true;
12093 }
12094 #endregion
12095
12096 if (m_GroupsModule != null)
12097 {
12098 m_GroupsModule.JoinGroupRequest(this,
12099 joinGroupRequest.GroupData.GroupID);
12100 }
12101 return true;
12102 }
12103 private bool HandleLeaveGroupRequest(IClientAPI sender, Packet Pack)
12104 {
12105 LeaveGroupRequestPacket leaveGroupRequest =
12106 (LeaveGroupRequestPacket)Pack;
12107
12108 #region Packet Session and User Check
12109 if (m_checkPackets)
12110 {
12111 if (leaveGroupRequest.AgentData.SessionID != SessionId ||
12112 leaveGroupRequest.AgentData.AgentID != AgentId)
12113 return true;
12114 }
12115 #endregion
12116
12117 if (m_GroupsModule != null)
12118 {
12119 m_GroupsModule.LeaveGroupRequest(this,
12120 leaveGroupRequest.GroupData.GroupID);
12121 }
12122 return true;
12123 }
12124 private bool HandleEjectGroupMemberRequest(IClientAPI sender, Packet Pack)
12125 {
12126 EjectGroupMemberRequestPacket ejectGroupMemberRequest =
12127 (EjectGroupMemberRequestPacket)Pack;
12128
12129 #region Packet Session and User Check
12130 if (m_checkPackets)
12131 {
12132 if (ejectGroupMemberRequest.AgentData.SessionID != SessionId ||
12133 ejectGroupMemberRequest.AgentData.AgentID != AgentId)
12134 return true;
12135 }
12136 #endregion
12137
12138 if (m_GroupsModule != null)
12139 {
12140 foreach (EjectGroupMemberRequestPacket.EjectDataBlock e
12141 in ejectGroupMemberRequest.EjectData)
12142 {
12143 m_GroupsModule.EjectGroupMemberRequest(this,
12144 ejectGroupMemberRequest.GroupData.GroupID,
12145 e.EjecteeID);
12146 }
12147 }
12148 return true;
12149 }
12150 private bool HandleInviteGroupRequest(IClientAPI sender, Packet Pack)
12151 {
12152 InviteGroupRequestPacket inviteGroupRequest =
12153 (InviteGroupRequestPacket)Pack;
12154
12155 #region Packet Session and User Check
12156 if (m_checkPackets)
12157 {
12158 if (inviteGroupRequest.AgentData.SessionID != SessionId ||
12159 inviteGroupRequest.AgentData.AgentID != AgentId)
12160 return true;
12161 }
12162 #endregion
12163
12164 if (m_GroupsModule != null)
12165 {
12166 foreach (InviteGroupRequestPacket.InviteDataBlock b in
12167 inviteGroupRequest.InviteData)
12168 {
12169 m_GroupsModule.InviteGroupRequest(this,
12170 inviteGroupRequest.GroupData.GroupID,
12171 b.InviteeID,
12172 b.RoleID);
12173 }
12174 }
12175 return true;
12176 }
12177
12178 #endregion Groups
12179
12180 private bool HandleStartLure(IClientAPI sender, Packet Pack)
12181 {
12182 StartLurePacket startLureRequest = (StartLurePacket)Pack;
12183
12184 #region Packet Session and User Check
12185 if (m_checkPackets)
12186 {
12187 if (startLureRequest.AgentData.SessionID != SessionId ||
12188 startLureRequest.AgentData.AgentID != AgentId)
12189 return true;
12190 }
12191 #endregion
12192
12193 StartLure handlerStartLure = OnStartLure;
12194 if (handlerStartLure != null)
12195 {
12196 for (int i = 0 ; i < startLureRequest.TargetData.Length ; i++)
12197 {
12198 handlerStartLure(startLureRequest.Info.LureType,
12199 Utils.BytesToString(
12200 startLureRequest.Info.Message),
12201 startLureRequest.TargetData[i].TargetID,
12202 this);
12203 }
12204 }
12205 return true;
12206 }
12207 private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack)
12208 {
12209 TeleportLureRequestPacket teleportLureRequest =
12210 (TeleportLureRequestPacket)Pack;
12211
12212 #region Packet Session and User Check
12213 if (m_checkPackets)
12214 {
12215 if (teleportLureRequest.Info.SessionID != SessionId ||
12216 teleportLureRequest.Info.AgentID != AgentId)
12217 return true;
12218 }
12219 #endregion
12220
12221 TeleportLureRequest handlerTeleportLureRequest = OnTeleportLureRequest;
12222 if (handlerTeleportLureRequest != null)
12223 handlerTeleportLureRequest(
12224 teleportLureRequest.Info.LureID,
12225 teleportLureRequest.Info.TeleportFlags,
12226 this);
12227 return true;
12228 }
12229 private bool HandleClassifiedInfoRequest(IClientAPI sender, Packet Pack)
12230 {
12231 ClassifiedInfoRequestPacket classifiedInfoRequest =
12232 (ClassifiedInfoRequestPacket)Pack;
12233
12234 #region Packet Session and User Check
12235 if (m_checkPackets)
12236 {
12237 if (classifiedInfoRequest.AgentData.SessionID != SessionId ||
12238 classifiedInfoRequest.AgentData.AgentID != AgentId)
12239 return true;
12240 }
12241 #endregion
12242
12243 ClassifiedInfoRequest handlerClassifiedInfoRequest = OnClassifiedInfoRequest;
12244 if (handlerClassifiedInfoRequest != null)
12245 handlerClassifiedInfoRequest(
12246 classifiedInfoRequest.Data.ClassifiedID,
12247 this);
12248 return true;
12249 }
12250 private bool HandleClassifiedInfoUpdate(IClientAPI sender, Packet Pack)
12251 {
12252 ClassifiedInfoUpdatePacket classifiedInfoUpdate =
12253 (ClassifiedInfoUpdatePacket)Pack;
12254
12255 #region Packet Session and User Check
12256 if (m_checkPackets)
12257 {
12258 if (classifiedInfoUpdate.AgentData.SessionID != SessionId ||
12259 classifiedInfoUpdate.AgentData.AgentID != AgentId)
12260 return true;
12261 }
12262 #endregion
12263
12264 ClassifiedInfoUpdate handlerClassifiedInfoUpdate = OnClassifiedInfoUpdate;
12265 if (handlerClassifiedInfoUpdate != null)
12266 handlerClassifiedInfoUpdate(
12267 classifiedInfoUpdate.Data.ClassifiedID,
12268 classifiedInfoUpdate.Data.Category,
12269 Utils.BytesToString(
12270 classifiedInfoUpdate.Data.Name),
12271 Utils.BytesToString(
12272 classifiedInfoUpdate.Data.Desc),
12273 classifiedInfoUpdate.Data.ParcelID,
12274 classifiedInfoUpdate.Data.ParentEstate,
12275 classifiedInfoUpdate.Data.SnapshotID,
12276 new Vector3(
12277 classifiedInfoUpdate.Data.PosGlobal),
12278 classifiedInfoUpdate.Data.ClassifiedFlags,
12279 classifiedInfoUpdate.Data.PriceForListing,
12280 this);
12281 return true;
12282 }
12283 private bool HandleClassifiedDelete(IClientAPI sender, Packet Pack)
12284 {
12285 ClassifiedDeletePacket classifiedDelete =
12286 (ClassifiedDeletePacket)Pack;
12287
12288 #region Packet Session and User Check
12289 if (m_checkPackets)
12290 {
12291 if (classifiedDelete.AgentData.SessionID != SessionId ||
12292 classifiedDelete.AgentData.AgentID != AgentId)
12293 return true;
12294 }
12295 #endregion
12296
12297 ClassifiedDelete handlerClassifiedDelete = OnClassifiedDelete;
12298 if (handlerClassifiedDelete != null)
12299 handlerClassifiedDelete(
12300 classifiedDelete.Data.ClassifiedID,
12301 this);
12302 return true;
12303 }
12304 private bool HandleClassifiedGodDelete(IClientAPI sender, Packet Pack)
12305 {
12306 ClassifiedGodDeletePacket classifiedGodDelete =
12307 (ClassifiedGodDeletePacket)Pack;
12308
12309 #region Packet Session and User Check
12310 if (m_checkPackets)
12311 {
12312 if (classifiedGodDelete.AgentData.SessionID != SessionId ||
12313 classifiedGodDelete.AgentData.AgentID != AgentId)
12314 return true;
12315 }
12316 #endregion
12317
12318 ClassifiedGodDelete handlerClassifiedGodDelete = OnClassifiedGodDelete;
12319 if (handlerClassifiedGodDelete != null)
12320 handlerClassifiedGodDelete(
12321 classifiedGodDelete.Data.ClassifiedID,
12322 classifiedGodDelete.Data.QueryID,
12323 this);
12324 return true;
12325 }
12326 private bool HandleEventGodDelete(IClientAPI sender, Packet Pack)
12327 {
12328 EventGodDeletePacket eventGodDelete =
12329 (EventGodDeletePacket)Pack;
12330
12331 #region Packet Session and User Check
12332 if (m_checkPackets)
12333 {
12334 if (eventGodDelete.AgentData.SessionID != SessionId ||
12335 eventGodDelete.AgentData.AgentID != AgentId)
12336 return true;
12337 }
12338 #endregion
12339
12340 EventGodDelete handlerEventGodDelete = OnEventGodDelete;
12341 if (handlerEventGodDelete != null)
12342 handlerEventGodDelete(
12343 eventGodDelete.EventData.EventID,
12344 eventGodDelete.QueryData.QueryID,
12345 Utils.BytesToString(
12346 eventGodDelete.QueryData.QueryText),
12347 eventGodDelete.QueryData.QueryFlags,
12348 eventGodDelete.QueryData.QueryStart,
12349 this);
12350 return true;
12351 }
12352 private bool HandleEventNotificationAddRequest(IClientAPI sender, Packet Pack)
12353 {
12354 EventNotificationAddRequestPacket eventNotificationAdd =
12355 (EventNotificationAddRequestPacket)Pack;
12356
12357 #region Packet Session and User Check
12358 if (m_checkPackets)
12359 {
12360 if (eventNotificationAdd.AgentData.SessionID != SessionId ||
12361 eventNotificationAdd.AgentData.AgentID != AgentId)
12362 return true;
12363 }
12364 #endregion
12365
12366 EventNotificationAddRequest handlerEventNotificationAddRequest = OnEventNotificationAddRequest;
12367 if (handlerEventNotificationAddRequest != null)
12368 handlerEventNotificationAddRequest(
12369 eventNotificationAdd.EventData.EventID, this);
12370 return true;
12371 }
12372 private bool HandleEventNotificationRemoveRequest(IClientAPI sender, Packet Pack)
12373 {
12374 EventNotificationRemoveRequestPacket eventNotificationRemove =
12375 (EventNotificationRemoveRequestPacket)Pack;
12376
12377 #region Packet Session and User Check
12378 if (m_checkPackets)
12379 {
12380 if (eventNotificationRemove.AgentData.SessionID != SessionId ||
12381 eventNotificationRemove.AgentData.AgentID != AgentId)
12382 return true;
12383 }
12384 #endregion
12385
12386 EventNotificationRemoveRequest handlerEventNotificationRemoveRequest = OnEventNotificationRemoveRequest;
12387 if (handlerEventNotificationRemoveRequest != null)
12388 handlerEventNotificationRemoveRequest(
12389 eventNotificationRemove.EventData.EventID, this);
12390 return true;
12391 }
12392 private bool HandleRetrieveInstantMessages(IClientAPI sender, Packet Pack)
12393 {
12394 RetrieveInstantMessagesPacket rimpInstantMessagePack = (RetrieveInstantMessagesPacket)Pack;
12395
12396 #region Packet Session and User Check
12397 if (m_checkPackets)
12398 {
12399 if (rimpInstantMessagePack.AgentData.SessionID != SessionId ||
12400 rimpInstantMessagePack.AgentData.AgentID != AgentId)
12401 return true;
12402 }
12403 #endregion
12404
12405 RetrieveInstantMessages handlerRetrieveInstantMessages = OnRetrieveInstantMessages;
12406 if (handlerRetrieveInstantMessages != null)
12407 handlerRetrieveInstantMessages(this);
12408 return true;
12409 }
12410 private bool HandlePickDelete(IClientAPI sender, Packet Pack)
12411 {
12412 PickDeletePacket pickDelete =
12413 (PickDeletePacket)Pack;
12414
12415 #region Packet Session and User Check
12416 if (m_checkPackets)
12417 {
12418 if (pickDelete.AgentData.SessionID != SessionId ||
12419 pickDelete.AgentData.AgentID != AgentId)
12420 return true;
12421 }
12422 #endregion
12423
12424 PickDelete handlerPickDelete = OnPickDelete;
12425 if (handlerPickDelete != null)
12426 handlerPickDelete(this, pickDelete.Data.PickID);
12427 return true;
12428 }
12429 private bool HandlePickGodDelete(IClientAPI sender, Packet Pack)
12430 {
12431 PickGodDeletePacket pickGodDelete =
12432 (PickGodDeletePacket)Pack;
12433
12434 #region Packet Session and User Check
12435 if (m_checkPackets)
12436 {
12437 if (pickGodDelete.AgentData.SessionID != SessionId ||
12438 pickGodDelete.AgentData.AgentID != AgentId)
12439 return true;
12440 }
12441 #endregion
12442
12443 PickGodDelete handlerPickGodDelete = OnPickGodDelete;
12444 if (handlerPickGodDelete != null)
12445 handlerPickGodDelete(this,
12446 pickGodDelete.AgentData.AgentID,
12447 pickGodDelete.Data.PickID,
12448 pickGodDelete.Data.QueryID);
12449 return true;
12450 }
12451 private bool HandlePickInfoUpdate(IClientAPI sender, Packet Pack)
12452 {
12453 PickInfoUpdatePacket pickInfoUpdate =
12454 (PickInfoUpdatePacket)Pack;
12455
12456 #region Packet Session and User Check
12457 if (m_checkPackets)
12458 {
12459 if (pickInfoUpdate.AgentData.SessionID != SessionId ||
12460 pickInfoUpdate.AgentData.AgentID != AgentId)
12461 return true;
12462 }
12463 #endregion
12464
12465 PickInfoUpdate handlerPickInfoUpdate = OnPickInfoUpdate;
12466 if (handlerPickInfoUpdate != null)
12467 handlerPickInfoUpdate(this,
12468 pickInfoUpdate.Data.PickID,
12469 pickInfoUpdate.Data.CreatorID,
12470 pickInfoUpdate.Data.TopPick,
12471 Utils.BytesToString(pickInfoUpdate.Data.Name),
12472 Utils.BytesToString(pickInfoUpdate.Data.Desc),
12473 pickInfoUpdate.Data.SnapshotID,
12474 pickInfoUpdate.Data.SortOrder,
12475 pickInfoUpdate.Data.Enabled);
12476 return true;
12477 }
12478 private bool HandleAvatarNotesUpdate(IClientAPI sender, Packet Pack)
12479 {
12480 AvatarNotesUpdatePacket avatarNotesUpdate =
12481 (AvatarNotesUpdatePacket)Pack;
12482
12483 #region Packet Session and User Check
12484 if (m_checkPackets)
12485 {
12486 if (avatarNotesUpdate.AgentData.SessionID != SessionId ||
12487 avatarNotesUpdate.AgentData.AgentID != AgentId)
12488 return true;
12489 }
12490 #endregion
12491
12492 AvatarNotesUpdate handlerAvatarNotesUpdate = OnAvatarNotesUpdate;
12493 if (handlerAvatarNotesUpdate != null)
12494 handlerAvatarNotesUpdate(this,
12495 avatarNotesUpdate.Data.TargetID,
12496 Utils.BytesToString(avatarNotesUpdate.Data.Notes));
12497 return true;
12498 }
12499 private bool HandleAvatarInterestsUpdate(IClientAPI sender, Packet Pack)
12500 {
12501 AvatarInterestsUpdatePacket avatarInterestUpdate =
12502 (AvatarInterestsUpdatePacket)Pack;
12503
12504 #region Packet Session and User Check
12505 if (m_checkPackets)
12506 {
12507 if (avatarInterestUpdate.AgentData.SessionID != SessionId ||
12508 avatarInterestUpdate.AgentData.AgentID != AgentId)
12509 return true;
12510 }
12511 #endregion
12512
12513 AvatarInterestUpdate handlerAvatarInterestUpdate = OnAvatarInterestUpdate;
12514 if (handlerAvatarInterestUpdate != null)
12515 handlerAvatarInterestUpdate(this,
12516 avatarInterestUpdate.PropertiesData.WantToMask,
12517 Utils.BytesToString(avatarInterestUpdate.PropertiesData.WantToText),
12518 avatarInterestUpdate.PropertiesData.SkillsMask,
12519 Utils.BytesToString(avatarInterestUpdate.PropertiesData.SkillsText),
12520 Utils.BytesToString(avatarInterestUpdate.PropertiesData.LanguagesText));
12521 return true;
12522 }
12523
12524 private bool HandleGrantUserRights(IClientAPI sender, Packet Pack)
12525 {
12526 GrantUserRightsPacket GrantUserRights =
12527 (GrantUserRightsPacket)Pack;
12528 #region Packet Session and User Check
12529 if (m_checkPackets)
12530 {
12531 if (GrantUserRights.AgentData.SessionID != SessionId ||
12532 GrantUserRights.AgentData.AgentID != AgentId)
12533 return true;
12534 }
12535 #endregion
12536
12537 GrantUserFriendRights GrantUserRightsHandler = OnGrantUserRights;
12538 if (GrantUserRightsHandler != null)
12539 GrantUserRightsHandler(this,
12540 GrantUserRights.Rights[0].AgentRelated,
12541 GrantUserRights.Rights[0].RelatedRights);
12542
12543 return true;
12544 }
12545
12546 private bool HandleRevokePermissions(IClientAPI sender, Packet Pack)
12547 {
12548 RevokePermissionsPacket pkt = (RevokePermissionsPacket)Pack;
12549 if (pkt.AgentData.SessionID != SessionId ||
12550 pkt .AgentData.AgentID != AgentId)
12551 return true;
12552
12553 // don't use multidelegate "event"
12554 ScenePresence sp = (ScenePresence)SceneAgent;
12555 if(sp != null && !sp.IsDeleted && !sp.IsInTransit)
12556 {
12557 UUID objectID = pkt.Data.ObjectID;
12558 uint permissions = pkt.Data.ObjectPermissions;
12559
12560 sp.HandleRevokePermissions(objectID , permissions);
12561 }
12562 return true;
12563 }
12564 private bool HandlePlacesQuery(IClientAPI sender, Packet Pack)
12565 {
12566 PlacesQueryPacket placesQueryPacket =
12567 (PlacesQueryPacket)Pack;
12568
12569 PlacesQuery handlerPlacesQuery = OnPlacesQuery;
12570
12571 if (handlerPlacesQuery != null)
12572 handlerPlacesQuery(placesQueryPacket.AgentData.QueryID,
12573 placesQueryPacket.TransactionData.TransactionID,
12574 Utils.BytesToString(
12575 placesQueryPacket.QueryData.QueryText),
12576 placesQueryPacket.QueryData.QueryFlags,
12577 (byte)placesQueryPacket.QueryData.Category,
12578 Utils.BytesToString(
12579 placesQueryPacket.QueryData.SimName),
12580 this);
12581 return true;
12582 }
12583
12584 #endregion Packet Handlers
12585
12586 public void SendScriptQuestion(UUID taskID, string taskName, string ownerName, UUID itemID, int question)
12587 {
12588 ScriptQuestionPacket scriptQuestion = (ScriptQuestionPacket)PacketPool.Instance.GetPacket(PacketType.ScriptQuestion);
12589 scriptQuestion.Data = new ScriptQuestionPacket.DataBlock();
12590 // TODO: don't create new blocks if recycling an old packet
12591 scriptQuestion.Data.TaskID = taskID;
12592 scriptQuestion.Data.ItemID = itemID;
12593 scriptQuestion.Data.Questions = question;
12594 scriptQuestion.Data.ObjectName = Util.StringToBytes256(taskName);
12595 scriptQuestion.Data.ObjectOwner = Util.StringToBytes256(ownerName);
12596
12597 OutPacket(scriptQuestion, ThrottleOutPacketType.Task);
12598 }
12599
12600 /// <summary>
12601 /// Handler called when we receive a logout packet.
12602 /// </summary>
12603 /// <param name="client"></param>
12604 /// <param name="packet"></param>
12605 /// <returns></returns>
12606 protected virtual bool HandleLogout(IClientAPI client, Packet packet)
12607 {
12608 if (packet.Type == PacketType.LogoutRequest)
12609 {
12610 if (((LogoutRequestPacket)packet).AgentData.SessionID != SessionId) return false;
12611 }
12612
12613 return Logout(client);
12614 }
12615
12616 /// <summary>
12617 ///
12618 /// </summary>
12619 /// <param name="client"></param>
12620 /// <returns></returns>
12621 protected virtual bool Logout(IClientAPI client)
12622 {
12623 m_log.InfoFormat("[CLIENT]: Got a logout request for {0} in {1}", Name, Scene.RegionInfo.RegionName);
12624
12625 Action<IClientAPI> handlerLogout = OnLogout;
12626
12627 if (handlerLogout != null)
12628 {
12629 handlerLogout(client);
12630 }
12631
12632 return true;
12633 }
12634
12635 /// <summary>
12636 /// </summary>
12637 /// <remarks>
12638 /// At the moment, we always reply that there is no cached texture.
12639 /// </remarks>
12640 /// <param name="simclient"></param>
12641 /// <param name="packet"></param>
12642 /// <returns></returns>
12643
12644 protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet)
12645 {
12646 //m_log.Debug("texture cached: " + packet.ToString());
12647 AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet;
12648 AgentCachedTextureResponsePacket cachedresp = (AgentCachedTextureResponsePacket)PacketPool.Instance.GetPacket(PacketType.AgentCachedTextureResponse);
12649
12650 if (cachedtex.AgentData.SessionID != SessionId)
12651 return false;
12652
12653 // TODO: don't create new blocks if recycling an old packet
12654 cachedresp.AgentData.AgentID = AgentId;
12655 cachedresp.AgentData.SessionID = m_sessionId;
12656 cachedresp.AgentData.SerialNum = cachedtex.AgentData.SerialNum;
12657 cachedresp.WearableData =
12658 new AgentCachedTextureResponsePacket.WearableDataBlock[cachedtex.WearableData.Length];
12659
12660 int cacheHits = 0;
12661
12662 // 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
12663
12664 WearableCacheItem[] cacheItems = null;
12665
12666 ScenePresence p = m_scene.GetScenePresence(AgentId);
12667
12668 if (p != null && p.Appearance != null)
12669 {
12670 cacheItems = p.Appearance.WearableCacheItems;
12671 }
12672
12673 int maxWearablesLoop = cachedtex.WearableData.Length;
12674
12675 if (cacheItems != null)
12676 {
12677 if (maxWearablesLoop > cacheItems.Length)
12678 maxWearablesLoop = cacheItems.Length;
12679 for (int i = 0; i < maxWearablesLoop; i++)
12680 {
12681 int idx = cachedtex.WearableData[i].TextureIndex;
12682 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
12683 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
12684 cachedresp.WearableData[i].HostName = new byte[0];
12685 if (cachedtex.WearableData[i].ID == cacheItems[idx].CacheId)
12686 {
12687 cachedresp.WearableData[i].TextureID = cacheItems[idx].TextureID;
12688 cacheHits++;
12689 }
12690 else
12691 {
12692 cachedresp.WearableData[i].TextureID = UUID.Zero;
12693 }
12694 }
12695 }
12696 else
12697 {
12698 for (int i = 0; i < maxWearablesLoop; i++)
12699 {
12700 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
12701 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
12702 cachedresp.WearableData[i].TextureID = UUID.Zero;
12703 cachedresp.WearableData[i].HostName = new byte[0];
12704 }
12705 }
12706
12707 //m_log.DebugFormat("texture cached: hits {0}", cacheHits);
12708
12709 cachedresp.Header.Zerocoded = true;
12710 OutPacket(cachedresp, ThrottleOutPacketType.Task);
12711
12712 return true;
12713 }
12714
12715 /// <summary>
12716 /// Send a response back to a client when it asks the asset server (via the region server) if it has
12717 /// its appearance texture cached.
12718 /// </summary>
12719 /// <param name="avatar"></param>
12720 /// <param name="serial"></param>
12721 /// <param name="cachedTextures"></param>
12722 /// <returns></returns>
12723 public void SendCachedTextureResponse(ISceneEntity avatar, int serial, List<CachedTextureResponseArg> cachedTextures)
12724 {
12725 ScenePresence presence = avatar as ScenePresence;
12726 if (presence == null)
12727 return;
12728
12729 AgentCachedTextureResponsePacket cachedresp = (AgentCachedTextureResponsePacket)PacketPool.Instance.GetPacket(PacketType.AgentCachedTextureResponse);
12730
12731 // TODO: don't create new blocks if recycling an old packet
12732 cachedresp.AgentData.AgentID = m_agentId;
12733 cachedresp.AgentData.SessionID = m_sessionId;
12734 cachedresp.AgentData.SerialNum = serial;
12735 cachedresp.WearableData = new AgentCachedTextureResponsePacket.WearableDataBlock[cachedTextures.Count];
12736
12737 for (int i = 0; i < cachedTextures.Count; i++)
12738 {
12739 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
12740 cachedresp.WearableData[i].TextureIndex = (byte)cachedTextures[i].BakedTextureIndex;
12741 cachedresp.WearableData[i].TextureID = cachedTextures[i].BakedTextureID;
12742 cachedresp.WearableData[i].HostName = new byte[0];
12743 }
12744
12745 cachedresp.Header.Zerocoded = true;
12746 OutPacket(cachedresp, ThrottleOutPacketType.Task);
12747 }
12748
12749 protected bool HandleMultipleObjUpdate(IClientAPI simClient, Packet packet)
12750 {
12751 MultipleObjectUpdatePacket multipleupdate = (MultipleObjectUpdatePacket)packet;
12752
12753 if (multipleupdate.AgentData.SessionID != SessionId)
12754 return false;
12755
12756// m_log.DebugFormat(
12757// "[CLIENT]: Incoming MultipleObjectUpdatePacket contained {0} blocks", multipleupdate.ObjectData.Length);
12758
12759 Scene tScene = (Scene)m_scene;
12760
12761 for (int i = 0; i < multipleupdate.ObjectData.Length; i++)
12762 {
12763 MultipleObjectUpdatePacket.ObjectDataBlock block = multipleupdate.ObjectData[i];
12764
12765 // Can't act on Null Data
12766 if (block.Data != null)
12767 {
12768 uint localId = block.ObjectLocalID;
12769 SceneObjectPart part = tScene.GetSceneObjectPart(localId);
12770
12771 if (part == null)
12772 {
12773 // It's a ghost! tell the client to delete it from view.
12774 simClient.SendKillObject(new List<uint> { localId });
12775 }
12776 else
12777 {
12778 ClientChangeObject updatehandler = onClientChangeObject;
12779
12780 if (updatehandler != null)
12781 {
12782 ObjectChangeData udata = new ObjectChangeData();
12783
12784 /*ubit from ll JIRA:
12785 * 0x01 position
12786 * 0x02 rotation
12787 * 0x04 scale
12788
12789 * 0x08 LINK_SET
12790 * 0x10 UNIFORM for scale
12791 */
12792
12793 // translate to internal changes
12794 // not all cases .. just the ones older code did
12795
12796 switch (block.Type)
12797 {
12798 case 1: //change position sp
12799 udata.position = new Vector3(block.Data, 0);
12800
12801 udata.change = ObjectChangeType.primP;
12802 updatehandler(localId, udata, this);
12803 break;
12804
12805 case 2: // rotation sp
12806 udata.rotation = new Quaternion(block.Data, 0, true);
12807
12808 udata.change = ObjectChangeType.primR;
12809 updatehandler(localId, udata, this);
12810 break;
12811
12812 case 3: // position plus rotation
12813 udata.position = new Vector3(block.Data, 0);
12814 udata.rotation = new Quaternion(block.Data, 12, true);
12815
12816 udata.change = ObjectChangeType.primPR;
12817 updatehandler(localId, udata, this);
12818 break;
12819
12820 case 4: // scale sp
12821 udata.scale = new Vector3(block.Data, 0);
12822 udata.change = ObjectChangeType.primS;
12823
12824 updatehandler(localId, udata, this);
12825 break;
12826
12827 case 0x14: // uniform scale sp
12828 udata.scale = new Vector3(block.Data, 0);
12829
12830 udata.change = ObjectChangeType.primUS;
12831 updatehandler(localId, udata, this);
12832 break;
12833
12834 case 5: // scale and position sp
12835 udata.position = new Vector3(block.Data, 0);
12836 udata.scale = new Vector3(block.Data, 12);
12837
12838 udata.change = ObjectChangeType.primPS;
12839 updatehandler(localId, udata, this);
12840 break;
12841
12842 case 0x15: //uniform scale and position
12843 udata.position = new Vector3(block.Data, 0);
12844 udata.scale = new Vector3(block.Data, 12);
12845
12846 udata.change = ObjectChangeType.primPUS;
12847 updatehandler(localId, udata, this);
12848 break;
12849
12850 // now group related (bit 4)
12851 case 9: //( 8 + 1 )group position
12852 udata.position = new Vector3(block.Data, 0);
12853
12854 udata.change = ObjectChangeType.groupP;
12855 updatehandler(localId, udata, this);
12856 break;
12857
12858 case 0x0A: // (8 + 2) group rotation
12859 udata.rotation = new Quaternion(block.Data, 0, true);
12860
12861 udata.change = ObjectChangeType.groupR;
12862 updatehandler(localId, udata, this);
12863 break;
12864
12865 case 0x0B: //( 8 + 2 + 1) group rotation and position
12866 udata.position = new Vector3(block.Data, 0);
12867 udata.rotation = new Quaternion(block.Data, 12, true);
12868
12869 udata.change = ObjectChangeType.groupPR;
12870 updatehandler(localId, udata, this);
12871 break;
12872
12873 case 0x0C: // (8 + 4) group scale
12874 // only afects root prim and only sent by viewer editor object tab scaling
12875 // mouse edition only allows uniform scaling
12876 // SL MAY CHANGE THIS in viewers
12877
12878 udata.scale = new Vector3(block.Data, 0);
12879
12880 udata.change = ObjectChangeType.groupS;
12881 updatehandler(localId, udata, this);
12882
12883 break;
12884
12885 case 0x0D: //(8 + 4 + 1) group scale and position
12886 // exception as above
12887
12888 udata.position = new Vector3(block.Data, 0);
12889 udata.scale = new Vector3(block.Data, 12);
12890
12891 udata.change = ObjectChangeType.groupPS;
12892 updatehandler(localId, udata, this);
12893 break;
12894
12895 case 0x1C: // (0x10 + 8 + 4 ) group scale UNIFORM
12896 udata.scale = new Vector3(block.Data, 0);
12897
12898 udata.change = ObjectChangeType.groupUS;
12899 updatehandler(localId, udata, this);
12900 break;
12901
12902 case 0x1D: // (UNIFORM + GROUP + SCALE + POS)
12903 udata.position = new Vector3(block.Data, 0);
12904 udata.scale = new Vector3(block.Data, 12);
12905
12906 udata.change = ObjectChangeType.groupPUS;
12907 updatehandler(localId, udata, this);
12908 break;
12909
12910 default:
12911 m_log.Debug("[CLIENT]: MultipleObjUpdate recieved an unknown packet type: " + (block.Type));
12912 break;
12913 }
12914 }
12915
12916 }
12917 }
12918 }
12919 return true;
12920 }
12921
12922 public void RequestMapLayer()
12923 {
12924 //should be getting the map layer from the grid server
12925 //send a layer covering the 800,800 - 1200,1200 area (should be covering the requested area)
12926 MapLayerReplyPacket mapReply = (MapLayerReplyPacket)PacketPool.Instance.GetPacket(PacketType.MapLayerReply);
12927 // TODO: don't create new blocks if recycling an old packet
12928 mapReply.AgentData.AgentID = AgentId;
12929 mapReply.AgentData.Flags = 0;
12930 mapReply.LayerData = new MapLayerReplyPacket.LayerDataBlock[1];
12931 mapReply.LayerData[0] = new MapLayerReplyPacket.LayerDataBlock();
12932 mapReply.LayerData[0].Bottom = 0;
12933 mapReply.LayerData[0].Left = 0;
12934 mapReply.LayerData[0].Top = 30000;
12935 mapReply.LayerData[0].Right = 30000;
12936 mapReply.LayerData[0].ImageID = new UUID("00000000-0000-1111-9999-000000000006");
12937 mapReply.Header.Zerocoded = true;
12938 OutPacket(mapReply, ThrottleOutPacketType.Land);
12939 }
12940
12941 public void RequestMapBlocksX(int minX, int minY, int maxX, int maxY)
12942 {
12943 /*
12944 IList simMapProfiles = m_gridServer.RequestMapBlocks(minX, minY, maxX, maxY);
12945 MapBlockReplyPacket mbReply = new MapBlockReplyPacket();
12946 mbReply.AgentData.AgentId = AgentId;
12947 int len;
12948 if (simMapProfiles == null)
12949 len = 0;
12950 else
12951 len = simMapProfiles.Count;
12952
12953 mbReply.Data = new MapBlockReplyPacket.DataBlock[len];
12954 int iii;
12955 for (iii = 0; iii < len; iii++)
12956 {
12957 Hashtable mp = (Hashtable)simMapProfiles[iii];
12958 mbReply.Data[iii] = new MapBlockReplyPacket.DataBlock();
12959 mbReply.Data[iii].Name = Util.UTF8.GetBytes((string)mp["name"]);
12960 mbReply.Data[iii].Access = System.Convert.ToByte(mp["access"]);
12961 mbReply.Data[iii].Agents = System.Convert.ToByte(mp["agents"]);
12962 mbReply.Data[iii].MapImageID = new UUID((string)mp["map-image-id"]);
12963 mbReply.Data[iii].RegionFlags = System.Convert.ToUInt32(mp["region-flags"]);
12964 mbReply.Data[iii].WaterHeight = System.Convert.ToByte(mp["water-height"]);
12965 mbReply.Data[iii].X = System.Convert.ToUInt16(mp["x"]);
12966 mbReply.Data[iii].Y = System.Convert.ToUInt16(mp["y"]);
12967 }
12968 this.OutPacket(mbReply, ThrottleOutPacketType.Land);
12969 */
12970 }
12971
12972 /// <summary>
12973 /// Sets the throttles from values supplied by the client
12974 /// </summary>
12975 /// <param name="throttles"></param>
12976 public void SetChildAgentThrottle(byte[] throttles)
12977 {
12978 SetChildAgentThrottle(throttles, 1.0f);
12979 }
12980
12981 public void SetChildAgentThrottle(byte[] throttles,float factor)
12982 {
12983 m_udpClient.SetThrottles(throttles, factor);
12984 GenericCall2 handler = OnUpdateThrottles;
12985 if (handler != null)
12986 {
12987 handler();
12988 }
12989 }
12990
12991 /// <summary>
12992 /// Sets the throttles from values supplied caller
12993 /// </summary>
12994 /// <param name="throttles"></param>
12995 public void SetAgentThrottleSilent(int throttle, int setting)
12996 {
12997 m_udpClient.ForceThrottleSetting(throttle,setting);
12998 }
12999
13000 public int GetAgentThrottleSilent(int throttle)
13001 {
13002 return m_udpClient.GetThrottleSetting(throttle);
13003 }
13004
13005 /// <summary>
13006 /// Get the current throttles for this client as a packed byte array
13007 /// </summary>
13008 /// <param name="multiplier">Unused</param>
13009 /// <returns></returns>
13010 public byte[] GetThrottlesPacked(float multiplier)
13011 {
13012 return m_udpClient.GetThrottlesPacked(multiplier);
13013 }
13014
13015 /// <summary>
13016 /// Cruft?
13017 /// </summary>
13018 public virtual void InPacket(object NewPack)
13019 {
13020 throw new NotImplementedException();
13021 }
13022
13023 /// <summary>
13024 /// This is the starting point for sending a simulator packet out to the client
13025 /// </summary>
13026 /// <param name="packet">Packet to send</param>
13027 /// <param name="throttlePacketType">Throttling category for the packet</param>
13028 protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType)
13029 {
13030 #region BinaryStats
13031 LLUDPServer.LogPacketHeader(false, m_circuitCode, 0, packet.Type, (ushort)packet.Length);
13032 #endregion BinaryStats
13033
13034 OutPacket(packet, throttlePacketType, true);
13035 }
13036
13037 /// <summary>
13038 /// This is the starting point for sending a simulator packet out to the client
13039 /// </summary>
13040 /// <param name="packet">Packet to send</param>
13041 /// <param name="throttlePacketType">Throttling category for the packet</param>
13042 /// <param name="doAutomaticSplitting">True to automatically split oversized
13043 /// packets (the default), or false to disable splitting if the calling code
13044 /// handles splitting manually</param>
13045 protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting)
13046 {
13047 OutPacket(packet, throttlePacketType, doAutomaticSplitting, null);
13048 }
13049
13050 /// <summary>
13051 /// This is the starting point for sending a simulator packet out to the client
13052 /// </summary>
13053 /// <param name="packet">Packet to send</param>
13054 /// <param name="throttlePacketType">Throttling category for the packet</param>
13055 /// <param name="doAutomaticSplitting">True to automatically split oversized
13056 /// packets (the default), or false to disable splitting if the calling code
13057 /// handles splitting manually</param>
13058 /// <param name="method">The method to be called in the event this packet is reliable
13059 /// and unacknowledged. The server will provide normal resend capability if you do not
13060 /// provide your own method.</param>
13061 protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting, UnackedPacketMethod method)
13062 {
13063
13064/* this is causing packet loss for some reason
13065 if(!m_udpClient.IsConnected)
13066 {
13067 PacketPool.Instance.ReturnPacket(packet);
13068 return;
13069 }
13070*/
13071 if (m_outPacketsToDrop != null)
13072 {
13073 if (m_outPacketsToDrop.Contains(packet.Type.ToString()))
13074 {
13075 PacketPool.Instance.ReturnPacket(packet);
13076 return;
13077 }
13078 }
13079
13080 if (DebugPacketLevel > 0)
13081 {
13082 bool logPacket = true;
13083
13084 if (DebugPacketLevel <= 255
13085 && (packet.Type == PacketType.SimStats || packet.Type == PacketType.SimulatorViewerTimeMessage))
13086 logPacket = false;
13087
13088 if (DebugPacketLevel <= 200
13089 && (packet.Type == PacketType.ImagePacket
13090 || packet.Type == PacketType.ImageData
13091 || packet.Type == PacketType.LayerData
13092 || packet.Type == PacketType.CoarseLocationUpdate))
13093 logPacket = false;
13094
13095 if (DebugPacketLevel <= 100 && (packet.Type == PacketType.AvatarAnimation || packet.Type == PacketType.ViewerEffect))
13096 logPacket = false;
13097
13098 if (DebugPacketLevel <= 50
13099 && (packet.Type == PacketType.ImprovedTerseObjectUpdate || packet.Type == PacketType.ObjectUpdate))
13100 logPacket = false;
13101
13102 if (DebugPacketLevel <= 25 && packet.Type == PacketType.ObjectPropertiesFamily)
13103 logPacket = false;
13104
13105 if (logPacket)
13106 m_log.DebugFormat(
13107 "[CLIENT]: PACKET OUT to {0} ({1}) in {2} - {3}",
13108 Name, SceneAgent.IsChildAgent ? "child" : "root ", m_scene.RegionInfo.RegionName, packet.Type);
13109 }
13110
13111 m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting, method);
13112 }
13113
13114 protected void HandleAutopilot(Object sender, string method, List<String> args)
13115 {
13116 float locx = 0;
13117 float locy = 0;
13118 float locz = 0;
13119 uint regionX = 0;
13120 uint regionY = 0;
13121
13122 Utils.LongToUInts(m_scene.RegionInfo.RegionHandle, out regionX, out regionY);
13123 locx = (float)(Convert.ToDouble(args[0]) - (double)regionX);
13124 locy = (float)(Convert.ToDouble(args[1]) - (double)regionY);
13125 locz = Convert.ToSingle(args[2]);
13126
13127 Action<Vector3, bool, bool> handlerAutoPilotGo = OnAutoPilotGo;
13128 if (handlerAutoPilotGo != null)
13129 handlerAutoPilotGo(new Vector3(locx, locy, locz), false, false);
13130 }
13131
13132 /// <summary>
13133 /// Entryway from the client to the simulator. All UDP packets from the client will end up here
13134 /// </summary>
13135 /// <param name="Pack">OpenMetaverse.packet</param>
13136 public void ProcessInPacket(Packet packet)
13137 {
13138 if (m_inPacketsToDrop != null)
13139 if (m_inPacketsToDrop.Contains(packet.Type.ToString()))
13140 return;
13141
13142 if (DebugPacketLevel > 0)
13143 {
13144 bool logPacket = true;
13145
13146 if (DebugPacketLevel <= 255 && packet.Type == PacketType.AgentUpdate)
13147 logPacket = false;
13148
13149 if (DebugPacketLevel <= 200 && packet.Type == PacketType.RequestImage)
13150 logPacket = false;
13151
13152 if (DebugPacketLevel <= 100 && (packet.Type == PacketType.ViewerEffect || packet.Type == PacketType.AgentAnimation))
13153 logPacket = false;
13154
13155 if (DebugPacketLevel <= 25 && packet.Type == PacketType.RequestObjectPropertiesFamily)
13156 logPacket = false;
13157
13158 if (logPacket)
13159 m_log.DebugFormat(
13160 "[CLIENT]: PACKET IN from {0} ({1}) in {2} - {3}",
13161 Name, SceneAgent.IsChildAgent ? "child" : "root ", Scene.Name, packet.Type);
13162 }
13163
13164 if (!ProcessPacketMethod(packet))
13165 m_log.WarnFormat(
13166 "[CLIENT]: Unhandled packet {0} from {1} ({2}) in {3}. Ignoring.",
13167 packet.Type, Name, SceneAgent.IsChildAgent ? "child" : "root ", Scene.Name);
13168 }
13169
13170 private static PrimitiveBaseShape GetShapeFromAddPacket(ObjectAddPacket addPacket)
13171 {
13172 PrimitiveBaseShape shape = new PrimitiveBaseShape();
13173
13174 shape.PCode = addPacket.ObjectData.PCode;
13175 shape.State = addPacket.ObjectData.State;
13176 shape.LastAttachPoint = addPacket.ObjectData.State;
13177 shape.PathBegin = addPacket.ObjectData.PathBegin;
13178 shape.PathEnd = addPacket.ObjectData.PathEnd;
13179 shape.PathScaleX = addPacket.ObjectData.PathScaleX;
13180 shape.PathScaleY = addPacket.ObjectData.PathScaleY;
13181 shape.PathShearX = addPacket.ObjectData.PathShearX;
13182 shape.PathShearY = addPacket.ObjectData.PathShearY;
13183 shape.PathSkew = addPacket.ObjectData.PathSkew;
13184 shape.ProfileBegin = addPacket.ObjectData.ProfileBegin;
13185 shape.ProfileEnd = addPacket.ObjectData.ProfileEnd;
13186 shape.Scale = addPacket.ObjectData.Scale;
13187 shape.PathCurve = addPacket.ObjectData.PathCurve;
13188 shape.ProfileCurve = addPacket.ObjectData.ProfileCurve;
13189 shape.ProfileHollow = addPacket.ObjectData.ProfileHollow;
13190 shape.PathRadiusOffset = addPacket.ObjectData.PathRadiusOffset;
13191 shape.PathRevolutions = addPacket.ObjectData.PathRevolutions;
13192 shape.PathTaperX = addPacket.ObjectData.PathTaperX;
13193 shape.PathTaperY = addPacket.ObjectData.PathTaperY;
13194 shape.PathTwist = addPacket.ObjectData.PathTwist;
13195 shape.PathTwistBegin = addPacket.ObjectData.PathTwistBegin;
13196 Primitive.TextureEntry ntex = new Primitive.TextureEntry(new UUID("89556747-24cb-43ed-920b-47caed15465f"));
13197 shape.TextureEntry = ntex.GetBytes();
13198 //shape.Textures = ntex;
13199 return shape;
13200 }
13201
13202 public ClientInfo GetClientInfo()
13203 {
13204 ClientInfo info = m_udpClient.GetClientInfo();
13205
13206 info.proxyEP = null;
13207 if (info.agentcircuit == null)
13208 info.agentcircuit = RequestClientInfo();
13209
13210 return info;
13211 }
13212
13213 public void SetClientInfo(ClientInfo info)
13214 {
13215 m_udpClient.SetClientInfo(info);
13216 }
13217
13218 #region Media Parcel Members
13219
13220 public void SendParcelMediaCommand(uint flags, ParcelMediaCommandEnum command, float time)
13221 {
13222 ParcelMediaCommandMessagePacket commandMessagePacket = new ParcelMediaCommandMessagePacket();
13223 commandMessagePacket.CommandBlock.Flags = flags;
13224 commandMessagePacket.CommandBlock.Command = (uint)command;
13225 commandMessagePacket.CommandBlock.Time = time;
13226
13227 OutPacket(commandMessagePacket, ThrottleOutPacketType.Task);
13228 }
13229
13230 public void SendParcelMediaUpdate(string mediaUrl, UUID mediaTextureID,
13231 byte autoScale, string mediaType, string mediaDesc, int mediaWidth, int mediaHeight,
13232 byte mediaLoop)
13233 {
13234 ParcelMediaUpdatePacket updatePacket = new ParcelMediaUpdatePacket();
13235 updatePacket.DataBlock.MediaURL = Util.StringToBytes256(mediaUrl);
13236 updatePacket.DataBlock.MediaID = mediaTextureID;
13237 updatePacket.DataBlock.MediaAutoScale = autoScale;
13238
13239 updatePacket.DataBlockExtended.MediaType = Util.StringToBytes256(mediaType);
13240 updatePacket.DataBlockExtended.MediaDesc = Util.StringToBytes256(mediaDesc);
13241 updatePacket.DataBlockExtended.MediaWidth = mediaWidth;
13242 updatePacket.DataBlockExtended.MediaHeight = mediaHeight;
13243 updatePacket.DataBlockExtended.MediaLoop = mediaLoop;
13244
13245 OutPacket(updatePacket, ThrottleOutPacketType.Task);
13246 }
13247
13248 #endregion
13249
13250 #region Camera
13251
13252 public void SendSetFollowCamProperties(UUID objectID, SortedDictionary<int, float> parameters)
13253 {
13254 SetFollowCamPropertiesPacket packet = (SetFollowCamPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.SetFollowCamProperties);
13255 packet.ObjectData.ObjectID = objectID;
13256 SetFollowCamPropertiesPacket.CameraPropertyBlock[] camPropBlock = new SetFollowCamPropertiesPacket.CameraPropertyBlock[parameters.Count];
13257 uint idx = 0;
13258 foreach (KeyValuePair<int, float> pair in parameters)
13259 {
13260 SetFollowCamPropertiesPacket.CameraPropertyBlock block = new SetFollowCamPropertiesPacket.CameraPropertyBlock();
13261 block.Type = pair.Key;
13262 block.Value = pair.Value;
13263
13264 camPropBlock[idx++] = block;
13265 }
13266 packet.CameraProperty = camPropBlock;
13267 OutPacket(packet, ThrottleOutPacketType.Task);
13268 }
13269
13270 public void SendClearFollowCamProperties(UUID objectID)
13271 {
13272 ClearFollowCamPropertiesPacket packet = (ClearFollowCamPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ClearFollowCamProperties);
13273 packet.ObjectData.ObjectID = objectID;
13274 OutPacket(packet, ThrottleOutPacketType.Task);
13275 }
13276
13277 #endregion
13278
13279 public void SetClientOption(string option, string value)
13280 {
13281 switch (option)
13282 {
13283 default:
13284 break;
13285 }
13286 }
13287
13288 public string GetClientOption(string option)
13289 {
13290 switch (option)
13291 {
13292 default:
13293 break;
13294 }
13295 return string.Empty;
13296 }
13297
13298 #region IClientCore
13299
13300 private readonly Dictionary<Type, object> m_clientInterfaces = new Dictionary<Type, object>();
13301
13302 /// <summary>
13303 /// Register an interface on this client, should only be called in the constructor.
13304 /// </summary>
13305 /// <typeparam name="T"></typeparam>
13306 /// <param name="iface"></param>
13307 protected void RegisterInterface<T>(T iface)
13308 {
13309 lock (m_clientInterfaces)
13310 {
13311 if (!m_clientInterfaces.ContainsKey(typeof(T)))
13312 {
13313 m_clientInterfaces.Add(typeof(T), iface);
13314 }
13315 }
13316 }
13317
13318 public bool TryGet<T>(out T iface)
13319 {
13320 if (m_clientInterfaces.ContainsKey(typeof(T)))
13321 {
13322 iface = (T)m_clientInterfaces[typeof(T)];
13323 return true;
13324 }
13325 iface = default(T);
13326 return false;
13327 }
13328
13329 public T Get<T>()
13330 {
13331 return (T)m_clientInterfaces[typeof(T)];
13332 }
13333
13334 public void Disconnect(string reason)
13335 {
13336 Kick(reason);
13337 Thread.Sleep(1000);
13338 Disconnect();
13339 }
13340
13341 public void Disconnect()
13342 {
13343 Close();
13344 }
13345
13346 #endregion
13347
13348 public void RefreshGroupMembership()
13349 {
13350 lock(m_groupPowers)
13351 {
13352 GroupMembershipData activeMembership = null;
13353 if (m_GroupsModule != null)
13354 {
13355 GroupMembershipData[] GroupMembership =
13356 m_GroupsModule.GetMembershipData(AgentId);
13357
13358 m_groupPowers.Clear();
13359
13360 if (GroupMembership != null)
13361 {
13362 for (int i = 0; i < GroupMembership.Length; i++)
13363 {
13364 m_groupPowers[GroupMembership[i].GroupID] = GroupMembership[i].GroupPowers;
13365 }
13366 }
13367
13368 activeMembership = m_GroupsModule.GetActiveMembershipData(AgentId);
13369 if(activeMembership != null)
13370 {
13371 if(!m_groupPowers.ContainsKey(activeMembership.GroupID))
13372 activeMembership = null;
13373 else
13374 {
13375 m_activeGroupID = activeMembership.GroupID;
13376 m_activeGroupName = activeMembership.GroupName;
13377 m_activeGroupPowers = ActiveGroupPowers;
13378 }
13379 }
13380 }
13381
13382 if(activeMembership == null)
13383 {
13384 m_activeGroupID = UUID.Zero;
13385 m_activeGroupName = "";
13386 m_activeGroupPowers = 0;
13387 }
13388 }
13389 }
13390
13391 public void UpdateGroupMembership(GroupMembershipData[] data)
13392 {
13393 lock(m_groupPowers)
13394 {
13395 m_groupPowers.Clear();
13396
13397 if (data != null)
13398 {
13399 for (int i = 0; i < data.Length; i++)
13400 m_groupPowers[data[i].GroupID] = data[i].GroupPowers;
13401 }
13402 }
13403 }
13404
13405 public void GroupMembershipRemove(UUID GroupID)
13406 {
13407 lock(m_groupPowers)
13408 {
13409 if(m_groupPowers.ContainsKey(GroupID))
13410 m_groupPowers.Remove(GroupID);
13411 }
13412 }
13413
13414 public void GroupMembershipAddReplace(UUID GroupID,ulong GroupPowers)
13415 {
13416 lock(m_groupPowers)
13417 {
13418 m_groupPowers[GroupID] = GroupPowers;
13419 }
13420 }
13421
13422 public string Report()
13423 {
13424 return m_udpClient.GetStats();
13425 }
13426
13427 public string XReport(string uptime, string version)
13428 {
13429 return String.Empty;
13430 }
13431
13432 public OSDMap OReport(string uptime, string version)
13433 {
13434 return new OSDMap();
13435 }
13436
13437 /// <summary>
13438 /// Make an asset request to the asset service in response to a client request.
13439 /// </summary>
13440 /// <param name="transferRequest"></param>
13441 /// <param name="taskID"></param>
13442 protected void MakeAssetRequest(TransferRequestPacket transferRequest, UUID taskID)
13443 {
13444 UUID requestID = UUID.Zero;
13445 int sourceType = transferRequest.TransferInfo.SourceType;
13446
13447 if (sourceType == (int)SourceType.Asset)
13448 {
13449 requestID = new UUID(transferRequest.TransferInfo.Params, 0);
13450 }
13451 else if (sourceType == (int)SourceType.SimInventoryItem)
13452 {
13453 requestID = new UUID(transferRequest.TransferInfo.Params, 80);
13454 }
13455 else if (sourceType == (int)SourceType.SimEstate)
13456 {
13457 requestID = taskID;
13458 }
13459
13460// m_log.DebugFormat(
13461// "[LLCLIENTVIEW]: Received transfer request for {0} in {1} type {2} by {3}",
13462// requestID, taskID, (SourceType)sourceType, Name);
13463
13464
13465 //Note, the bool returned from the below function is useless since it is always false.
13466 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived);
13467
13468 }
13469
13470 /// <summary>
13471 /// When we get a reply back from the asset service in response to a client request, send back the data.
13472 /// </summary>
13473 /// <param name="id"></param>
13474 /// <param name="sender"></param>
13475 /// <param name="asset"></param>
13476 protected void AssetReceived(string id, Object sender, AssetBase asset)
13477 {
13478 TransferRequestPacket transferRequest = (TransferRequestPacket)sender;
13479
13480 UUID requestID = UUID.Zero;
13481 byte source = (byte)SourceType.Asset;
13482
13483 AssetRequestToClient req = new AssetRequestToClient();
13484
13485 if (asset == null)
13486 {
13487 // Try the user's asset server
13488 IInventoryAccessModule inventoryAccessModule = Scene.RequestModuleInterface<IInventoryAccessModule>();
13489
13490 string assetServerURL = string.Empty;
13491 if (inventoryAccessModule.IsForeignUser(AgentId, out assetServerURL) && !string.IsNullOrEmpty(assetServerURL))
13492 {
13493 if (!assetServerURL.EndsWith("/") && !assetServerURL.EndsWith("="))
13494 assetServerURL = assetServerURL + "/";
13495
13496 //m_log.DebugFormat("[LLCLIENTVIEW]: asset {0} not found in local storage. Trying user's storage.", assetServerURL + id);
13497 asset = m_scene.AssetService.Get(assetServerURL + id);
13498 }
13499
13500 if (asset == null)
13501 {
13502 req.AssetInf = null;
13503 req.AssetRequestSource = source;
13504 req.IsTextureRequest = false;
13505 req.NumPackets = 0;
13506 req.Params = transferRequest.TransferInfo.Params;
13507 req.RequestAssetID = requestID;
13508 req.TransferRequestID = transferRequest.TransferInfo.TransferID;
13509
13510 SendAssetNotFound(req);
13511 return;
13512 }
13513 }
13514
13515 if (transferRequest.TransferInfo.SourceType == (int)SourceType.Asset)
13516 {
13517 requestID = new UUID(transferRequest.TransferInfo.Params, 0);
13518 }
13519 else if (transferRequest.TransferInfo.SourceType == (int)SourceType.SimInventoryItem)
13520 {
13521 requestID = new UUID(transferRequest.TransferInfo.Params, 80);
13522 source = (byte)SourceType.SimInventoryItem;
13523 //m_log.Debug("asset request " + requestID);
13524 }
13525
13526 // Scripts cannot be retrieved by direct request
13527 if (transferRequest.TransferInfo.SourceType == (int)SourceType.Asset && asset.Type == 10)
13528 return;
13529
13530 // The asset is known to exist and is in our cache, so add it to the AssetRequests list
13531 req.AssetInf = asset;
13532 req.AssetRequestSource = source;
13533 req.IsTextureRequest = false;
13534 req.NumPackets = CalculateNumPackets(asset.Data);
13535 req.Params = transferRequest.TransferInfo.Params;
13536 req.RequestAssetID = requestID;
13537 req.TransferRequestID = transferRequest.TransferInfo.TransferID;
13538
13539 SendAsset(req);
13540 }
13541
13542 /// <summary>
13543 /// Calculate the number of packets required to send the asset to the client.
13544 /// </summary>
13545 /// <param name="data"></param>
13546 /// <returns></returns>
13547 private static int CalculateNumPackets(byte[] data)
13548 {
13549// const uint m_maxPacketSize = 600;
13550 uint m_maxPacketSize = MaxTransferBytesPerPacket;
13551 int numPackets = 1;
13552
13553 if (data == null)
13554 return 0;
13555
13556 if (data.LongLength > m_maxPacketSize)
13557 {
13558 // over max number of bytes so split up file
13559 long restData = data.LongLength - m_maxPacketSize;
13560 int restPackets = (int)((restData + m_maxPacketSize - 1) / m_maxPacketSize);
13561 numPackets += restPackets;
13562 }
13563
13564 return numPackets;
13565 }
13566
13567 public void SendRebakeAvatarTextures(UUID textureID)
13568 {
13569 RebakeAvatarTexturesPacket pack =
13570 (RebakeAvatarTexturesPacket)PacketPool.Instance.GetPacket(PacketType.RebakeAvatarTextures);
13571
13572 pack.TextureData = new RebakeAvatarTexturesPacket.TextureDataBlock();
13573 pack.TextureData.TextureID = textureID;
13574 OutPacket(pack, ThrottleOutPacketType.Task);
13575 }
13576
13577 public struct PacketProcessor
13578 {
13579 /// <summary>
13580 /// Packet handling method.
13581 /// </summary>
13582 public PacketMethod method { get; set; }
13583
13584 /// <summary>
13585 /// Should this packet be handled asynchronously?
13586 /// </summary>
13587 public bool Async { get; set; }
13588
13589 }
13590
13591 public class AsyncPacketProcess
13592 {
13593 public bool result = false;
13594 public readonly LLClientView ClientView = null;
13595 public readonly Packet Pack = null;
13596 public readonly PacketMethod Method = null;
13597 public AsyncPacketProcess(LLClientView pClientview, PacketMethod pMethod, Packet pPack)
13598 {
13599 ClientView = pClientview;
13600 Method = pMethod;
13601 Pack = pPack;
13602 }
13603 }
13604
13605 public static OSD BuildEvent(string eventName, OSD eventBody)
13606 {
13607 OSDMap osdEvent = new OSDMap(2);
13608 osdEvent.Add("message", new OSDString(eventName));
13609 osdEvent.Add("body", eventBody);
13610
13611 return osdEvent;
13612 }
13613
13614 public void SendAvatarInterestsReply(UUID avatarID, uint wantMask, string wantText, uint skillsMask, string skillsText, string languages)
13615 {
13616 AvatarInterestsReplyPacket packet = (AvatarInterestsReplyPacket)PacketPool.Instance.GetPacket(PacketType.AvatarInterestsReply);
13617
13618 packet.AgentData = new AvatarInterestsReplyPacket.AgentDataBlock();
13619 packet.AgentData.AgentID = AgentId;
13620 packet.AgentData.AvatarID = avatarID;
13621
13622 packet.PropertiesData = new AvatarInterestsReplyPacket.PropertiesDataBlock();
13623 packet.PropertiesData.WantToMask = wantMask;
13624 packet.PropertiesData.WantToText = Utils.StringToBytes(wantText);
13625 packet.PropertiesData.SkillsMask = skillsMask;
13626 packet.PropertiesData.SkillsText = Utils.StringToBytes(skillsText);
13627 packet.PropertiesData.LanguagesText = Utils.StringToBytes(languages);
13628 OutPacket(packet, ThrottleOutPacketType.Task);
13629 }
13630
13631 public void SendChangeUserRights(UUID agentID, UUID friendID, int rights)
13632 {
13633 ChangeUserRightsPacket packet = (ChangeUserRightsPacket)PacketPool.Instance.GetPacket(PacketType.ChangeUserRights);
13634
13635 packet.AgentData = new ChangeUserRightsPacket.AgentDataBlock();
13636 packet.AgentData.AgentID = agentID;
13637
13638 packet.Rights = new ChangeUserRightsPacket.RightsBlock[1];
13639 packet.Rights[0] = new ChangeUserRightsPacket.RightsBlock();
13640 packet.Rights[0].AgentRelated = friendID;
13641 packet.Rights[0].RelatedRights = rights;
13642
13643 OutPacket(packet, ThrottleOutPacketType.Task);
13644 }
13645
13646 public void SendTextBoxRequest(string message, int chatChannel, string objectname, UUID ownerID, string ownerFirstName, string ownerLastName, UUID objectId)
13647 {
13648 ScriptDialogPacket dialog = (ScriptDialogPacket)PacketPool.Instance.GetPacket(PacketType.ScriptDialog);
13649 dialog.Data.ObjectID = objectId;
13650 dialog.Data.ChatChannel = chatChannel;
13651 dialog.Data.ImageID = UUID.Zero;
13652 dialog.Data.ObjectName = Util.StringToBytes256(objectname);
13653 // this is the username of the *owner*
13654 dialog.Data.FirstName = Util.StringToBytes256(ownerFirstName);
13655 dialog.Data.LastName = Util.StringToBytes256(ownerLastName);
13656 dialog.Data.Message = Util.StringToBytes(message,512);
13657
13658 ScriptDialogPacket.ButtonsBlock[] buttons = new ScriptDialogPacket.ButtonsBlock[1];
13659 buttons[0] = new ScriptDialogPacket.ButtonsBlock();
13660 buttons[0].ButtonLabel = Util.StringToBytes256("!!llTextBox!!");
13661 dialog.Buttons = buttons;
13662
13663 dialog.OwnerData = new ScriptDialogPacket.OwnerDataBlock[1];
13664 dialog.OwnerData[0] = new ScriptDialogPacket.OwnerDataBlock();
13665 dialog.OwnerData[0].OwnerID = ownerID;
13666
13667 OutPacket(dialog, ThrottleOutPacketType.Task);
13668 }
13669
13670 public void SendAgentTerseUpdate(ISceneEntity p)
13671 {
13672 if (p is ScenePresence)
13673 {
13674// m_log.DebugFormat(
13675// "[LLCLIENTVIEW]: Immediately sending terse agent update for {0} to {1} in {2}",
13676// p.Name, Name, Scene.Name);
13677
13678 // It turns out to get the agent to stop flying, you have to feed it stop flying velocities
13679 // There's no explicit message to send the client to tell it to stop flying.. it relies on the
13680 // velocity, collision plane and avatar height
13681
13682 // Add 1/6 the avatar's height to it's position so it doesn't shoot into the air
13683 // when the avatar stands up
13684
13685 ImprovedTerseObjectUpdatePacket.ObjectDataBlock block =
13686 CreateImprovedTerseBlock(p, false);
13687
13688// const float TIME_DILATION = 1.0f;
13689 ushort timeDilation = Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f);;
13690
13691 ImprovedTerseObjectUpdatePacket packet
13692 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
13693 PacketType.ImprovedTerseObjectUpdate);
13694
13695 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
13696 packet.RegionData.TimeDilation = timeDilation;
13697 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1];
13698
13699 packet.ObjectData[0] = block;
13700
13701 OutPacket(packet, ThrottleOutPacketType.Task, true);
13702 }
13703
13704 //ControllingClient.SendAvatarTerseUpdate(new SendAvatarTerseData(m_rootRegionHandle, (ushort)(m_scene.TimeDilation * ushort.MaxValue), LocalId,
13705 // AbsolutePosition, Velocity, Vector3.Zero, m_bodyRot, new Vector4(0,0,1,AbsolutePosition.Z - 0.5f), m_uuid, null, GetUpdatePriority(ControllingClient)));
13706 }
13707
13708 public void SendPlacesReply(UUID queryID, UUID transactionID,
13709 PlacesReplyData[] data)
13710 {
13711 PlacesReplyPacket reply = null;
13712 PlacesReplyPacket.QueryDataBlock[] dataBlocks =
13713 new PlacesReplyPacket.QueryDataBlock[0];
13714
13715 for (int i = 0 ; i < data.Length ; i++)
13716 {
13717 PlacesReplyPacket.QueryDataBlock block =
13718 new PlacesReplyPacket.QueryDataBlock();
13719
13720 block.OwnerID = data[i].OwnerID;
13721 block.Name = Util.StringToBytes256(data[i].Name);
13722 block.Desc = Util.StringToBytes1024(data[i].Desc);
13723 block.ActualArea = data[i].ActualArea;
13724 block.BillableArea = data[i].BillableArea;
13725 block.Flags = data[i].Flags;
13726 block.GlobalX = data[i].GlobalX;
13727 block.GlobalY = data[i].GlobalY;
13728 block.GlobalZ = data[i].GlobalZ;
13729 block.SimName = Util.StringToBytes256(data[i].SimName);
13730 block.SnapshotID = data[i].SnapshotID;
13731 block.Dwell = data[i].Dwell;
13732 block.Price = data[i].Price;
13733
13734 if (reply != null && reply.Length + block.Length > 1400)
13735 {
13736 OutPacket(reply, ThrottleOutPacketType.Task);
13737
13738 reply = null;
13739 dataBlocks = new PlacesReplyPacket.QueryDataBlock[0];
13740 }
13741
13742 if (reply == null)
13743 {
13744 reply = (PlacesReplyPacket)PacketPool.Instance.GetPacket(PacketType.PlacesReply);
13745 reply.AgentData = new PlacesReplyPacket.AgentDataBlock();
13746 reply.AgentData.AgentID = AgentId;
13747 reply.AgentData.QueryID = queryID;
13748
13749 reply.TransactionData = new PlacesReplyPacket.TransactionDataBlock();
13750 reply.TransactionData.TransactionID = transactionID;
13751
13752 reply.QueryData = dataBlocks;
13753 }
13754
13755 Array.Resize(ref dataBlocks, dataBlocks.Length + 1);
13756 dataBlocks[dataBlocks.Length - 1] = block;
13757 reply.QueryData = dataBlocks;
13758 }
13759 if (reply != null)
13760 OutPacket(reply, ThrottleOutPacketType.Task);
13761 }
13762
13763 public void SendRemoveInventoryItems(UUID[] items)
13764 {
13765 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>();
13766
13767 if (eq == null)
13768 {
13769 m_log.DebugFormat("[LLCLIENT]: Null event queue");
13770 return;
13771 }
13772
13773 OSDMap llsd = new OSDMap(3);
13774
13775 OSDMap AgentDataMap = new OSDMap(1);
13776 AgentDataMap.Add("AgentID", OSD.FromUUID(AgentId));
13777 AgentDataMap.Add("SessionID", OSD.FromUUID(SessionId));
13778
13779 OSDArray AgentData = new OSDArray(1);
13780 AgentData.Add(AgentDataMap);
13781
13782 llsd.Add("AgentData", AgentData);
13783
13784 OSDArray ItemData = new OSDArray();
13785
13786 foreach (UUID item in items)
13787 {
13788 OSDMap ItemDataMap = new OSDMap(2);
13789 ItemDataMap.Add("ItemID", OSD.FromUUID(item));
13790 ItemDataMap.Add("AgentID", OSD.FromUUID(AgentId));
13791
13792 ItemData.Add(ItemDataMap);
13793 }
13794
13795 llsd.Add("InventoryData", ItemData);
13796
13797 eq.Enqueue(BuildEvent("RemoveInventoryItem",
13798 llsd), AgentId);
13799 }
13800
13801 public void SendRemoveInventoryFolders(UUID[] folders)
13802 {
13803 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>();
13804
13805 if (eq == null)
13806 {
13807 m_log.DebugFormat("[LLCLIENT]: Null event queue");
13808 return;
13809 }
13810
13811 OSDMap llsd = new OSDMap(3);
13812
13813 OSDMap AgentDataMap = new OSDMap(1);
13814 AgentDataMap.Add("AgentID", OSD.FromUUID(AgentId));
13815 AgentDataMap.Add("SessionID", OSD.FromUUID(SessionId));
13816
13817 OSDArray AgentData = new OSDArray(1);
13818 AgentData.Add(AgentDataMap);
13819
13820 llsd.Add("AgentData", AgentData);
13821
13822 OSDArray FolderData = new OSDArray();
13823
13824 foreach (UUID folder in folders)
13825 {
13826 OSDMap FolderDataMap = new OSDMap(2);
13827 FolderDataMap.Add("FolderID", OSD.FromUUID(folder));
13828 FolderDataMap.Add("AgentID", OSD.FromUUID(AgentId));
13829
13830 FolderData.Add(FolderDataMap);
13831 }
13832
13833 llsd.Add("FolderData", FolderData);
13834
13835 eq.Enqueue(BuildEvent("RemoveInventoryFolder",
13836 llsd), AgentId);
13837 }
13838
13839 private byte[] EncodeU32(uint val)
13840 {
13841 byte[] ret = BitConverter.GetBytes(val);
13842 if (BitConverter.IsLittleEndian)
13843 Array.Reverse(ret);
13844 return ret;
13845 }
13846
13847 public void SendBulkUpdateInventory(InventoryFolderBase[] folders, InventoryItemBase[] items)
13848 {
13849 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>();
13850
13851 if (eq == null)
13852 {
13853 m_log.DebugFormat("[LLCLIENT]: Null event queue");
13854 return;
13855 }
13856
13857 OSDMap llsd = new OSDMap(3);
13858
13859 OSDMap AgentDataMap = new OSDMap(1);
13860 AgentDataMap.Add("AgentID", OSD.FromUUID(AgentId));
13861 AgentDataMap.Add("SessionID", OSD.FromUUID(SessionId));
13862 AgentDataMap.Add("TransactionID", OSD.FromUUID(UUID.Random()));
13863
13864 OSDArray AgentData = new OSDArray(1);
13865 AgentData.Add(AgentDataMap);
13866
13867 llsd.Add("AgentData", AgentData);
13868
13869 OSDArray FolderData = new OSDArray();
13870
13871 foreach (InventoryFolderBase folder in folders)
13872 {
13873 OSDMap FolderDataMap = new OSDMap(5);
13874 FolderDataMap.Add("FolderID", OSD.FromUUID(folder.ID));
13875 FolderDataMap.Add("AgentID", OSD.FromUUID(AgentId));
13876 FolderDataMap.Add("ParentID", OSD.FromUUID(folder.ParentID));
13877 FolderDataMap.Add("Type", OSD.FromInteger(folder.Type));
13878 FolderDataMap.Add("Name", OSD.FromString(folder.Name));
13879
13880 FolderData.Add(FolderDataMap);
13881 }
13882
13883 llsd.Add("FolderData", FolderData);
13884
13885 OSDArray ItemData = new OSDArray();
13886
13887 foreach (InventoryItemBase item in items)
13888 {
13889 OSDMap ItemDataMap = new OSDMap();
13890
13891 ItemDataMap.Add("ItemID", OSD.FromUUID(item.ID));
13892 ItemDataMap.Add("FolderID", OSD.FromUUID(item.Folder));
13893
13894 ItemDataMap.Add("CreatorID", OSD.FromUUID(item.CreatorIdAsUuid));
13895 ItemDataMap.Add("OwnerID", OSD.FromUUID(item.Owner));
13896 ItemDataMap.Add("GroupID", OSD.FromUUID(item.GroupID));
13897 ItemDataMap.Add("BaseMask", OSD.FromBinary(EncodeU32((uint)item.BasePermissions)));
13898 ItemDataMap.Add("OwnerMask", OSD.FromBinary(EncodeU32((uint)item.CurrentPermissions)));
13899 ItemDataMap.Add("GroupMask", OSD.FromBinary(EncodeU32((uint)item.GroupPermissions)));
13900 ItemDataMap.Add("EveryoneMask", OSD.FromBinary(EncodeU32((uint)item.EveryOnePermissions)));
13901 ItemDataMap.Add("NextOwnerMask", OSD.FromBinary(EncodeU32((uint)item.NextPermissions)));
13902 ItemDataMap.Add("GroupOwned", OSD.FromBoolean(item.GroupOwned));
13903 ItemDataMap.Add("AssetID", OSD.FromUUID(item.AssetID));
13904 ItemDataMap.Add("Type", OSD.FromInteger(item.AssetType));
13905 ItemDataMap.Add("InvType", OSD.FromInteger(item.InvType));
13906 ItemDataMap.Add("Flags", OSD.FromBinary(EncodeU32((uint)item.Flags)));
13907 ItemDataMap.Add("SaleType", OSD.FromInteger((byte)item.SaleType));
13908 ItemDataMap.Add("SalePrice", OSD.FromInteger(item.SalePrice));
13909 ItemDataMap.Add("Name", OSD.FromString(item.Name));
13910 ItemDataMap.Add("Description", OSD.FromString(item.Description));
13911 ItemDataMap.Add("CreationDate", OSD.FromInteger(item.CreationDate));
13912
13913 ItemDataMap.Add("CRC", OSD.FromBinary(EncodeU32(
13914 Helpers.InventoryCRC(1000, 0, (sbyte)item.InvType,
13915 (sbyte)item.AssetType, item.AssetID,
13916 item.GroupID, 100,
13917 item.Owner, item.CreatorIdAsUuid,
13918 item.ID, item.Folder,
13919 (uint)PermissionMask.All, 1, (uint)PermissionMask.All, (uint)PermissionMask.All,
13920 (uint)PermissionMask.All)
13921 )));
13922 ItemDataMap.Add("CallbackID", 0);
13923
13924 ItemData.Add(ItemDataMap);
13925 }
13926
13927 llsd.Add("ItemData", ItemData);
13928
13929 eq.Enqueue(BuildEvent("BulkUpdateInventory",
13930 llsd), AgentId);
13931 }
13932
13933 private HashSet<string> m_outPacketsToDrop;
13934
13935 public bool AddOutPacketToDropSet(string packetName)
13936 {
13937 if (m_outPacketsToDrop == null)
13938 m_outPacketsToDrop = new HashSet<string>();
13939
13940 return m_outPacketsToDrop.Add(packetName);
13941 }
13942
13943 public bool RemoveOutPacketFromDropSet(string packetName)
13944 {
13945 if (m_outPacketsToDrop == null)
13946 return false;
13947
13948 return m_outPacketsToDrop.Remove(packetName);
13949 }
13950
13951 public HashSet<string> GetOutPacketDropSet()
13952 {
13953 return new HashSet<string>(m_outPacketsToDrop);
13954 }
13955
13956 private HashSet<string> m_inPacketsToDrop;
13957
13958 public bool AddInPacketToDropSet(string packetName)
13959 {
13960 if (m_inPacketsToDrop == null)
13961 m_inPacketsToDrop = new HashSet<string>();
13962
13963 return m_inPacketsToDrop.Add(packetName);
13964 }
13965
13966 public bool RemoveInPacketFromDropSet(string packetName)
13967 {
13968 if (m_inPacketsToDrop == null)
13969 return false;
13970
13971 return m_inPacketsToDrop.Remove(packetName);
13972 }
13973
13974 public HashSet<string> GetInPacketDropSet()
13975 {
13976 return new HashSet<string>(m_inPacketsToDrop);
13977 }
13978 }
13979}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs
new file mode 100644
index 0000000..deefd40
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs
@@ -0,0 +1,360 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Threading;
30using System.Collections;
31using System.Collections.Generic;
32using System.Reflection;
33using OpenMetaverse;
34using OpenMetaverse.Imaging;
35using OpenSim.Framework;
36using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Services.Interfaces;
38using log4net;
39
40namespace OpenSim.Region.ClientStack.LindenUDP
41{
42 /// <summary>
43 /// This class handles UDP texture requests.
44 /// </summary>
45 public class LLImageManager
46 {
47 private sealed class J2KImageComparer : IComparer<J2KImage>
48 {
49 public int Compare(J2KImage x, J2KImage y)
50 {
51 return x.Priority.CompareTo(y.Priority);
52 }
53 }
54
55 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
56 private bool m_shuttingdown;
57 private AssetBase m_missingImage;
58 private IAssetService m_assetCache;
59 private IJ2KDecoder m_j2kDecodeModule;
60
61 /// <summary>
62 /// Priority queue for determining which image to send first.
63 /// </summary>
64 private C5.IntervalHeap<J2KImage> m_priorityQueue = new C5.IntervalHeap<J2KImage>(10, new J2KImageComparer());
65
66 /// <summary>
67 /// Used to control thread access to the priority queue.
68 /// </summary>
69 private object m_syncRoot = new object();
70
71 /// <summary>
72 /// Client served by this image manager
73 /// </summary>
74 public IClientAPI Client { get; private set; }
75
76 public AssetBase MissingImage { get { return m_missingImage; } }
77
78 public LLImageManager(IClientAPI client, IAssetService pAssetCache, IJ2KDecoder pJ2kDecodeModule)
79 {
80 Client = client;
81 m_assetCache = pAssetCache;
82
83 if (pAssetCache != null)
84 m_missingImage = pAssetCache.Get("5748decc-f629-461c-9a36-a35a221fe21f");
85
86 if (m_missingImage == null)
87 m_log.Error("[ClientView] - Couldn't set missing image asset, falling back to missing image packet. This is known to crash the client");
88
89 m_j2kDecodeModule = pJ2kDecodeModule;
90 }
91
92 /// <summary>
93 /// Handles an incoming texture request or update to an existing texture request
94 /// </summary>
95 /// <param name="newRequest"></param>
96 public void EnqueueReq(TextureRequestArgs newRequest)
97 {
98 if (!m_shuttingdown)
99 {
100 J2KImage imgrequest;
101
102 // Do a linear search for this texture download
103 lock (m_syncRoot)
104 m_priorityQueue.Find(delegate(J2KImage img) { return img.TextureID == newRequest.RequestedAssetID; }, out imgrequest);
105
106 if (imgrequest != null)
107 {
108 if (newRequest.DiscardLevel == -1 && newRequest.Priority == 0f)
109 {
110 //m_log.Debug("[TEX]: (CAN) ID=" + newRequest.RequestedAssetID);
111
112 try
113 {
114 lock (m_syncRoot)
115 m_priorityQueue.Delete(imgrequest.PriorityQueueHandle);
116 }
117 catch (Exception) { }
118 }
119 else
120 {
121// m_log.DebugFormat(
122// "[LL IMAGE MANAGER]: Received duplicate of existing request for {0}, start packet {1} from {2}",
123// newRequest.RequestedAssetID, newRequest.PacketNumber, m_client.Name);
124
125// m_log.DebugFormat("[TEX]: (UPD) ID={0}: D={1}, S={2}, P={3}",
126// newRequest.RequestedAssetID, newRequest.DiscardLevel, newRequest.PacketNumber, newRequest.Priority);
127
128 //Check the packet sequence to make sure this isn't older than
129 //one we've already received
130 if (newRequest.requestSequence > imgrequest.LastSequence)
131 {
132 //Update the sequence number of the last RequestImage packet
133 imgrequest.LastSequence = newRequest.requestSequence;
134
135 //Update the requested discard level
136 imgrequest.DiscardLevel = newRequest.DiscardLevel;
137
138 //Update the requested packet number
139 imgrequest.StartPacket = Math.Max(1, newRequest.PacketNumber);
140
141 //Update the requested priority
142 imgrequest.Priority = newRequest.Priority;
143
144 UpdateImageInQueue(imgrequest);
145
146 imgrequest.RunUpdate();
147
148// J2KImage imgrequest2 = new J2KImage(this);
149// imgrequest2.J2KDecoder = m_j2kDecodeModule;
150// imgrequest2.AssetService = m_assetCache;
151// imgrequest2.AgentID = m_client.AgentId;
152// imgrequest2.InventoryAccessModule = m_client.Scene.RequestModuleInterface<IInventoryAccessModule>();
153// imgrequest2.DiscardLevel = newRequest.DiscardLevel;
154// imgrequest2.StartPacket = Math.Max(1, newRequest.PacketNumber);
155// imgrequest2.Priority = newRequest.Priority;
156// imgrequest2.TextureID = newRequest.RequestedAssetID;
157// imgrequest2.Priority = newRequest.Priority;
158//
159// //Add this download to the priority queue
160// AddImageToQueue(imgrequest2);
161//
162// imgrequest2.RunUpdate();
163
164 }
165// else
166// {
167// m_log.DebugFormat(
168// "[LL IMAGE MANAGER]: Ignoring duplicate of existing request for {0} (sequence {1}) from {2} as its request sequence {3} is not greater",
169// newRequest.RequestedAssetID, imgrequest.LastSequence, m_client.Name, newRequest.requestSequence);
170// }
171 }
172 }
173 else
174 {
175 if (newRequest.DiscardLevel == -1 && newRequest.Priority == 0f)
176 {
177 //m_log.DebugFormat("[TEX]: (IGN) ID={0}: D={1}, S={2}, P={3}",
178 // newRequest.RequestedAssetID, newRequest.DiscardLevel, newRequest.PacketNumber, newRequest.Priority);
179 }
180 else
181 {
182// m_log.DebugFormat(
183// "[LL IMAGE MANAGER]: Received request for {0}, start packet {1} from {2}",
184// newRequest.RequestedAssetID, newRequest.PacketNumber, m_client.Name);
185
186 //m_log.DebugFormat("[TEX]: (NEW) ID={0}: D={1}, S={2}, P={3}",
187 // newRequest.RequestedAssetID, newRequest.DiscardLevel, newRequest.PacketNumber, newRequest.Priority);
188
189 imgrequest = new J2KImage(this);
190 imgrequest.J2KDecoder = m_j2kDecodeModule;
191 imgrequest.AssetService = m_assetCache;
192 imgrequest.AgentID = Client.AgentId;
193 imgrequest.InventoryAccessModule = Client.Scene.RequestModuleInterface<IInventoryAccessModule>();
194 imgrequest.DiscardLevel = newRequest.DiscardLevel;
195 imgrequest.StartPacket = Math.Max(1, newRequest.PacketNumber);
196 imgrequest.Priority = newRequest.Priority;
197 imgrequest.TextureID = newRequest.RequestedAssetID;
198 imgrequest.Priority = newRequest.Priority;
199
200 //Add this download to the priority queue
201 AddImageToQueue(imgrequest);
202
203 imgrequest.RunUpdate();
204 }
205 }
206 }
207 }
208
209 public bool HasUpdates()
210 {
211 J2KImage image = GetHighestPriorityImage();
212
213 return image != null && image.IsDecoded;
214 }
215
216 public bool ProcessImageQueue(int packetsToSend)
217 {
218 int packetsSent = 0;
219
220 while (packetsSent < packetsToSend)
221 {
222 J2KImage image = GetHighestPriorityImage();
223
224 // If null was returned, the texture priority queue is currently empty
225 if (image == null)
226 break;
227
228 if (image.IsDecoded)
229 {
230 int sent;
231 bool imageDone = image.SendPackets(Client, packetsToSend - packetsSent, out sent);
232 packetsSent += sent;
233
234 // If the send is complete, destroy any knowledge of this transfer
235 if (imageDone)
236 RemoveImageFromQueue(image);
237 }
238 else
239 {
240 // TODO: This is a limitation of how LLImageManager is currently
241 // written. Undecoded textures should not be going into the priority
242 // queue, because a high priority undecoded texture will clog up the
243 // pipeline for a client
244// m_log.DebugFormat(
245// "[LL IMAGE MANAGER]: Exiting image queue processing early on encountering undecoded image {0}",
246// image.TextureID);
247
248 break;
249 }
250 }
251
252// if (packetsSent != 0)
253// m_log.DebugFormat("[LL IMAGE MANAGER]: Processed {0} packets from image queue", packetsSent);
254
255 return m_priorityQueue.Count > 0;
256 }
257
258 /// <summary>
259 /// Faux destructor
260 /// </summary>
261 public void Close()
262 {
263 m_shuttingdown = true;
264 }
265
266 /// <summary>
267 /// Clear the image queue.
268 /// </summary>
269 /// <returns>The number of requests cleared.</returns>
270 public int ClearImageQueue()
271 {
272 int requestsDeleted;
273
274 lock (m_priorityQueue)
275 {
276 requestsDeleted = m_priorityQueue.Count;
277
278 // Surprisingly, there doesn't seem to be a clear method at this time.
279 while (!m_priorityQueue.IsEmpty)
280 m_priorityQueue.DeleteMax();
281 }
282
283 return requestsDeleted;
284 }
285
286 /// <summary>
287 /// Returns an array containing all the images in the queue.
288 /// </summary>
289 /// <returns></returns>
290 public J2KImage[] GetImages()
291 {
292 lock (m_priorityQueue)
293 return m_priorityQueue.ToArray();
294 }
295
296 #region Priority Queue Helpers
297
298 private J2KImage GetHighestPriorityImage()
299 {
300 J2KImage image = null;
301
302 lock (m_syncRoot)
303 {
304 if (m_priorityQueue.Count > 0)
305 {
306 try
307 {
308 image = m_priorityQueue.FindMax();
309 }
310 catch (Exception) { }
311 }
312 }
313 return image;
314 }
315
316 private void AddImageToQueue(J2KImage image)
317 {
318 image.PriorityQueueHandle = null;
319
320 lock (m_syncRoot)
321 {
322 try
323 {
324 m_priorityQueue.Add(ref image.PriorityQueueHandle, image);
325 }
326 catch (Exception) { }
327 }
328 }
329
330 private void RemoveImageFromQueue(J2KImage image)
331 {
332 lock (m_syncRoot)
333 {
334 try
335 {
336 m_priorityQueue.Delete(image.PriorityQueueHandle);
337 }
338 catch (Exception) { }
339 }
340 }
341
342 private void UpdateImageInQueue(J2KImage image)
343 {
344 lock (m_syncRoot)
345 {
346 try
347 {
348 m_priorityQueue.Replace(image.PriorityQueueHandle, image);
349 }
350 catch (Exception)
351 {
352 image.PriorityQueueHandle = null;
353 m_priorityQueue.Add(ref image.PriorityQueueHandle, image);
354 }
355 }
356 }
357
358 #endregion Priority Queue Helpers
359 }
360} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
new file mode 100644
index 0000000..439621a
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
@@ -0,0 +1,918 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Net;
31using System.Threading;
32using log4net;
33using OpenSim.Framework;
34using OpenSim.Framework.Monitoring;
35using OpenMetaverse;
36using OpenMetaverse.Packets;
37
38using TokenBucket = OpenSim.Region.ClientStack.LindenUDP.TokenBucket;
39
40namespace OpenSim.Region.ClientStack.LindenUDP
41{
42 #region Delegates
43
44 /// <summary>
45 /// Fired when updated networking stats are produced for this client
46 /// </summary>
47 /// <param name="inPackets">Number of incoming packets received since this
48 /// event was last fired</param>
49 /// <param name="outPackets">Number of outgoing packets sent since this
50 /// event was last fired</param>
51 /// <param name="unAckedBytes">Current total number of bytes in packets we
52 /// are waiting on ACKs for</param>
53 public delegate void PacketStats(int inPackets, int outPackets, int unAckedBytes);
54 /// <summary>
55 /// Fired when the queue for one or more packet categories is empty. This
56 /// event can be hooked to put more data on the empty queues
57 /// </summary>
58 /// <param name="category">Categories of the packet queues that are empty</param>
59 public delegate void QueueEmpty(ThrottleOutPacketTypeFlags categories);
60
61 #endregion Delegates
62
63 /// <summary>
64 /// Tracks state for a client UDP connection and provides client-specific methods
65 /// </summary>
66 public sealed class LLUDPClient
67 {
68 // TODO: Make this a config setting
69 /// <summary>Percentage of the task throttle category that is allocated to avatar and prim
70 /// state updates</summary>
71 const float STATE_TASK_PERCENTAGE = 0.8f;
72
73 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
74
75 /// <summary>The number of packet categories to throttle on. If a throttle category is added
76 /// or removed, this number must also change</summary>
77 const int THROTTLE_CATEGORY_COUNT = 8;
78
79 /// <summary>
80 /// Controls whether information is logged about each outbound packet immediately before it is sent. For debug purposes.
81 /// </summary>
82 /// <remarks>Any level above 0 will turn on logging.</remarks>
83 public int DebugDataOutLevel { get; set; }
84
85 /// <summary>
86 /// Controls whether information is logged about each outbound packet immediately before it is sent. For debug purposes.
87 /// </summary>
88 /// <remarks>Any level above 0 will turn on logging.</remarks>
89 public int ThrottleDebugLevel
90 {
91 get
92 {
93 return m_throttleDebugLevel;
94 }
95
96 set
97 {
98 m_throttleDebugLevel = value;
99/*
100 m_throttleClient.DebugLevel = m_throttleDebugLevel;
101 foreach (TokenBucket tb in m_throttleCategories)
102 tb.DebugLevel = m_throttleDebugLevel;
103 */
104 }
105 }
106 private int m_throttleDebugLevel;
107
108 /// <summary>Fired when updated networking stats are produced for this client</summary>
109 public event PacketStats OnPacketStats;
110 /// <summary>Fired when the queue for a packet category is empty. This event can be
111 /// hooked to put more data on the empty queue</summary>
112 public event QueueEmpty OnQueueEmpty;
113
114 public event Func<ThrottleOutPacketTypeFlags, bool> HasUpdates;
115
116 /// <summary>AgentID for this client</summary>
117 public readonly UUID AgentID;
118 /// <summary>The remote address of the connected client</summary>
119 public readonly IPEndPoint RemoteEndPoint;
120 /// <summary>Circuit code that this client is connected on</summary>
121 public readonly uint CircuitCode;
122 /// <summary>Sequence numbers of packets we've received (for duplicate checking)</summary>
123 public IncomingPacketHistoryCollection PacketArchive = new IncomingPacketHistoryCollection(200);
124
125 /// <summary>Packets we have sent that need to be ACKed by the client</summary>
126 public UnackedPacketCollection NeedAcks = new UnackedPacketCollection();
127
128 /// <summary>ACKs that are queued up, waiting to be sent to the client</summary>
129 public DoubleLocklessQueue<uint> PendingAcks = new DoubleLocklessQueue<uint>();
130
131 /// <summary>Current packet sequence number</summary>
132 public int CurrentSequence;
133 /// <summary>Current ping sequence number</summary>
134 public byte CurrentPingSequence;
135 /// <summary>True when this connection is alive, otherwise false</summary>
136 public bool IsConnected = true;
137 /// <summary>True when this connection is paused, otherwise false</summary>
138 public bool IsPaused;
139 /// <summary>Environment.TickCount when the last packet was received for this client</summary>
140 public int TickLastPacketReceived;
141
142 /// <summary>Smoothed round-trip time. A smoothed average of the round-trip time for sending a
143 /// reliable packet to the client and receiving an ACK</summary>
144 public float SRTT;
145 /// <summary>Round-trip time variance. Measures the consistency of round-trip times</summary>
146 public float RTTVAR;
147 /// <summary>Retransmission timeout. Packets that have not been acknowledged in this number of
148 /// milliseconds or longer will be resent</summary>
149 /// <remarks>Calculated from <seealso cref="SRTT"/> and <seealso cref="RTTVAR"/> using the
150 /// guidelines in RFC 2988</remarks>
151 public int RTO;
152 /// <summary>Number of bytes received since the last acknowledgement was sent out. This is used
153 /// to loosely follow the TCP delayed ACK algorithm in RFC 1122 (4.2.3.2)</summary>
154 public int BytesSinceLastACK;
155 /// <summary>Number of packets received from this client</summary>
156 public int PacketsReceived;
157 /// <summary>Number of packets sent to this client</summary>
158 public int PacketsSent;
159 /// <summary>Number of packets resent to this client</summary>
160 public int PacketsResent;
161 /// <summary>Total byte count of unacked packets sent to this client</summary>
162 public int UnackedBytes;
163
164 private int m_packetsUnAckReported;
165 /// <summary>Total number of received packets that we have reported to the OnPacketStats event(s)</summary>
166 private int m_packetsReceivedReported;
167 /// <summary>Total number of sent packets that we have reported to the OnPacketStats event(s)</summary>
168 private int m_packetsSentReported;
169 /// <summary>Holds the Environment.TickCount value of when the next OnQueueEmpty can be fired</summary>
170 private double m_nextOnQueueEmpty = 0;
171
172 /// <summary>Throttle bucket for this agent's connection</summary>
173 private AdaptiveTokenBucket m_throttleClient;
174 public AdaptiveTokenBucket FlowThrottle
175 {
176 get { return m_throttleClient; }
177 }
178
179 /// <summary>Throttle buckets for each packet category</summary>
180 private readonly TokenBucket[] m_throttleCategories;
181 /// <summary>Outgoing queues for throttled packets</summary>
182 private DoubleLocklessQueue<OutgoingPacket>[] m_packetOutboxes = new DoubleLocklessQueue<OutgoingPacket>[THROTTLE_CATEGORY_COUNT];
183 /// <summary>A container that can hold one packet for each outbox, used to store
184 /// dequeued packets that are being held for throttling</summary>
185 private OutgoingPacket[] m_nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT];
186 /// <summary>A reference to the LLUDPServer that is managing this client</summary>
187 private readonly LLUDPServer m_udpServer;
188
189 /// <summary>Caches packed throttle information</summary>
190 private byte[] m_packedThrottles;
191
192 private int m_defaultRTO = 1000; // 1sec is the recommendation in the RFC
193 private int m_maxRTO = 60000;
194 public bool m_deliverPackets = true;
195
196 private float m_burstTime;
197
198 public int m_lastStartpingTimeMS;
199 public int m_pingMS;
200
201 public int PingTimeMS
202 {
203 get
204 {
205 if (m_pingMS < 10)
206 return 10;
207 if(m_pingMS > 2000)
208 return 2000;
209 return m_pingMS;
210 }
211 }
212
213 /// <summary>
214 /// This is the percentage of the udp texture queue to add to the task queue since
215 /// textures are now generally handled through http.
216 /// </summary>
217 private double m_cannibalrate = 0.0;
218
219 private ClientInfo m_info = new ClientInfo();
220
221 /// <summary>
222 /// Default constructor
223 /// </summary>
224 /// <param name="server">Reference to the UDP server this client is connected to</param>
225 /// <param name="rates">Default throttling rates and maximum throttle limits</param>
226 /// <param name="parentThrottle">Parent HTB (hierarchical token bucket)
227 /// that the child throttles will be governed by</param>
228 /// <param name="circuitCode">Circuit code for this connection</param>
229 /// <param name="agentID">AgentID for the connected agent</param>
230 /// <param name="remoteEndPoint">Remote endpoint for this connection</param>
231 /// <param name="defaultRTO">
232 /// Default retransmission timeout for unacked packets. The RTO will never drop
233 /// beyond this number.
234 /// </param>
235 /// <param name="maxRTO">
236 /// The maximum retransmission timeout for unacked packets. The RTO will never exceed this number.
237 /// </param>
238 public LLUDPClient(
239 LLUDPServer server, ThrottleRates rates, TokenBucket parentThrottle, uint circuitCode, UUID agentID,
240 IPEndPoint remoteEndPoint, int defaultRTO, int maxRTO)
241 {
242 AgentID = agentID;
243 RemoteEndPoint = remoteEndPoint;
244 CircuitCode = circuitCode;
245 m_udpServer = server;
246 if (defaultRTO != 0)
247 m_defaultRTO = defaultRTO;
248 if (maxRTO != 0)
249 m_maxRTO = maxRTO;
250
251 m_burstTime = rates.BrustTime;
252 float m_burst = rates.ClientMaxRate * m_burstTime;
253
254 // Create a token bucket throttle for this client that has the scene token bucket as a parent
255 m_throttleClient = new AdaptiveTokenBucket(parentThrottle, rates.ClientMaxRate, m_burst, rates.AdaptiveThrottlesEnabled);
256
257 // Create an array of token buckets for this clients different throttle categories
258 m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT];
259
260 m_cannibalrate = rates.CannibalizeTextureRate;
261
262 m_burst = rates.Total * rates.BrustTime;
263
264 for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
265 {
266 ThrottleOutPacketType type = (ThrottleOutPacketType)i;
267
268 // Initialize the packet outboxes, where packets sit while they are waiting for tokens
269 m_packetOutboxes[i] = new DoubleLocklessQueue<OutgoingPacket>();
270 // Initialize the token buckets that control the throttling for each category
271 m_throttleCategories[i] = new TokenBucket(m_throttleClient, rates.GetRate(type), m_burst);
272 }
273
274 // Default the retransmission timeout to one second
275 RTO = m_defaultRTO;
276
277 // Initialize this to a sane value to prevent early disconnects
278 TickLastPacketReceived = Environment.TickCount & Int32.MaxValue;
279 m_pingMS = (int)(3.0 * server.TickCountResolution); // so filter doesnt start at 0;
280 }
281
282 /// <summary>
283 /// Shuts down this client connection
284 /// </summary>
285 public void Shutdown()
286 {
287 IsConnected = false;
288 for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
289 {
290 m_packetOutboxes[i].Clear();
291 m_nextPackets[i] = null;
292 }
293
294 // pull the throttle out of the scene throttle
295 m_throttleClient.Parent.UnregisterRequest(m_throttleClient);
296 PendingAcks.Clear();
297 NeedAcks.Clear();
298 }
299
300 /// <summary>
301 /// Gets information about this client connection
302 /// </summary>
303 /// <returns>Information about the client connection</returns>
304 public ClientInfo GetClientInfo()
305 {
306 // TODO: This data structure is wrong in so many ways. Locking and copying the entire lists
307 // of pending and needed ACKs for every client every time some method wants information about
308 // this connection is a recipe for poor performance
309
310 m_info.resendThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate;
311 m_info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate;
312 m_info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate;
313 m_info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate;
314 m_info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate;
315 m_info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate;
316 m_info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate;
317 m_info.totalThrottle = (int)m_throttleClient.DripRate;
318 return m_info;
319 }
320
321 /// <summary>
322 /// Modifies the UDP throttles
323 /// </summary>
324 /// <param name="info">New throttling values</param>
325 public void SetClientInfo(ClientInfo info)
326 {
327 // TODO: Allowing throttles to be manually set from this function seems like a reasonable
328 // idea. On the other hand, letting external code manipulate our ACK accounting is not
329 // going to happen
330 throw new NotImplementedException();
331 }
332
333 /// <summary>
334 /// Get the total number of pakcets queued for this client.
335 /// </summary>
336 /// <returns></returns>
337 public int GetTotalPacketsQueuedCount()
338 {
339 int total = 0;
340
341 for (int i = 0; i <= (int)ThrottleOutPacketType.Asset; i++)
342 total += m_packetOutboxes[i].Count;
343
344 return total;
345 }
346
347 /// <summary>
348 /// Get the number of packets queued for the given throttle type.
349 /// </summary>
350 /// <returns></returns>
351 /// <param name="throttleType"></param>
352 public int GetPacketsQueuedCount(ThrottleOutPacketType throttleType)
353 {
354 int icat = (int)throttleType;
355 if (icat > 0 && icat < THROTTLE_CATEGORY_COUNT)
356 return m_packetOutboxes[icat].Count;
357 else
358 return 0;
359 }
360
361 /// <summary>
362 /// Return statistics information about client packet queues.
363 /// </summary>
364 /// <remarks>
365 /// FIXME: This should really be done in a more sensible manner rather than sending back a formatted string.
366 /// </remarks>
367 /// <returns></returns>
368 public string GetStats()
369 {
370 return string.Format(
371 "{0,7} {1,7} {2,7} {3,9} {4,7} {5,7} {6,7} {7,7} {8,7} {9,8} {10,7} {11,7}",
372 Util.EnvironmentTickCountSubtract(TickLastPacketReceived),
373 PacketsReceived,
374 PacketsSent,
375 PacketsResent,
376 UnackedBytes,
377 m_packetOutboxes[(int)ThrottleOutPacketType.Resend].Count,
378 m_packetOutboxes[(int)ThrottleOutPacketType.Land].Count,
379 m_packetOutboxes[(int)ThrottleOutPacketType.Wind].Count,
380 m_packetOutboxes[(int)ThrottleOutPacketType.Cloud].Count,
381 m_packetOutboxes[(int)ThrottleOutPacketType.Task].Count,
382 m_packetOutboxes[(int)ThrottleOutPacketType.Texture].Count,
383 m_packetOutboxes[(int)ThrottleOutPacketType.Asset].Count);
384 }
385
386 public void SendPacketStats()
387 {
388 PacketStats callback = OnPacketStats;
389 if (callback != null)
390 {
391 int newPacketsReceived = PacketsReceived - m_packetsReceivedReported;
392 int newPacketsSent = PacketsSent - m_packetsSentReported;
393 int newPacketUnAck = UnackedBytes - m_packetsUnAckReported;
394 callback(newPacketsReceived, newPacketsSent, UnackedBytes);
395
396 m_packetsReceivedReported += newPacketsReceived;
397 m_packetsSentReported += newPacketsSent;
398 m_packetsUnAckReported += newPacketUnAck;
399 }
400 }
401
402 public void SetThrottles(byte[] throttleData)
403 {
404 SetThrottles(throttleData, 1.0f);
405 }
406
407 public void SetThrottles(byte[] throttleData, float factor)
408 {
409 byte[] adjData;
410 int pos = 0;
411
412 if (!BitConverter.IsLittleEndian)
413 {
414 byte[] newData = new byte[7 * 4];
415 Buffer.BlockCopy(throttleData, 0, newData, 0, 7 * 4);
416
417 for (int i = 0; i < 7; i++)
418 Array.Reverse(newData, i * 4, 4);
419
420 adjData = newData;
421 }
422 else
423 {
424 adjData = throttleData;
425 }
426
427 // 0.125f converts from bits to bytes
428 float scale = 0.125f * factor;
429 int resend = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4;
430 int land = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4;
431 int wind = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4;
432 int cloud = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4;
433 int task = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4;
434 int texture = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4;
435 int asset = (int)(BitConverter.ToSingle(adjData, pos) * scale);
436
437
438
439 // Make sure none of the throttles are set below our packet MTU,
440 // otherwise a throttle could become permanently clogged
441
442/* now using floats
443 resend = Math.Max(resend, LLUDPServer.MTU);
444 land = Math.Max(land, LLUDPServer.MTU);
445 wind = Math.Max(wind, LLUDPServer.MTU);
446 cloud = Math.Max(cloud, LLUDPServer.MTU);
447 task = Math.Max(task, LLUDPServer.MTU);
448 texture = Math.Max(texture, LLUDPServer.MTU);
449 asset = Math.Max(asset, LLUDPServer.MTU);
450*/
451
452 // Since most textures are now delivered through http, make it possible
453 // to cannibalize some of the bw from the texture throttle to use for
454 // the task queue (e.g. object updates)
455 task = task + (int)(m_cannibalrate * texture);
456 texture = (int)((1 - m_cannibalrate) * texture);
457
458 int total = resend + land + wind + cloud + task + texture + asset;
459
460 float m_burst = total * m_burstTime;
461
462 if (ThrottleDebugLevel > 0)
463 {
464 m_log.DebugFormat(
465 "[LLUDPCLIENT]: {0} is setting throttles in {1} to Resend={2}, Land={3}, Wind={4}, Cloud={5}, Task={6}, Texture={7}, Asset={8}, TOTAL = {9}",
466 AgentID, m_udpServer.Scene.Name, resend, land, wind, cloud, task, texture, asset, total);
467 }
468
469 TokenBucket bucket;
470
471 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend];
472 bucket.RequestedDripRate = resend;
473 bucket.RequestedBurst = m_burst;
474
475 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land];
476 bucket.RequestedDripRate = land;
477 bucket.RequestedBurst = m_burst;
478
479 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind];
480 bucket.RequestedDripRate = wind;
481 bucket.RequestedBurst = m_burst;
482
483 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud];
484 bucket.RequestedDripRate = cloud;
485 bucket.RequestedBurst = m_burst;
486
487 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset];
488 bucket.RequestedDripRate = asset;
489 bucket.RequestedBurst = m_burst;
490
491 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task];
492 bucket.RequestedDripRate = task;
493 bucket.RequestedBurst = m_burst;
494
495 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture];
496 bucket.RequestedDripRate = texture;
497 bucket.RequestedBurst = m_burst;
498
499 // Reset the packed throttles cached data
500 m_packedThrottles = null;
501 }
502
503 public byte[] GetThrottlesPacked(float multiplier)
504 {
505 byte[] data = m_packedThrottles;
506
507 if (data == null)
508 {
509 float rate;
510
511 data = new byte[7 * 4];
512 int i = 0;
513
514 // multiply by 8 to convert bytes back to bits
515 multiplier *= 8;
516
517 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].RequestedDripRate * multiplier;
518 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
519
520 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Land].RequestedDripRate * multiplier;
521 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
522
523 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].RequestedDripRate * multiplier;
524 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
525
526 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].RequestedDripRate * multiplier;
527 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
528
529 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Task].RequestedDripRate * multiplier;
530 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
531
532 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].RequestedDripRate * multiplier;
533 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
534
535 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].RequestedDripRate * multiplier;
536 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
537
538 m_packedThrottles = data;
539 }
540
541 return data;
542 }
543
544 public int GetCatBytesCanSend(ThrottleOutPacketType cat, int timeMS)
545 {
546 int icat = (int)cat;
547 if (icat > 0 && icat < THROTTLE_CATEGORY_COUNT)
548 {
549 TokenBucket bucket = m_throttleCategories[icat];
550 return bucket.GetCatBytesCanSend(timeMS);
551 }
552 else
553 return 0;
554 }
555
556 /// <summary>
557 /// Queue an outgoing packet if appropriate.
558 /// </summary>
559 /// <param name="packet"></param>
560 /// <param name="forceQueue">Always queue the packet if at all possible.</param>
561 /// <returns>
562 /// true if the packet has been queued,
563 /// false if the packet has not been queued and should be sent immediately.
564 /// </returns>
565 public bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue)
566 {
567 return EnqueueOutgoing(packet, forceQueue, false);
568 }
569
570 public bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue, bool highPriority)
571 {
572 int category = (int)packet.Category;
573
574 if (category >= 0 && category < m_packetOutboxes.Length)
575 {
576 DoubleLocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category];
577
578 if (m_deliverPackets == false)
579 {
580 queue.Enqueue(packet, highPriority);
581 return true;
582 }
583
584 TokenBucket bucket = m_throttleCategories[category];
585
586 // Don't send this packet if queue is not empty
587 if (queue.Count > 0 || m_nextPackets[category] != null)
588 {
589 queue.Enqueue(packet, highPriority);
590 return true;
591 }
592
593 if (!forceQueue && bucket.CheckTokens(packet.Buffer.DataLength))
594 {
595 // enough tokens so it can be sent imediatly by caller
596 bucket.RemoveTokens(packet.Buffer.DataLength);
597 return false;
598 }
599 else
600 {
601 // Force queue specified or not enough tokens in the bucket, queue this packet
602 queue.Enqueue(packet, highPriority);
603 return true;
604 }
605 }
606 else
607 {
608 // We don't have a token bucket for this category, so it will not be queued
609 return false;
610 }
611
612 }
613
614 /// <summary>
615 /// Loops through all of the packet queues for this client and tries to send
616 /// an outgoing packet from each, obeying the throttling bucket limits
617 /// </summary>
618 ///
619 /// <remarks>
620 /// Packet queues are inspected in ascending numerical order starting from 0. Therefore, queues with a lower
621 /// ThrottleOutPacketType number will see their packet get sent first (e.g. if both Land and Wind queues have
622 /// packets, then the packet at the front of the Land queue will be sent before the packet at the front of the
623 /// wind queue).
624 ///
625 /// This function is only called from a synchronous loop in the
626 /// UDPServer so we don't need to bother making this thread safe
627 /// </remarks>
628 ///
629 /// <returns>True if any packets were sent, otherwise false</returns>
630 public bool DequeueOutgoing()
631 {
632// if (m_deliverPackets == false) return false;
633
634 OutgoingPacket packet = null;
635 DoubleLocklessQueue<OutgoingPacket> queue;
636 TokenBucket bucket;
637 bool packetSent = false;
638 ThrottleOutPacketTypeFlags emptyCategories = 0;
639
640 //string queueDebugOutput = String.Empty; // Serious debug business
641
642 for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
643 {
644 bucket = m_throttleCategories[i];
645 //queueDebugOutput += m_packetOutboxes[i].Count + " "; // Serious debug business
646
647 if (m_nextPackets[i] != null)
648 {
649 // This bucket was empty the last time we tried to send a packet,
650 // leaving a dequeued packet still waiting to be sent out. Try to
651 // send it again
652 OutgoingPacket nextPacket = m_nextPackets[i];
653 if (bucket.RemoveTokens(nextPacket.Buffer.DataLength))
654 {
655 // Send the packet
656 m_udpServer.SendPacketFinal(nextPacket);
657 m_nextPackets[i] = null;
658 packetSent = true;
659
660 if (m_packetOutboxes[i].Count < 5)
661 emptyCategories |= CategoryToFlag(i);
662 }
663 }
664 else
665 {
666 // No dequeued packet waiting to be sent, try to pull one off
667 // this queue
668 queue = m_packetOutboxes[i];
669 if (queue != null)
670 {
671 bool success = false;
672 try
673 {
674 success = queue.Dequeue(out packet);
675 }
676 catch
677 {
678 m_packetOutboxes[i] = new DoubleLocklessQueue<OutgoingPacket>();
679 }
680 if (success)
681 {
682 // A packet was pulled off the queue. See if we have
683 // enough tokens in the bucket to send it out
684 if (bucket.RemoveTokens(packet.Buffer.DataLength))
685 {
686 // Send the packet
687 m_udpServer.SendPacketFinal(packet);
688 packetSent = true;
689
690 if (queue.Count < 5)
691 emptyCategories |= CategoryToFlag(i);
692 }
693 else
694 {
695 // Save the dequeued packet for the next iteration
696 m_nextPackets[i] = packet;
697 }
698
699 }
700 else
701 {
702 // No packets in this queue. Fire the queue empty callback
703 // if it has not been called recently
704 emptyCategories |= CategoryToFlag(i);
705 }
706 }
707 else
708 {
709 m_packetOutboxes[i] = new DoubleLocklessQueue<OutgoingPacket>();
710 emptyCategories |= CategoryToFlag(i);
711 }
712 }
713 }
714
715 if (emptyCategories != 0)
716 BeginFireQueueEmpty(emptyCategories);
717
718 //m_log.Info("[LLUDPCLIENT]: Queues: " + queueDebugOutput); // Serious debug business
719 return packetSent;
720 }
721
722 /// <summary>
723 /// Called when an ACK packet is received and a round-trip time for a
724 /// packet is calculated. This is used to calculate the smoothed
725 /// round-trip time, round trip time variance, and finally the
726 /// retransmission timeout
727 /// </summary>
728 /// <param name="r">Round-trip time of a single packet and its
729 /// acknowledgement</param>
730 public void UpdateRoundTrip(float r)
731 {
732 const float ALPHA = 0.125f;
733 const float BETA = 0.25f;
734 const float K = 4.0f;
735
736 if (RTTVAR == 0.0f)
737 {
738 // First RTT measurement
739 SRTT = r;
740 RTTVAR = r * 0.5f;
741 }
742 else
743 {
744 // Subsequence RTT measurement
745 RTTVAR = (1.0f - BETA) * RTTVAR + BETA * Math.Abs(SRTT - r);
746 SRTT = (1.0f - ALPHA) * SRTT + ALPHA * r;
747 }
748
749 int rto = (int)(SRTT + Math.Max(m_udpServer.TickCountResolution, K * RTTVAR));
750
751 // Clamp the retransmission timeout to manageable values
752 rto = Utils.Clamp(rto, m_defaultRTO, m_maxRTO);
753
754 RTO = rto;
755
756 //if (RTO != rto)
757 // m_log.Debug("[LLUDPCLIENT]: Setting RTO to " + RTO + "ms from " + rto + "ms with an RTTVAR of " +
758 //RTTVAR + " based on new RTT of " + r + "ms");
759 }
760
761 /// <summary>
762 /// Exponential backoff of the retransmission timeout, per section 5.5
763 /// of RFC 2988
764 /// </summary>
765 public void BackoffRTO()
766 {
767 // Reset SRTT and RTTVAR, we assume they are bogus since things
768 // didn't work out and we're backing off the timeout
769 SRTT = 0.0f;
770 RTTVAR = 0.0f;
771
772 // Double the retransmission timeout
773 RTO = Math.Min(RTO * 2, m_maxRTO);
774 }
775
776 const double MIN_CALLBACK_MS = 20.0;
777 private bool m_isQueueEmptyRunning;
778
779 /// <summary>
780 /// Does an early check to see if this queue empty callback is already
781 /// running, then asynchronously firing the event
782 /// </summary>
783 /// <param name="categories">Throttle categories to fire the callback for</param>
784 private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories)
785 {
786 if (!m_isQueueEmptyRunning)
787 {
788 if (!HasUpdates(categories))
789 return;
790
791 double start = Util.GetTimeStampMS();
792 if (start < m_nextOnQueueEmpty)
793 return;
794
795 m_isQueueEmptyRunning = true;
796 m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
797
798 // Asynchronously run the callback
799 if (m_udpServer.OqrEngine.IsRunning)
800 m_udpServer.OqrEngine.QueueJob(AgentID.ToString(), () => FireQueueEmpty(categories));
801 else
802 Util.FireAndForget(FireQueueEmpty, categories, "LLUDPClient.BeginFireQueueEmpty");
803 }
804 }
805
806
807
808 /// <summary>
809 /// Fires the OnQueueEmpty callback and sets the minimum time that it
810 /// can be called again
811 /// </summary>
812 /// <param name="o">Throttle categories to fire the callback for,
813 /// stored as an object to match the WaitCallback delegate
814 /// signature</param>
815 public void FireQueueEmpty(object o)
816 {
817 ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o;
818 QueueEmpty callback = OnQueueEmpty;
819
820 if (callback != null)
821 {
822 // if (m_udpServer.IsRunningOutbound)
823 // {
824 try { callback(categories); }
825 catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); }
826 // }
827 }
828
829 m_isQueueEmptyRunning = false;
830 }
831
832 internal void ForceThrottleSetting(int throttle, int setting)
833 {
834 if (throttle > 0 && throttle < THROTTLE_CATEGORY_COUNT)
835 m_throttleCategories[throttle].RequestedDripRate = Math.Max(setting, LLUDPServer.MTU);
836 }
837
838 internal int GetThrottleSetting(int throttle)
839 {
840 if (throttle > 0 && throttle < THROTTLE_CATEGORY_COUNT)
841 return (int)m_throttleCategories[throttle].RequestedDripRate;
842 else
843 return 0;
844 }
845
846 /// <summary>
847 /// Converts a <seealso cref="ThrottleOutPacketType"/> integer to a
848 /// flag value
849 /// </summary>
850 /// <param name="i">Throttle category to convert</param>
851 /// <returns>Flag representation of the throttle category</returns>
852 private static ThrottleOutPacketTypeFlags CategoryToFlag(int i)
853 {
854 ThrottleOutPacketType category = (ThrottleOutPacketType)i;
855
856 /*
857 * Land = 1,
858 /// <summary>Wind data</summary>
859 Wind = 2,
860 /// <summary>Cloud data</summary>
861 Cloud = 3,
862 /// <summary>Any packets that do not fit into the other throttles</summary>
863 Task = 4,
864 /// <summary>Texture assets</summary>
865 Texture = 5,
866 /// <summary>Non-texture assets</summary>
867 Asset = 6,
868 */
869
870 switch (category)
871 {
872 case ThrottleOutPacketType.Land:
873 return ThrottleOutPacketTypeFlags.Land;
874 case ThrottleOutPacketType.Wind:
875 return ThrottleOutPacketTypeFlags.Wind;
876 case ThrottleOutPacketType.Cloud:
877 return ThrottleOutPacketTypeFlags.Cloud;
878 case ThrottleOutPacketType.Task:
879 return ThrottleOutPacketTypeFlags.Task;
880 case ThrottleOutPacketType.Texture:
881 return ThrottleOutPacketTypeFlags.Texture;
882 case ThrottleOutPacketType.Asset:
883 return ThrottleOutPacketTypeFlags.Asset;
884 default:
885 return 0;
886 }
887 }
888 }
889
890 public class DoubleLocklessQueue<T> : OpenSim.Framework.LocklessQueue<T>
891 {
892 OpenSim.Framework.LocklessQueue<T> highQueue = new OpenSim.Framework.LocklessQueue<T>();
893
894 public override int Count
895 {
896 get
897 {
898 return base.Count + highQueue.Count;
899 }
900 }
901
902 public override bool Dequeue(out T item)
903 {
904 if (highQueue.Dequeue(out item))
905 return true;
906
907 return base.Dequeue(out item);
908 }
909
910 public void Enqueue(T item, bool highPriority)
911 {
912 if (highPriority)
913 highQueue.Enqueue(item);
914 else
915 Enqueue(item);
916 }
917 }
918}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
new file mode 100644
index 0000000..69239b1
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -0,0 +1,2246 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Diagnostics;
31using System.IO;
32using System.Net;
33using System.Net.Sockets;
34using System.Reflection;
35using System.Text;
36using System.Text.RegularExpressions;
37using System.Threading;
38using log4net;
39using Nini.Config;
40using OpenMetaverse.Packets;
41using OpenSim.Framework;
42using OpenSim.Framework.Console;
43using OpenSim.Framework.Monitoring;
44using OpenSim.Region.Framework.Scenes;
45using OpenSim.Region.Framework.Interfaces;
46using OpenMetaverse;
47using Mono.Addins;
48using TokenBucket = OpenSim.Region.ClientStack.LindenUDP.TokenBucket;
49
50namespace OpenSim.Region.ClientStack.LindenUDP
51{
52 /// <summary>
53 /// A shim around LLUDPServer that implements the IClientNetworkServer interface
54 /// </summary>
55 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "LLUDPServerShim")]
56 public class LLUDPServerShim : INonSharedRegionModule
57 {
58 protected IConfigSource m_Config;
59 protected LLUDPServer m_udpServer;
60
61 #region INonSharedRegionModule
62 public virtual string Name
63 {
64 get { return "LLUDPServerShim"; }
65 }
66
67 public virtual Type ReplaceableInterface
68 {
69 get { return null; }
70 }
71
72 public virtual void Initialise(IConfigSource source)
73 {
74 m_Config = source;
75 }
76
77 public virtual void Close()
78 {
79 }
80
81 public virtual void AddRegion(Scene scene)
82 {
83 uint port = (uint)scene.RegionInfo.InternalEndPoint.Port;
84
85 IPAddress listenIP = scene.RegionInfo.InternalEndPoint.Address;
86 Initialise(listenIP, ref port, scene.RegionInfo.ProxyOffset, m_Config, scene.AuthenticateHandler);
87 scene.RegionInfo.InternalEndPoint.Port = (int)port;
88
89 AddScene(scene);
90 }
91
92 public virtual void RemoveRegion(Scene scene)
93 {
94 Stop();
95 }
96
97 public virtual void RegionLoaded(Scene scene)
98 {
99 Start();
100 }
101 #endregion
102
103 public virtual void Initialise(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, IConfigSource configSource, AgentCircuitManager circuitManager)
104 {
105 m_udpServer = new LLUDPServer(listenIP, ref port, proxyPortOffsetParm, configSource, circuitManager);
106 }
107
108 public virtual void AddScene(IScene scene)
109 {
110 m_udpServer.AddScene(scene);
111
112 StatsManager.RegisterStat(
113 new Stat(
114 "ClientLogoutsDueToNoReceives",
115 "Number of times a client has been logged out because no packets were received before the timeout.",
116 "",
117 "",
118 "clientstack",
119 scene.Name,
120 StatType.Pull,
121 MeasuresOfInterest.None,
122 stat => stat.Value = m_udpServer.ClientLogoutsDueToNoReceives,
123 StatVerbosity.Debug));
124
125 StatsManager.RegisterStat(
126 new Stat(
127 "IncomingUDPReceivesCount",
128 "Number of UDP receives performed",
129 "",
130 "",
131 "clientstack",
132 scene.Name,
133 StatType.Pull,
134 MeasuresOfInterest.AverageChangeOverTime,
135 stat => stat.Value = m_udpServer.UdpReceives,
136 StatVerbosity.Debug));
137
138 StatsManager.RegisterStat(
139 new Stat(
140 "IncomingPacketsProcessedCount",
141 "Number of inbound LL protocol packets processed",
142 "",
143 "",
144 "clientstack",
145 scene.Name,
146 StatType.Pull,
147 MeasuresOfInterest.AverageChangeOverTime,
148 stat => stat.Value = m_udpServer.IncomingPacketsProcessed,
149 StatVerbosity.Debug));
150
151 StatsManager.RegisterStat(
152 new Stat(
153 "IncomingPacketsMalformedCount",
154 "Number of inbound UDP packets that could not be recognized as LL protocol packets.",
155 "",
156 "",
157 "clientstack",
158 scene.Name,
159 StatType.Pull,
160 MeasuresOfInterest.AverageChangeOverTime,
161 stat => stat.Value = m_udpServer.IncomingMalformedPacketCount,
162 StatVerbosity.Info));
163
164 StatsManager.RegisterStat(
165 new Stat(
166 "IncomingPacketsOrphanedCount",
167 "Number of inbound packets that were not initial connections packets and could not be associated with a viewer.",
168 "",
169 "",
170 "clientstack",
171 scene.Name,
172 StatType.Pull,
173 MeasuresOfInterest.AverageChangeOverTime,
174 stat => stat.Value = m_udpServer.IncomingOrphanedPacketCount,
175 StatVerbosity.Info));
176
177 StatsManager.RegisterStat(
178 new Stat(
179 "IncomingPacketsResentCount",
180 "Number of inbound packets that clients indicate are resends.",
181 "",
182 "",
183 "clientstack",
184 scene.Name,
185 StatType.Pull,
186 MeasuresOfInterest.AverageChangeOverTime,
187 stat => stat.Value = m_udpServer.IncomingPacketsResentCount,
188 StatVerbosity.Debug));
189
190 StatsManager.RegisterStat(
191 new Stat(
192 "OutgoingUDPSendsCount",
193 "Number of UDP sends performed",
194 "",
195 "",
196 "clientstack",
197 scene.Name,
198 StatType.Pull,
199 MeasuresOfInterest.AverageChangeOverTime,
200 stat => stat.Value = m_udpServer.UdpSends,
201 StatVerbosity.Debug));
202
203 StatsManager.RegisterStat(
204 new Stat(
205 "OutgoingPacketsResentCount",
206 "Number of packets resent because a client did not acknowledge receipt",
207 "",
208 "",
209 "clientstack",
210 scene.Name,
211 StatType.Pull,
212 MeasuresOfInterest.AverageChangeOverTime,
213 stat => stat.Value = m_udpServer.PacketsResentCount,
214 StatVerbosity.Debug));
215
216 StatsManager.RegisterStat(
217 new Stat(
218 "AverageUDPProcessTime",
219 "Average number of milliseconds taken to process each incoming UDP packet in a sample.",
220 "This is for initial receive processing which is separate from the later client LL packet processing stage.",
221 "ms",
222 "clientstack",
223 scene.Name,
224 StatType.Pull,
225 MeasuresOfInterest.None,
226 stat => stat.Value = m_udpServer.AverageReceiveTicksForLastSamplePeriod,
227// stat =>
228// stat.Value = Math.Round(m_udpServer.AverageReceiveTicksForLastSamplePeriod, 7),
229 StatVerbosity.Debug));
230 }
231
232 public virtual bool HandlesRegion(Location x)
233 {
234 return m_udpServer.HandlesRegion(x);
235 }
236
237 public virtual void Start()
238 {
239 m_udpServer.Start();
240 }
241
242 public virtual void Stop()
243 {
244 m_udpServer.Stop();
245 }
246
247 }
248
249 /// <summary>
250 /// The LLUDP server for a region. This handles incoming and outgoing
251 /// packets for all UDP connections to the region
252 /// </summary>
253 public class LLUDPServer : OpenSimUDPBase
254 {
255 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
256
257 /// <summary>Maximum transmission unit, or UDP packet size, for the LLUDP protocol</summary>
258 public const int MTU = 1400;
259
260 /// <summary>Number of forced client logouts due to no receipt of packets before timeout.</summary>
261 public int ClientLogoutsDueToNoReceives { get; protected set; }
262
263 /// <summary>
264 /// Default packet debug level given to new clients
265 /// </summary>
266 public int DefaultClientPacketDebugLevel { get; set; }
267
268 /// <summary>
269 /// If set then all inbound agent updates are discarded. For debugging purposes.
270 /// discard agent update.
271 /// </summary>
272 public bool DiscardInboundAgentUpdates { get; set; }
273
274 /// <summary>The measured resolution of Environment.TickCount</summary>
275 public readonly float TickCountResolution;
276
277 /// <summary>Number of prim updates to put on the queue each time the
278 /// OnQueueEmpty event is triggered for updates</summary>
279 public readonly int PrimUpdatesPerCallback;
280
281 /// <summary>Number of texture packets to put on the queue each time the
282 /// OnQueueEmpty event is triggered for textures</summary>
283 public readonly int TextureSendLimit;
284
285 /// <summary>Handlers for incoming packets</summary>
286 //PacketEventDictionary packetEvents = new PacketEventDictionary();
287 /// <summary>Incoming packets that are awaiting handling</summary>
288 //protected OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>();
289
290 protected OpenSim.Framework.BlockingQueue<IncomingPacket> packetInbox = new OpenSim.Framework.BlockingQueue<IncomingPacket>();
291
292 /// <summary>Bandwidth throttle for this UDP server</summary>
293 public TokenBucket Throttle { get; protected set; }
294
295 /// <summary>Per client throttle rates enforced by this server</summary>
296 /// <remarks>
297 /// If the total rate is non-zero, then this is the maximum total throttle setting that any client can ever have.
298 /// The other rates (resend, asset, etc.) are the defaults for a new client and can be changed (and usually
299 /// do get changed immediately). They do not need to sum to the total.
300 /// </remarks>
301 public ThrottleRates ThrottleRates { get; protected set; }
302
303 /// <summary>Manages authentication for agent circuits</summary>
304 protected AgentCircuitManager m_circuitManager;
305
306 /// <summary>Reference to the scene this UDP server is attached to</summary>
307 public Scene Scene { get; protected set; }
308
309 /// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary>
310 protected Location m_location;
311
312 /// <summary>The size of the receive buffer for the UDP socket. This value
313 /// is passed up to the operating system and used in the system networking
314 /// stack. Use zero to leave this value as the default</summary>
315 protected int m_recvBufferSize;
316
317 /// <summary>Tracks whether or not a packet was sent each round so we know
318 /// whether or not to sleep</summary>
319 protected bool m_packetSent;
320
321 /// <summary>Environment.TickCount of the last time that packet stats were reported to the scene</summary>
322 protected int m_elapsedMSSinceLastStatReport = 0;
323
324 /// <summary>Environment.TickCount of the last time the outgoing packet handler executed</summary>
325 protected double m_tickLastOutgoingPacketHandler;
326
327 /// <summary>Keeps track of the number of elapsed milliseconds since the last time the outgoing packet handler looped</summary>
328 protected double m_elapsedMSOutgoingPacketHandler;
329
330 /// <summary>Keeps track of the number of 100 millisecond periods elapsed in the outgoing packet handler executed</summary>
331 protected int m_elapsed100MSOutgoingPacketHandler;
332
333 /// <summary>Keeps track of the number of 500 millisecond periods elapsed in the outgoing packet handler executed</summary>
334 protected int m_elapsed500MSOutgoingPacketHandler;
335
336 /// <summary>Flag to signal when clients should check for resends</summary>
337 protected bool m_resendUnacked;
338
339 /// <summary>Flag to signal when clients should send ACKs</summary>
340 protected bool m_sendAcks;
341
342 /// <summary>Flag to signal when clients should send pings</summary>
343 protected bool m_sendPing;
344
345 protected int m_animationSequenceNumber;
346
347 public int NextAnimationSequenceNumber
348 {
349 get
350 {
351 m_animationSequenceNumber++;
352 if (m_animationSequenceNumber > 2147482624)
353 m_animationSequenceNumber = 1;
354 return m_animationSequenceNumber;
355 }
356 }
357
358 protected ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>();
359
360 protected Pool<IncomingPacket> m_incomingPacketPool;
361
362 /// <summary>
363 /// Stat for number of packets in the main pool awaiting use.
364 /// </summary>
365 protected Stat m_poolCountStat;
366
367 /// <summary>
368 /// Stat for number of packets in the inbound packet pool awaiting use.
369 /// </summary>
370 protected Stat m_incomingPacketPoolStat;
371
372 protected int m_defaultRTO = 0;
373 protected int m_maxRTO = 0;
374 protected int m_ackTimeout = 0;
375 protected int m_pausedAckTimeout = 0;
376 protected bool m_disableFacelights = false;
377
378 public Socket Server { get { return null; } }
379
380 /// <summary>
381 /// Record how many packets have been resent
382 /// </summary>
383 internal int PacketsResentCount { get; set; }
384
385 /// <summary>
386 /// Record how many packets have been sent
387 /// </summary>
388 internal int PacketsSentCount { get; set; }
389
390 /// <summary>
391 /// Record how many incoming packets are indicated as resends by clients.
392 /// </summary>
393 internal int IncomingPacketsResentCount { get; set; }
394
395 /// <summary>
396 /// Record how many inbound packets could not be recognized as LLUDP packets.
397 /// </summary>
398 public int IncomingMalformedPacketCount { get; protected set; }
399
400 /// <summary>
401 /// Record how many inbound packets could not be associated with a simulator circuit.
402 /// </summary>
403 public int IncomingOrphanedPacketCount { get; protected set; }
404
405 /// <summary>
406 /// Record current outgoing client for monitoring purposes.
407 /// </summary>
408 protected IClientAPI m_currentOutgoingClient;
409
410 /// <summary>
411 /// Recording current incoming client for monitoring purposes.
412 /// </summary>
413 protected IClientAPI m_currentIncomingClient;
414
415 /// <summary>
416 /// Queue some low priority but potentially high volume async requests so that they don't overwhelm available
417 /// threadpool threads.
418 /// </summary>
419// public JobEngine IpahEngine { get; protected set; }
420
421 /// <summary>
422 /// Run queue empty processing within a single persistent thread.
423 /// </summary>
424 /// <remarks>
425 /// This is the alternative to having every
426 /// connection schedule its own job in the threadpool which causes performance problems when there are many
427 /// connections.
428 /// </remarks>
429 public JobEngine OqrEngine { get; protected set; }
430
431 public LLUDPServer(
432 IPAddress listenIP, ref uint port, int proxyPortOffsetParm,
433 IConfigSource configSource, AgentCircuitManager circuitManager)
434 : base(listenIP, (int)port)
435 {
436 #region Environment.TickCount Measurement
437
438 // Update the port with the one we actually got
439 port = (uint)Port;
440
441 // Measure the resolution of Environment.TickCount
442 TickCountResolution = 0f;
443 for (int i = 0; i < 10; i++)
444 {
445 int start = Environment.TickCount;
446 int now = start;
447 while (now == start)
448 now = Environment.TickCount;
449 TickCountResolution += (float)(now - start);
450 }
451 m_log.Info("[LLUDPSERVER]: Average Environment.TickCount resolution: " + TickCountResolution * 0.1f + "ms");
452
453 TickCountResolution = 0f;
454 for (int i = 0; i < 100; i++)
455 {
456 double start = Util.GetTimeStampMS();
457 double now = start;
458 while (now == start)
459 now = Util.GetTimeStampMS();
460 TickCountResolution += (float)((now - start));
461 }
462
463 TickCountResolution = (float)Math.Round(TickCountResolution * 0.01f,6,MidpointRounding.AwayFromZero);
464 m_log.Info("[LLUDPSERVER]: Average Util.GetTimeStampMS resolution: " + TickCountResolution + "ms");
465
466 #endregion Environment.TickCount Measurement
467
468 m_circuitManager = circuitManager;
469 int sceneThrottleBps = 0;
470 bool usePools = false;
471
472 IConfig config = configSource.Configs["ClientStack.LindenUDP"];
473 if (config != null)
474 {
475 m_recvBufferSize = config.GetInt("client_socket_rcvbuf_size", 0);
476 sceneThrottleBps = config.GetInt("scene_throttle_max_bps", 0);
477
478 PrimUpdatesPerCallback = config.GetInt("PrimUpdatesPerCallback", 100);
479 TextureSendLimit = config.GetInt("TextureSendLimit", 20);
480
481 m_defaultRTO = config.GetInt("DefaultRTO", 0);
482 m_maxRTO = config.GetInt("MaxRTO", 0);
483 m_disableFacelights = config.GetBoolean("DisableFacelights", false);
484 m_ackTimeout = 1000 * config.GetInt("AckTimeout", 60);
485 m_pausedAckTimeout = 1000 * config.GetInt("PausedAckTimeout", 300);
486 }
487 else
488 {
489 PrimUpdatesPerCallback = 100;
490 TextureSendLimit = 20;
491 m_ackTimeout = 1000 * 60; // 1 minute
492 m_pausedAckTimeout = 1000 * 300; // 5 minutes
493 }
494
495 // FIXME: This actually only needs to be done once since the PacketPool is shared across all servers.
496 // However, there is no harm in temporarily doing it multiple times.
497 IConfig packetConfig = configSource.Configs["PacketPool"];
498 if (packetConfig != null)
499 {
500 PacketPool.Instance.RecyclePackets = packetConfig.GetBoolean("RecyclePackets", true);
501 PacketPool.Instance.RecycleDataBlocks = packetConfig.GetBoolean("RecycleDataBlocks", true);
502 usePools = packetConfig.GetBoolean("RecycleBaseUDPPackets", usePools);
503 }
504
505 #region BinaryStats
506 config = configSource.Configs["Statistics.Binary"];
507 m_shouldCollectStats = false;
508 if (config != null)
509 {
510 m_shouldCollectStats = config.GetBoolean("Enabled", false);
511 binStatsMaxFilesize = TimeSpan.FromSeconds(config.GetInt("packet_headers_period_seconds", 300));
512 binStatsDir = config.GetString("stats_dir", ".");
513 m_aggregatedBWStats = config.GetBoolean("aggregatedBWStats", false);
514 }
515 #endregion BinaryStats
516
517 Throttle = new TokenBucket(null, sceneThrottleBps, sceneThrottleBps * 10e-3f);
518 ThrottleRates = new ThrottleRates(configSource);
519
520 Random rnd = new Random(Util.EnvironmentTickCount());
521 m_animationSequenceNumber = rnd.Next(11474826);
522
523// if (usePools)
524// EnablePools();
525 base.DisablePools();
526 }
527
528 public void Start()
529 {
530 StartInbound();
531 StartOutbound();
532// IpahEngine.Start();
533 OqrEngine.Start();
534
535 m_elapsedMSSinceLastStatReport = Environment.TickCount;
536 }
537
538 public void StartInbound()
539 {
540 m_log.InfoFormat(
541 "[LLUDPSERVER]: Starting inbound packet processing for the LLUDP server");
542
543 base.StartInbound(m_recvBufferSize);
544
545 // This thread will process the packets received that are placed on the packetInbox
546 WorkManager.StartThread(
547 IncomingPacketHandler,
548 string.Format("Incoming Packets ({0})", Scene.Name),
549 ThreadPriority.Normal,
550 false,
551 true,
552 GetWatchdogIncomingAlarmData,
553 Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS);
554 }
555
556 public override void StartOutbound()
557 {
558 m_log.Info("[LLUDPSERVER]: Starting outbound packet processing for the LLUDP server");
559
560 base.StartOutbound();
561
562 WorkManager.StartThread(
563 OutgoingPacketHandler,
564 string.Format("Outgoing Packets ({0})", Scene.Name),
565 ThreadPriority.Normal,
566 false,
567 true,
568 GetWatchdogOutgoingAlarmData,
569 Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS);
570 }
571
572 public void Stop()
573 {
574 m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + Scene.Name);
575 base.StopOutbound();
576 base.StopInbound();
577// IpahEngine.Stop();
578 OqrEngine.Stop();
579 }
580
581 public override bool EnablePools()
582 {
583 if (!UsePools)
584 {
585 base.EnablePools();
586
587 m_incomingPacketPool = new Pool<IncomingPacket>(() => new IncomingPacket(), 500);
588
589 return true;
590 }
591
592 return false;
593 }
594
595 public override bool DisablePools()
596 {
597 if (UsePools)
598 {
599 base.DisablePools();
600
601 StatsManager.DeregisterStat(m_incomingPacketPoolStat);
602
603 // We won't null out the pool to avoid a race condition with code that may be in the middle of using it.
604
605 return true;
606 }
607
608 return false;
609 }
610
611 /// <summary>
612 /// This is a seperate method so that it can be called once we have an m_scene to distinguish different scene
613 /// stats.
614 /// </summary>
615 protected internal void EnablePoolStats()
616 {
617 m_poolCountStat
618 = new Stat(
619 "UDPPacketBufferPoolCount",
620 "Objects within the UDPPacketBuffer pool",
621 "The number of objects currently stored within the UDPPacketBuffer pool",
622 "",
623 "clientstack",
624 Scene.Name,
625 StatType.Pull,
626 stat => stat.Value = Pool.Count,
627 StatVerbosity.Debug);
628
629 StatsManager.RegisterStat(m_poolCountStat);
630
631 m_incomingPacketPoolStat
632 = new Stat(
633 "IncomingPacketPoolCount",
634 "Objects within incoming packet pool",
635 "The number of objects currently stored within the incoming packet pool",
636 "",
637 "clientstack",
638 Scene.Name,
639 StatType.Pull,
640 stat => stat.Value = m_incomingPacketPool.Count,
641 StatVerbosity.Debug);
642
643 StatsManager.RegisterStat(m_incomingPacketPoolStat);
644 }
645
646 /// <summary>
647 /// Disables pool stats.
648 /// </summary>
649 protected internal void DisablePoolStats()
650 {
651 StatsManager.DeregisterStat(m_poolCountStat);
652 m_poolCountStat = null;
653
654 StatsManager.DeregisterStat(m_incomingPacketPoolStat);
655 m_incomingPacketPoolStat = null;
656 }
657
658 /// <summary>
659 /// If the outgoing UDP thread times out, then return client that was being processed to help with debugging.
660 /// </summary>
661 /// <returns></returns>
662 protected string GetWatchdogIncomingAlarmData()
663 {
664 return string.Format(
665 "Client is {0}",
666 m_currentIncomingClient != null ? m_currentIncomingClient.Name : "none");
667 }
668
669 /// <summary>
670 /// If the outgoing UDP thread times out, then return client that was being processed to help with debugging.
671 /// </summary>
672 /// <returns></returns>
673 protected string GetWatchdogOutgoingAlarmData()
674 {
675 return string.Format(
676 "Client is {0}",
677 m_currentOutgoingClient != null ? m_currentOutgoingClient.Name : "none");
678 }
679
680 public void AddScene(IScene scene)
681 {
682 if (Scene != null)
683 {
684 m_log.Error("[LLUDPSERVER]: AddScene() called on an LLUDPServer that already has a scene");
685 return;
686 }
687
688 if (!(scene is Scene))
689 {
690 m_log.Error("[LLUDPSERVER]: AddScene() called with an unrecognized scene type " + scene.GetType());
691 return;
692 }
693
694 Scene = (Scene)scene;
695 m_location = new Location(Scene.RegionInfo.RegionHandle);
696/*
697 IpahEngine
698 = new JobEngine(
699 string.Format("Incoming Packet Async Handling Engine ({0})", Scene.Name),
700 "INCOMING PACKET ASYNC HANDLING ENGINE");
701*/
702 OqrEngine
703 = new JobEngine(
704 string.Format("Outgoing Queue Refill Engine ({0})", Scene.Name),
705 "OUTGOING QUEUE REFILL ENGINE");
706
707 StatsManager.RegisterStat(
708 new Stat(
709 "InboxPacketsCount",
710 "Number of LL protocol packets waiting for the second stage of processing after initial receive.",
711 "Number of LL protocol packets waiting for the second stage of processing after initial receive.",
712 "",
713 "clientstack",
714 scene.Name,
715 StatType.Pull,
716 MeasuresOfInterest.AverageChangeOverTime,
717 stat => stat.Value = packetInbox.Count(),
718 StatVerbosity.Debug));
719
720 // XXX: These stats are also pool stats but we register them separately since they are currently not
721 // turned on and off by EnablePools()/DisablePools()
722 StatsManager.RegisterStat(
723 new PercentageStat(
724 "PacketsReused",
725 "Packets reused",
726 "Number of packets reused out of all requests to the packet pool",
727 "clientstack",
728 Scene.Name,
729 StatType.Pull,
730 stat =>
731 { PercentageStat pstat = (PercentageStat)stat;
732 pstat.Consequent = PacketPool.Instance.PacketsRequested;
733 pstat.Antecedent = PacketPool.Instance.PacketsReused; },
734 StatVerbosity.Debug));
735
736 StatsManager.RegisterStat(
737 new PercentageStat(
738 "PacketDataBlocksReused",
739 "Packet data blocks reused",
740 "Number of data blocks reused out of all requests to the packet pool",
741 "clientstack",
742 Scene.Name,
743 StatType.Pull,
744 stat =>
745 { PercentageStat pstat = (PercentageStat)stat;
746 pstat.Consequent = PacketPool.Instance.BlocksRequested;
747 pstat.Antecedent = PacketPool.Instance.BlocksReused; },
748 StatVerbosity.Debug));
749
750 StatsManager.RegisterStat(
751 new Stat(
752 "PacketsPoolCount",
753 "Objects within the packet pool",
754 "The number of objects currently stored within the packet pool",
755 "",
756 "clientstack",
757 Scene.Name,
758 StatType.Pull,
759 stat => stat.Value = PacketPool.Instance.PacketsPooled,
760 StatVerbosity.Debug));
761
762 StatsManager.RegisterStat(
763 new Stat(
764 "PacketDataBlocksPoolCount",
765 "Objects within the packet data block pool",
766 "The number of objects currently stored within the packet data block pool",
767 "",
768 "clientstack",
769 Scene.Name,
770 StatType.Pull,
771 stat => stat.Value = PacketPool.Instance.BlocksPooled,
772 StatVerbosity.Debug));
773
774 StatsManager.RegisterStat(
775 new Stat(
776 "OutgoingPacketsQueuedCount",
777 "Packets queued for outgoing send",
778 "Number of queued outgoing packets across all connections",
779 "",
780 "clientstack",
781 Scene.Name,
782 StatType.Pull,
783 MeasuresOfInterest.AverageChangeOverTime,
784 stat => stat.Value = GetTotalQueuedOutgoingPackets(),
785 StatVerbosity.Info));
786/*
787 StatsManager.RegisterStat(
788 new Stat(
789 "IncomingPacketAsyncRequestsWaiting",
790 "Number of incoming packets waiting for async processing in engine.",
791 "",
792 "",
793 "clientstack",
794 Scene.Name,
795 StatType.Pull,
796 MeasuresOfInterest.None,
797 stat => stat.Value = IpahEngine.JobsWaiting,
798 StatVerbosity.Debug));
799*/
800 StatsManager.RegisterStat(
801 new Stat(
802 "OQRERequestsWaiting",
803 "Number of outgong queue refill requests waiting for processing.",
804 "",
805 "",
806 "clientstack",
807 Scene.Name,
808 StatType.Pull,
809 MeasuresOfInterest.None,
810 stat => stat.Value = OqrEngine.JobsWaiting,
811 StatVerbosity.Debug));
812
813 // We delay enabling pool stats to AddScene() instead of Initialize() so that we can distinguish pool stats by
814 // scene name
815 if (UsePools)
816 EnablePoolStats();
817
818
819 LLUDPServerCommands commands = new LLUDPServerCommands(MainConsole.Instance, this);
820 commands.Register();
821
822 }
823
824 public bool HandlesRegion(Location x)
825 {
826 return x == m_location;
827 }
828
829 public int GetTotalQueuedOutgoingPackets()
830 {
831 int total = 0;
832
833 foreach (ScenePresence sp in Scene.GetScenePresences())
834 {
835 // XXX: Need a better way to determine which IClientAPIs have UDPClients (NPCs do not, for instance).
836 if (sp.ControllingClient is LLClientView)
837 {
838 LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
839 total += udpClient.GetTotalPacketsQueuedCount();
840 }
841 }
842
843 return total;
844 }
845
846// public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting)
847// {
848// // CoarseLocationUpdate and AvatarGroupsReply packets cannot be split in an automated way
849// if ((packet.Type == PacketType.CoarseLocationUpdate || packet.Type == PacketType.AvatarGroupsReply) && allowSplitting)
850// allowSplitting = false;
851//
852// if (allowSplitting && packet.HasVariableBlocks)
853// {
854// byte[][] datas = packet.ToBytesMultiple();
855// int packetCount = datas.Length;
856//
857// if (packetCount < 1)
858// m_log.Error("[LLUDPSERVER]: Failed to split " + packet.Type + " with estimated length " + packet.Length);
859//
860// for (int i = 0; i < packetCount; i++)
861// {
862// byte[] data = datas[i];
863// m_scene.ForEachClient(
864// delegate(IClientAPI client)
865// {
866// if (client is LLClientView)
867// SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null);
868// }
869// );
870// }
871// }
872// else
873// {
874// byte[] data = packet.ToBytes();
875// m_scene.ForEachClient(
876// delegate(IClientAPI client)
877// {
878// if (client is LLClientView)
879// SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null);
880// }
881// );
882// }
883// }
884
885 /// <summary>
886 /// Start the process of sending a packet to the client.
887 /// </summary>
888 /// <param name="udpClient"></param>
889 /// <param name="packet"></param>
890 /// <param name="category"></param>
891 /// <param name="allowSplitting"></param>
892 /// <param name="method">
893 /// The method to call if the packet is not acked by the client. If null, then a standard
894 /// resend of the packet is done.
895 /// </param>
896 public virtual void SendPacket(
897 LLUDPClient udpClient, Packet packet, ThrottleOutPacketType category, bool allowSplitting, UnackedPacketMethod method)
898 {
899 // CoarseLocationUpdate packets cannot be split in an automated way
900 if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting)
901 allowSplitting = false;
902
903 bool packetQueued = false;
904
905 if (allowSplitting && packet.HasVariableBlocks)
906 {
907 byte[][] datas = packet.ToBytesMultiple();
908 int packetCount = datas.Length;
909
910 if (packetCount < 1)
911 m_log.Error("[LLUDPSERVER]: Failed to split " + packet.Type + " with estimated length " + packet.Length);
912
913 for (int i = 0; i < packetCount; i++)
914 {
915 byte[] data = datas[i];
916 if (!SendPacketData(udpClient, data, packet.Type, category, method))
917 packetQueued = true;
918 }
919 }
920 else
921 {
922 byte[] data = packet.ToBytes();
923 if (!SendPacketData(udpClient, data, packet.Type, category, method))
924 packetQueued = true;
925 }
926
927 PacketPool.Instance.ReturnPacket(packet);
928 }
929
930 /// <summary>
931 /// Start the process of sending a packet to the client.
932 /// </summary>
933 /// <param name="udpClient"></param>
934 /// <param name="data"></param>
935 /// <param name="type"></param>
936 /// <param name="category"></param>
937 /// <param name="method">
938 /// The method to call if the packet is not acked by the client. If null, then a standard
939 /// resend of the packet is done.
940 /// </param>
941 /// <returns>true if the data was sent immediately, false if it was queued for sending</returns>
942 public bool SendPacketData(
943 LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category, UnackedPacketMethod method)
944 {
945 int dataLength = data.Length;
946 bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0;
947 bool doCopy = true;
948
949 // Frequency analysis of outgoing packet sizes shows a large clump of packets at each end of the spectrum.
950 // The vast majority of packets are less than 200 bytes, although due to asset transfers and packet splitting
951 // there are a decent number of packets in the 1000-1140 byte range. We allocate one of two sizes of data here
952 // to accomodate for both common scenarios and provide ample room for ACK appending in both
953 int bufferSize = (dataLength > 180) ? LLUDPServer.MTU : 200;
954
955 UDPPacketBuffer buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize);
956
957 // Zerocode if needed
958 if (doZerocode)
959 {
960 try
961 {
962 dataLength = Helpers.ZeroEncode(data, dataLength, buffer.Data);
963 doCopy = false;
964 }
965 catch (IndexOutOfRangeException)
966 {
967 // The packet grew larger than the bufferSize while zerocoding.
968 // Remove the MSG_ZEROCODED flag and send the unencoded data
969 // instead
970 m_log.Debug("[LLUDPSERVER]: Packet exceeded buffer size during zerocoding for " + type + ". DataLength=" + dataLength +
971 " and BufferLength=" + buffer.Data.Length + ". Removing MSG_ZEROCODED flag");
972 data[0] = (byte)(data[0] & ~Helpers.MSG_ZEROCODED);
973 }
974 }
975
976 // If the packet data wasn't already copied during zerocoding, copy it now
977 if (doCopy)
978 {
979 if (dataLength <= buffer.Data.Length)
980 {
981 Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength);
982 }
983 else
984 {
985 bufferSize = dataLength;
986 buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize);
987
988 m_log.Error("[LLUDPSERVER]: Packet exceeded buffer size! This could be an indication of packet assembly not obeying the MTU. Type=" +
989 type + ", DataLength=" + dataLength + ", BufferLength=" + buffer.Data.Length);
990 Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength);
991 }
992 }
993
994 buffer.DataLength = dataLength;
995
996 #region Queue or Send
997
998 bool highPriority = false;
999
1000 if (category != ThrottleOutPacketType.Unknown && (category & ThrottleOutPacketType.HighPriority) != 0)
1001 {
1002 category = (ThrottleOutPacketType)((int)category & 127);
1003 highPriority = true;
1004 }
1005
1006 OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null);
1007
1008 // If we were not provided a method for handling unacked, use the UDPServer default method
1009 if ((outgoingPacket.Buffer.Data[0] & Helpers.MSG_RELIABLE) != 0)
1010 outgoingPacket.UnackedMethod = ((method == null) ? delegate(OutgoingPacket oPacket) { ResendUnacked(oPacket); } : method);
1011
1012 // If a Linden Lab 1.23.5 client receives an update packet after a kill packet for an object, it will
1013 // continue to display the deleted object until relog. Therefore, we need to always queue a kill object
1014 // packet so that it isn't sent before a queued update packet.
1015
1016 bool requestQueue = type == PacketType.KillObject;
1017 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue, highPriority))
1018 {
1019 SendPacketFinal(outgoingPacket);
1020 return true;
1021 }
1022
1023 return false;
1024
1025 #endregion Queue or Send
1026 }
1027
1028 public void SendAcks(LLUDPClient udpClient)
1029 {
1030 uint ack;
1031
1032 if (udpClient.PendingAcks.Dequeue(out ack))
1033 {
1034 List<PacketAckPacket.PacketsBlock> blocks = new List<PacketAckPacket.PacketsBlock>();
1035 PacketAckPacket.PacketsBlock block = new PacketAckPacket.PacketsBlock();
1036 block.ID = ack;
1037 blocks.Add(block);
1038
1039 while (udpClient.PendingAcks.Dequeue(out ack))
1040 {
1041 block = new PacketAckPacket.PacketsBlock();
1042 block.ID = ack;
1043 blocks.Add(block);
1044 }
1045
1046 PacketAckPacket packet = new PacketAckPacket();
1047 packet.Header.Reliable = false;
1048 packet.Packets = blocks.ToArray();
1049
1050 SendPacket(udpClient, packet, ThrottleOutPacketType.Unknown, true, null);
1051 }
1052 }
1053
1054 public void SendPing(LLUDPClient udpClient)
1055 {
1056 StartPingCheckPacket pc = (StartPingCheckPacket)PacketPool.Instance.GetPacket(PacketType.StartPingCheck);
1057 pc.Header.Reliable = false;
1058
1059 pc.PingID.PingID = (byte)udpClient.CurrentPingSequence++;
1060 // We *could* get OldestUnacked, but it would hurt performance and not provide any benefit
1061 pc.PingID.OldestUnacked = 0;
1062
1063 SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false, null);
1064 udpClient.m_lastStartpingTimeMS = Util.EnvironmentTickCount();
1065 }
1066
1067 public void CompletePing(LLUDPClient udpClient, byte pingID)
1068 {
1069 CompletePingCheckPacket completePing = new CompletePingCheckPacket();
1070 completePing.PingID.PingID = pingID;
1071 SendPacket(udpClient, completePing, ThrottleOutPacketType.Unknown, false, null);
1072 }
1073
1074 public void HandleUnacked(LLClientView client)
1075 {
1076 LLUDPClient udpClient = client.UDPClient;
1077
1078 if (!udpClient.IsConnected)
1079 return;
1080
1081 // Disconnect an agent if no packets are received for some time
1082 int timeoutTicks = m_ackTimeout;
1083
1084 // Allow more slack if the client is "paused" eg file upload dialogue is open
1085 // Some sort of limit is needed in case the client crashes, loses its network connection
1086 // or some other disaster prevents it from sendung the AgentResume
1087 if (udpClient.IsPaused)
1088 timeoutTicks = m_pausedAckTimeout;
1089
1090 if (client.IsActive &&
1091 (Environment.TickCount & Int32.MaxValue) - udpClient.TickLastPacketReceived > timeoutTicks)
1092 {
1093 // We must set IsActive synchronously so that we can stop the packet loop reinvoking this method, even
1094 // though it's set later on by LLClientView.Close()
1095 client.IsActive = false;
1096
1097 // Fire this out on a different thread so that we don't hold up outgoing packet processing for
1098 // everybody else if this is being called due to an ack timeout.
1099 // This is the same as processing as the async process of a logout request.
1100 Util.FireAndForget(
1101 o => DeactivateClientDueToTimeout(client, timeoutTicks), null, "LLUDPServer.DeactivateClientDueToTimeout");
1102
1103 return;
1104 }
1105
1106 // Get a list of all of the packets that have been sitting unacked longer than udpClient.RTO
1107 List<OutgoingPacket> expiredPackets = udpClient.NeedAcks.GetExpiredPackets(udpClient.RTO);
1108
1109 if (expiredPackets != null)
1110 {
1111 //m_log.Debug("[LLUDPSERVER]: Handling " + expiredPackets.Count + " packets to " + udpClient.AgentID + ", RTO=" + udpClient.RTO);
1112 // Exponential backoff of the retransmission timeout
1113 udpClient.BackoffRTO();
1114 for (int i = 0; i < expiredPackets.Count; ++i)
1115 expiredPackets[i].UnackedMethod(expiredPackets[i]);
1116 }
1117 }
1118
1119 public void ResendUnacked(OutgoingPacket outgoingPacket)
1120 {
1121 //m_log.DebugFormat("[LLUDPSERVER]: Resending packet #{0} (attempt {1}), {2}ms have passed",
1122 // outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount);
1123
1124 // Set the resent flag
1125 outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT);
1126 outgoingPacket.Category = ThrottleOutPacketType.Resend;
1127
1128 // Bump up the resend count on this packet
1129 Interlocked.Increment(ref outgoingPacket.ResendCount);
1130
1131 // Requeue or resend the packet
1132 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, false))
1133 SendPacketFinal(outgoingPacket);
1134 }
1135
1136 public void Flush(LLUDPClient udpClient)
1137 {
1138 // FIXME: Implement?
1139 }
1140
1141 /// <summary>
1142 /// Actually send a packet to a client.
1143 /// </summary>
1144 /// <param name="outgoingPacket"></param>
1145 internal void SendPacketFinal(OutgoingPacket outgoingPacket)
1146 {
1147 UDPPacketBuffer buffer = outgoingPacket.Buffer;
1148 byte flags = buffer.Data[0];
1149 bool isResend = (flags & Helpers.MSG_RESENT) != 0;
1150 bool isReliable = (flags & Helpers.MSG_RELIABLE) != 0;
1151 bool isZerocoded = (flags & Helpers.MSG_ZEROCODED) != 0;
1152 LLUDPClient udpClient = outgoingPacket.Client;
1153
1154 if (!udpClient.IsConnected)
1155 return;
1156
1157 #region ACK Appending
1158
1159 int dataLength = buffer.DataLength;
1160
1161 // NOTE: I'm seeing problems with some viewers when ACKs are appended to zerocoded packets so I've disabled that here
1162 if (!isZerocoded && !isResend && outgoingPacket.UnackedMethod == null)
1163 {
1164 // Keep appending ACKs until there is no room left in the buffer or there are
1165 // no more ACKs to append
1166 uint ackCount = 0;
1167 uint ack;
1168 while (dataLength + 5 < buffer.Data.Length && udpClient.PendingAcks.Dequeue(out ack))
1169 {
1170 Utils.UIntToBytesBig(ack, buffer.Data, dataLength);
1171 dataLength += 4;
1172 ++ackCount;
1173 }
1174
1175 if (ackCount > 0)
1176 {
1177 // Set the last byte of the packet equal to the number of appended ACKs
1178 buffer.Data[dataLength++] = (byte)ackCount;
1179 // Set the appended ACKs flag on this packet
1180 buffer.Data[0] = (byte)(buffer.Data[0] | Helpers.MSG_APPENDED_ACKS);
1181 }
1182 }
1183
1184 buffer.DataLength = dataLength;
1185
1186 #endregion ACK Appending
1187
1188 #region Sequence Number Assignment
1189
1190 if (!isResend)
1191 {
1192 // Not a resend, assign a new sequence number
1193 uint sequenceNumber = (uint)Interlocked.Increment(ref udpClient.CurrentSequence);
1194 Utils.UIntToBytesBig(sequenceNumber, buffer.Data, 1);
1195 outgoingPacket.SequenceNumber = sequenceNumber;
1196
1197 if (isReliable)
1198 {
1199 // Add this packet to the list of ACK responses we are waiting on from the server
1200 udpClient.NeedAcks.Add(outgoingPacket);
1201 }
1202 }
1203 else
1204 {
1205 Interlocked.Increment(ref udpClient.PacketsResent);
1206
1207 // We're not going to worry about interlock yet since its not currently critical that this total count
1208 // is 100% correct
1209 PacketsResentCount++;
1210 }
1211
1212 #endregion Sequence Number Assignment
1213
1214 // Stats tracking
1215 Interlocked.Increment(ref udpClient.PacketsSent);
1216
1217 // We're not going to worry about interlock yet since its not currently critical that this total count
1218 // is 100% correct
1219 PacketsSentCount++;
1220
1221 if (udpClient.DebugDataOutLevel > 0)
1222 m_log.DebugFormat(
1223 "[LLUDPSERVER]: Sending packet #{0} (rel: {1}, res: {2}) to {3} from {4}",
1224 outgoingPacket.SequenceNumber, isReliable, isResend, udpClient.AgentID, Scene.Name);
1225
1226 // Put the UDP payload on the wire
1227// AsyncBeginSend(buffer);
1228 SyncSend(buffer);
1229
1230 // Keep track of when this packet was sent out (right now)
1231 outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue;
1232 }
1233
1234 protected void RecordMalformedInboundPacket(IPEndPoint endPoint)
1235 {
1236// if (m_malformedCount < 100)
1237// m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString());
1238
1239 IncomingMalformedPacketCount++;
1240
1241 if ((IncomingMalformedPacketCount % 10000) == 0)
1242 m_log.WarnFormat(
1243 "[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack. Last was from {1}",
1244 IncomingMalformedPacketCount, endPoint);
1245 }
1246
1247 public override void PacketReceived(UDPPacketBuffer buffer)
1248 {
1249 // Debugging/Profiling
1250 //try { Thread.CurrentThread.Name = "PacketReceived (" + m_scene.RegionInfo.RegionName + ")"; }
1251 //catch (Exception) { }
1252// m_log.DebugFormat(
1253// "[LLUDPSERVER]: Packet received from {0} in {1}", buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
1254
1255 LLUDPClient udpClient = null;
1256 Packet packet = null;
1257 int packetEnd = buffer.DataLength - 1;
1258 IPEndPoint endPoint = (IPEndPoint)buffer.RemoteEndPoint;
1259
1260 #region Decoding
1261
1262 if (buffer.DataLength < 7)
1263 {
1264// m_log.WarnFormat(
1265// "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}",
1266// buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
1267
1268 RecordMalformedInboundPacket(endPoint);
1269
1270 return; // Drop undersized packet
1271 }
1272
1273 int headerLen = 7;
1274 if (buffer.Data[6] == 0xFF)
1275 {
1276 if (buffer.Data[7] == 0xFF)
1277 headerLen = 10;
1278 else
1279 headerLen = 8;
1280 }
1281
1282 if (buffer.DataLength < headerLen)
1283 {
1284// m_log.WarnFormat(
1285// "[LLUDPSERVER]: Dropping packet with malformed header received from {0} in {1}",
1286// buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
1287
1288 RecordMalformedInboundPacket(endPoint);
1289
1290 return; // Malformed header
1291 }
1292
1293 try
1294 {
1295// packet = Packet.BuildPacket(buffer.Data, ref packetEnd,
1296// // Only allocate a buffer for zerodecoding if the packet is zerocoded
1297// ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
1298 // If OpenSimUDPBase.UsePool == true (which is currently separate from the PacketPool) then we
1299 // assume that packet construction does not retain a reference to byte[] buffer.Data (instead, all
1300 // bytes are copied out).
1301 packet = PacketPool.Instance.GetPacket(buffer.Data, ref packetEnd,
1302 // Only allocate a buffer for zerodecoding if the packet is zerocoded
1303 ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
1304 }
1305 catch (Exception e)
1306 {
1307 if (IncomingMalformedPacketCount < 100)
1308 m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString());
1309 }
1310
1311 // Fail-safe check
1312 if (packet == null)
1313 {
1314 if (IncomingMalformedPacketCount < 100)
1315 {
1316 m_log.WarnFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}, data as hex {2}: {3}",
1317 buffer.DataLength, buffer.RemoteEndPoint, Utils.BytesToHexString(buffer.Data, buffer.DataLength, null),
1318 Regex.Replace(Encoding.UTF8.GetString(buffer.Data, 0, buffer.DataLength), @"\p{Cc}", a=>string.Format("[{0:X2}]", (byte)a.Value[0])));
1319 }
1320
1321 RecordMalformedInboundPacket(endPoint);
1322
1323 return;
1324 }
1325
1326 #endregion Decoding
1327
1328 #region Packet to Client Mapping
1329
1330 // If there is already a client for this endpoint, don't process UseCircuitCode
1331 IClientAPI client = null;
1332 if (!Scene.TryGetClient(endPoint, out client) || !(client is LLClientView))
1333 {
1334 // UseCircuitCode handling
1335 if (packet.Type == PacketType.UseCircuitCode)
1336 {
1337 // And if there is a UseCircuitCode pending, also drop it
1338 lock (m_pendingCache)
1339 {
1340 if (m_pendingCache.Contains(endPoint))
1341 return;
1342
1343 m_pendingCache.AddOrUpdate(endPoint, new Queue<UDPPacketBuffer>(), 60);
1344 }
1345
1346 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the
1347 // buffer.
1348 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
1349
1350 Util.FireAndForget(HandleUseCircuitCode, array);
1351
1352 return;
1353 }
1354 }
1355
1356 // If this is a pending connection, enqueue, don't process yet
1357 lock (m_pendingCache)
1358 {
1359 Queue<UDPPacketBuffer> queue;
1360 if (m_pendingCache.TryGetValue(endPoint, out queue))
1361 {
1362 //m_log.DebugFormat("[LLUDPSERVER]: Enqueued a {0} packet into the pending queue", packet.Type);
1363 queue.Enqueue(buffer);
1364 return;
1365 }
1366
1367/*
1368 else if (packet.Type == PacketType.CompleteAgentMovement)
1369 {
1370 // Send ack straight away to let the viewer know that we got it.
1371 SendAckImmediate(endPoint, packet.Header.Sequence);
1372
1373 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the
1374 // buffer.
1375 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
1376
1377 Util.FireAndForget(HandleCompleteMovementIntoRegion, array);
1378
1379 return;
1380 }
1381 */
1382 }
1383
1384 // Determine which agent this packet came from
1385 if (client == null || !(client is LLClientView))
1386 {
1387 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName);
1388
1389 IncomingOrphanedPacketCount++;
1390
1391 if ((IncomingOrphanedPacketCount % 10000) == 0)
1392 m_log.WarnFormat(
1393 "[LLUDPSERVER]: Received {0} orphaned packets so far. Last was from {1}",
1394 IncomingOrphanedPacketCount, endPoint);
1395
1396 return;
1397 }
1398
1399 udpClient = ((LLClientView)client).UDPClient;
1400
1401 if (!udpClient.IsConnected)
1402 {
1403 m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet for a unConnected client in " + Scene.RegionInfo.RegionName);
1404 return;
1405 }
1406
1407 #endregion Packet to Client Mapping
1408
1409 // Stats tracking
1410 Interlocked.Increment(ref udpClient.PacketsReceived);
1411
1412 int now = Environment.TickCount & Int32.MaxValue;
1413 udpClient.TickLastPacketReceived = now;
1414
1415 #region ACK Receiving
1416
1417 // Handle appended ACKs
1418 if (packet.Header.AppendedAcks && packet.Header.AckList != null)
1419 {
1420 // m_log.DebugFormat(
1421 // "[LLUDPSERVER]: Handling {0} appended acks from {1} in {2}",
1422 // packet.Header.AckList.Length, client.Name, m_scene.Name);
1423
1424 for (int i = 0; i < packet.Header.AckList.Length; i++)
1425 udpClient.NeedAcks.Acknowledge(packet.Header.AckList[i], now, packet.Header.Resent);
1426 }
1427
1428 // Handle PacketAck packets
1429 if (packet.Type == PacketType.PacketAck)
1430 {
1431 PacketAckPacket ackPacket = (PacketAckPacket)packet;
1432
1433 // m_log.DebugFormat(
1434 // "[LLUDPSERVER]: Handling {0} packet acks for {1} in {2}",
1435 // ackPacket.Packets.Length, client.Name, m_scene.Name);
1436
1437 for (int i = 0; i < ackPacket.Packets.Length; i++)
1438 udpClient.NeedAcks.Acknowledge(ackPacket.Packets[i].ID, now, packet.Header.Resent);
1439
1440 // We don't need to do anything else with PacketAck packets
1441 return;
1442 }
1443
1444 #endregion ACK Receiving
1445
1446 #region ACK Sending
1447
1448 if (packet.Header.Reliable)
1449 {
1450// m_log.DebugFormat(
1451// "[LLUDPSERVER]: Adding ack request for {0} {1} from {2} in {3}",
1452// packet.Type, packet.Header.Sequence, client.Name, m_scene.Name);
1453
1454 udpClient.PendingAcks.Enqueue(packet.Header.Sequence);
1455
1456 // This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out,
1457 // add the current received bytes to it, test if 2*MTU bytes have been sent, if so remove
1458 // 2*MTU bytes from the value and send ACKs, and finally add the local value back to
1459 // client.BytesSinceLastACK. Lockless thread safety
1460 int bytesSinceLastACK = Interlocked.Exchange(ref udpClient.BytesSinceLastACK, 0);
1461 bytesSinceLastACK += buffer.DataLength;
1462 if (bytesSinceLastACK > LLUDPServer.MTU * 2)
1463 {
1464 bytesSinceLastACK -= LLUDPServer.MTU * 2;
1465 SendAcks(udpClient);
1466 }
1467 Interlocked.Add(ref udpClient.BytesSinceLastACK, bytesSinceLastACK);
1468 }
1469
1470 #endregion ACK Sending
1471
1472 #region Incoming Packet Accounting
1473
1474 // We're not going to worry about interlock yet since its not currently critical that this total count
1475 // is 100% correct
1476 if (packet.Header.Resent)
1477 IncomingPacketsResentCount++;
1478
1479 // Check the archive of received reliable packet IDs to see whether we already received this packet
1480 if (packet.Header.Reliable && !udpClient.PacketArchive.TryEnqueue(packet.Header.Sequence))
1481 {
1482 if (packet.Header.Resent)
1483 m_log.DebugFormat(
1484 "[LLUDPSERVER]: Received a resend of already processed packet #{0}, type {1} from {2}",
1485 packet.Header.Sequence, packet.Type, client.Name);
1486 else
1487 m_log.WarnFormat(
1488 "[LLUDPSERVER]: Received a duplicate (not marked as resend) of packet #{0}, type {1} from {2}",
1489 packet.Header.Sequence, packet.Type, client.Name);
1490
1491 // Avoid firing a callback twice for the same packet
1492 return;
1493 }
1494
1495 #endregion Incoming Packet Accounting
1496
1497 #region BinaryStats
1498 LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length);
1499 #endregion BinaryStats
1500
1501
1502//AgentUpdate removed from here
1503
1504
1505 #region Ping Check Handling
1506
1507 if (packet.Type == PacketType.StartPingCheck)
1508 {
1509// m_log.DebugFormat("[LLUDPSERVER]: Handling ping from {0} in {1}", client.Name, m_scene.Name);
1510
1511 // We don't need to do anything else with ping checks
1512 StartPingCheckPacket startPing = (StartPingCheckPacket)packet;
1513 CompletePing(udpClient, startPing.PingID.PingID);
1514
1515 if ((Environment.TickCount - m_elapsedMSSinceLastStatReport) >= 3000)
1516 {
1517 udpClient.SendPacketStats();
1518 m_elapsedMSSinceLastStatReport = Environment.TickCount;
1519 }
1520 return;
1521 }
1522 else if (packet.Type == PacketType.CompletePingCheck)
1523 {
1524 int t = Util.EnvironmentTickCountSubtract(udpClient.m_lastStartpingTimeMS);
1525 int c = udpClient.m_pingMS;
1526 c = 800 * c + 200 * t;
1527 c /= 1000;
1528 udpClient.m_pingMS = c;
1529 return;
1530 }
1531
1532 #endregion Ping Check Handling
1533
1534 IncomingPacket incomingPacket;
1535
1536 // Inbox insertion
1537 if (UsePools)
1538 {
1539 incomingPacket = m_incomingPacketPool.GetObject();
1540 incomingPacket.Client = (LLClientView)client;
1541 incomingPacket.Packet = packet;
1542 }
1543 else
1544 {
1545 incomingPacket = new IncomingPacket((LLClientView)client, packet);
1546 }
1547
1548// if (incomingPacket.Packet.Type == PacketType.AgentUpdate ||
1549// incomingPacket.Packet.Type == PacketType.ChatFromViewer)
1550 if (incomingPacket.Packet.Type == PacketType.ChatFromViewer)
1551 packetInbox.PriorityEnqueue(incomingPacket);
1552 else
1553 packetInbox.Enqueue(incomingPacket);
1554
1555 }
1556
1557 #region BinaryStats
1558
1559 public class PacketLogger
1560 {
1561 public DateTime StartTime;
1562 public string Path = null;
1563 public System.IO.BinaryWriter Log = null;
1564 }
1565
1566 public static PacketLogger PacketLog;
1567
1568 protected static bool m_shouldCollectStats = false;
1569 // Number of seconds to log for
1570 static TimeSpan binStatsMaxFilesize = TimeSpan.FromSeconds(300);
1571 static object binStatsLogLock = new object();
1572 static string binStatsDir = "";
1573
1574 //for Aggregated In/Out BW logging
1575 static bool m_aggregatedBWStats = false;
1576 static long m_aggregatedBytesIn = 0;
1577 static long m_aggregatedByestOut = 0;
1578 static object aggBWStatsLock = new object();
1579
1580 public static long AggregatedLLUDPBytesIn
1581 {
1582 get { return m_aggregatedBytesIn; }
1583 }
1584 public static long AggregatedLLUDPBytesOut
1585 {
1586 get {return m_aggregatedByestOut;}
1587 }
1588
1589 public static void LogPacketHeader(bool incoming, uint circuit, byte flags, PacketType packetType, ushort size)
1590 {
1591 if (m_aggregatedBWStats)
1592 {
1593 lock (aggBWStatsLock)
1594 {
1595 if (incoming)
1596 m_aggregatedBytesIn += size;
1597 else
1598 m_aggregatedByestOut += size;
1599 }
1600 }
1601
1602 if (!m_shouldCollectStats) return;
1603
1604 // Binary logging format is TTTTTTTTCCCCFPPPSS, T=Time, C=Circuit, F=Flags, P=PacketType, S=size
1605
1606 // Put the incoming bit into the least significant bit of the flags byte
1607 if (incoming)
1608 flags |= 0x01;
1609 else
1610 flags &= 0xFE;
1611
1612 // Put the flags byte into the most significant bits of the type integer
1613 uint type = (uint)packetType;
1614 type |= (uint)flags << 24;
1615
1616 // m_log.Debug("1 LogPacketHeader(): Outside lock");
1617 lock (binStatsLogLock)
1618 {
1619 DateTime now = DateTime.Now;
1620
1621 // m_log.Debug("2 LogPacketHeader(): Inside lock. now is " + now.Ticks);
1622 try
1623 {
1624 if (PacketLog == null || (now > PacketLog.StartTime + binStatsMaxFilesize))
1625 {
1626 if (PacketLog != null && PacketLog.Log != null)
1627 {
1628 PacketLog.Log.Close();
1629 }
1630
1631 // First log file or time has expired, start writing to a new log file
1632 PacketLog = new PacketLogger();
1633 PacketLog.StartTime = now;
1634 PacketLog.Path = (binStatsDir.Length > 0 ? binStatsDir + System.IO.Path.DirectorySeparatorChar.ToString() : "")
1635 + String.Format("packets-{0}.log", now.ToString("yyyyMMddHHmmss"));
1636 PacketLog.Log = new BinaryWriter(File.Open(PacketLog.Path, FileMode.Append, FileAccess.Write));
1637 }
1638
1639 // Serialize the data
1640 byte[] output = new byte[18];
1641 Buffer.BlockCopy(BitConverter.GetBytes(now.Ticks), 0, output, 0, 8);
1642 Buffer.BlockCopy(BitConverter.GetBytes(circuit), 0, output, 8, 4);
1643 Buffer.BlockCopy(BitConverter.GetBytes(type), 0, output, 12, 4);
1644 Buffer.BlockCopy(BitConverter.GetBytes(size), 0, output, 16, 2);
1645
1646 // Write the serialized data to disk
1647 if (PacketLog != null && PacketLog.Log != null)
1648 PacketLog.Log.Write(output);
1649 }
1650 catch (Exception ex)
1651 {
1652 m_log.Error("Packet statistics gathering failed: " + ex.Message, ex);
1653 if (PacketLog.Log != null)
1654 {
1655 PacketLog.Log.Close();
1656 }
1657 PacketLog = null;
1658 }
1659 }
1660 }
1661
1662 #endregion BinaryStats
1663
1664 protected void HandleUseCircuitCode(object o)
1665 {
1666 IPEndPoint endPoint = null;
1667 IClientAPI client = null;
1668
1669 try
1670 {
1671// DateTime startTime = DateTime.Now;
1672 object[] array = (object[])o;
1673 endPoint = (IPEndPoint)array[0];
1674 UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1];
1675
1676 m_log.DebugFormat(
1677 "[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} to {1} from IP {2}",
1678 uccp.CircuitCode.Code, Scene.RegionInfo.RegionName, endPoint);
1679
1680 AuthenticateResponse sessionInfo;
1681 if (IsClientAuthorized(uccp, out sessionInfo))
1682 {
1683 AgentCircuitData aCircuit = Scene.AuthenticateHandler.GetAgentCircuitData(uccp.CircuitCode.Code);
1684
1685 // Begin the process of adding the client to the simulator
1686 client
1687 = AddClient(
1688 uccp.CircuitCode.Code,
1689 uccp.CircuitCode.ID,
1690 uccp.CircuitCode.SessionID,
1691 endPoint,
1692 sessionInfo);
1693
1694 // This will be true if the client is new, e.g. not
1695 // an existing child agent, and there is no circuit data
1696 if (client != null && aCircuit == null)
1697 {
1698 Scene.CloseAgent(client.AgentId, true);
1699 return;
1700 }
1701
1702 // Now we know we can handle more data
1703 Thread.Sleep(200);
1704
1705 // Obtain the pending queue and remove it from the cache
1706 Queue<UDPPacketBuffer> queue = null;
1707
1708 lock (m_pendingCache)
1709 {
1710 if (!m_pendingCache.TryGetValue(endPoint, out queue))
1711 {
1712 m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present");
1713 return;
1714
1715 }
1716 m_pendingCache.Remove(endPoint);
1717 }
1718
1719 m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count);
1720
1721 // Reinject queued packets
1722 while (queue.Count > 0)
1723 {
1724 UDPPacketBuffer buf = queue.Dequeue();
1725 PacketReceived(buf);
1726 }
1727
1728 queue = null;
1729
1730 // Send ack straight away to let the viewer know that the connection is active.
1731 // The client will be null if it already exists (e.g. if on a region crossing the client sends a use
1732 // circuit code to the existing child agent. This is not particularly obvious.
1733 SendAckImmediate(endPoint, uccp.Header.Sequence);
1734
1735 // We only want to send initial data to new clients, not ones which are being converted from child to root.
1736 if (client != null)
1737 {
1738 bool tp = (aCircuit.teleportFlags > 0);
1739 // Let's delay this for TP agents, otherwise the viewer doesn't know where to get resources from
1740 if (!tp)
1741 client.SceneAgent.SendInitialDataToMe();
1742 }
1743 }
1744 else
1745 {
1746 // Don't create clients for unauthorized requesters.
1747 m_log.WarnFormat(
1748 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}",
1749
1750 uccp.CircuitCode.ID, Scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint);
1751
1752 lock (m_pendingCache)
1753 m_pendingCache.Remove(endPoint);
1754 }
1755
1756 // m_log.DebugFormat(
1757 // "[LLUDPSERVER]: Handling UseCircuitCode request from {0} took {1}ms",
1758 // buffer.RemoteEndPoint, (DateTime.Now - startTime).Milliseconds);
1759
1760 }
1761 catch (Exception e)
1762 {
1763 m_log.ErrorFormat(
1764 "[LLUDPSERVER]: UseCircuitCode handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}",
1765 endPoint != null ? endPoint.ToString() : "n/a",
1766 client != null ? client.Name : "unknown",
1767 client != null ? client.AgentId.ToString() : "unknown",
1768 e.Message,
1769 e.StackTrace);
1770 }
1771 }
1772/*
1773 protected void HandleCompleteMovementIntoRegion(object o)
1774 {
1775 IPEndPoint endPoint = null;
1776 IClientAPI client = null;
1777
1778 try
1779 {
1780 object[] array = (object[])o;
1781 endPoint = (IPEndPoint)array[0];
1782 CompleteAgentMovementPacket packet = (CompleteAgentMovementPacket)array[1];
1783
1784 m_log.DebugFormat(
1785 "[LLUDPSERVER]: Handling CompleteAgentMovement request from {0} in {1}", endPoint, Scene.Name);
1786
1787 // Determine which agent this packet came from
1788 // We need to wait here because in when using the OpenSimulator V2 teleport protocol to travel to a destination
1789 // simulator with no existing child presence, the viewer (at least LL 3.3.4) will send UseCircuitCode
1790 // and then CompleteAgentMovement immediately without waiting for an ack. As we are now handling these
1791 // packets asynchronously, we need to account for this thread proceeding more quickly than the
1792 // UseCircuitCode thread.
1793 int count = 40;
1794 while (count-- > 0)
1795 {
1796 if (Scene.TryGetClient(endPoint, out client))
1797 {
1798 if (!client.IsActive)
1799 {
1800 // This check exists to catch a condition where the client has been closed by another thread
1801 // but has not yet been removed from the client manager (and possibly a new connection has
1802 // not yet been established).
1803 m_log.DebugFormat(
1804 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client is not active yet. Waiting.",
1805 endPoint, client.Name, Scene.Name);
1806 }
1807 else if (client.SceneAgent == null)
1808 {
1809 // This check exists to catch a condition where the new client has been added to the client
1810 // manager but the SceneAgent has not yet been set in Scene.AddNewAgent(). If we are too
1811 // eager, then the new ScenePresence may not have registered a listener for this messsage
1812 // before we try to process it.
1813 // XXX: A better long term fix may be to add the SceneAgent before the client is added to
1814 // the client manager
1815 m_log.DebugFormat(
1816 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client SceneAgent not set yet. Waiting.",
1817 endPoint, client.Name, Scene.Name);
1818 }
1819 else
1820 {
1821 break;
1822 }
1823 }
1824 else
1825 {
1826 m_log.DebugFormat(
1827 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} in {1} but no client exists yet. Waiting.",
1828 endPoint, Scene.Name);
1829 }
1830
1831 Thread.Sleep(200);
1832 }
1833
1834 if (client == null)
1835 {
1836 m_log.DebugFormat(
1837 "[LLUDPSERVER]: No client found for CompleteAgentMovement from {0} in {1} after wait. Dropping.",
1838 endPoint, Scene.Name);
1839
1840 return;
1841 }
1842 else if (!client.IsActive || client.SceneAgent == null)
1843 {
1844 // This check exists to catch a condition where the client has been closed by another thread
1845 // but has not yet been removed from the client manager.
1846 // The packet could be simply ignored but it is useful to know if this condition occurred for other debugging
1847 // purposes.
1848 m_log.DebugFormat(
1849 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client is not active after wait. Dropping.",
1850 endPoint, client.Name, Scene.Name);
1851
1852 return;
1853 }
1854
1855 IncomingPacket incomingPacket1;
1856
1857 // Inbox insertion
1858 if (UsePools)
1859 {
1860 incomingPacket1 = m_incomingPacketPool.GetObject();
1861 incomingPacket1.Client = (LLClientView)client;
1862 incomingPacket1.Packet = packet;
1863 }
1864 else
1865 {
1866 incomingPacket1 = new IncomingPacket((LLClientView)client, packet);
1867 }
1868
1869 packetInbox.Enqueue(incomingPacket1);
1870 }
1871 catch (Exception e)
1872 {
1873 m_log.ErrorFormat(
1874 "[LLUDPSERVER]: CompleteAgentMovement handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}",
1875 endPoint != null ? endPoint.ToString() : "n/a",
1876 client != null ? client.Name : "unknown",
1877 client != null ? client.AgentId.ToString() : "unknown",
1878 e.Message,
1879 e.StackTrace);
1880 }
1881 }
1882*/
1883
1884 /// <summary>
1885 /// Send an ack immediately to the given endpoint.
1886 /// </summary>
1887 /// <remarks>
1888 /// FIXME: Might be possible to use SendPacketData() like everything else, but this will require refactoring so
1889 /// that we can obtain the UDPClient easily at this point.
1890 /// </remarks>
1891 /// <param name="remoteEndpoint"></param>
1892 /// <param name="sequenceNumber"></param>
1893 protected void SendAckImmediate(IPEndPoint remoteEndpoint, uint sequenceNumber)
1894 {
1895 PacketAckPacket ack = new PacketAckPacket();
1896 ack.Header.Reliable = false;
1897 ack.Packets = new PacketAckPacket.PacketsBlock[1];
1898 ack.Packets[0] = new PacketAckPacket.PacketsBlock();
1899 ack.Packets[0].ID = sequenceNumber;
1900
1901 SendAckImmediate(remoteEndpoint, ack);
1902 }
1903
1904 public virtual void SendAckImmediate(IPEndPoint remoteEndpoint, PacketAckPacket ack)
1905 {
1906 byte[] packetData = ack.ToBytes();
1907 int length = packetData.Length;
1908
1909 UDPPacketBuffer buffer = new UDPPacketBuffer(remoteEndpoint, length);
1910 buffer.DataLength = length;
1911
1912 Buffer.BlockCopy(packetData, 0, buffer.Data, 0, length);
1913
1914// AsyncBeginSend(buffer);
1915 SyncSend(buffer);
1916 }
1917
1918 protected bool IsClientAuthorized(UseCircuitCodePacket useCircuitCode, out AuthenticateResponse sessionInfo)
1919 {
1920 UUID agentID = useCircuitCode.CircuitCode.ID;
1921 UUID sessionID = useCircuitCode.CircuitCode.SessionID;
1922 uint circuitCode = useCircuitCode.CircuitCode.Code;
1923
1924 sessionInfo = m_circuitManager.AuthenticateSession(sessionID, agentID, circuitCode);
1925 return sessionInfo.Authorised;
1926 }
1927
1928 /// <summary>
1929 /// Add a client.
1930 /// </summary>
1931 /// <param name="circuitCode"></param>
1932 /// <param name="agentID"></param>
1933 /// <param name="sessionID"></param>
1934 /// <param name="remoteEndPoint"></param>
1935 /// <param name="sessionInfo"></param>
1936 /// <returns>The client if it was added. Null if the client already existed.</returns>
1937 protected virtual IClientAPI AddClient(
1938 uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo)
1939 {
1940 IClientAPI client = null;
1941 bool createNew = false;
1942
1943 // We currently synchronize this code across the whole scene to avoid issues such as
1944 // http://opensimulator.org/mantis/view.php?id=5365 However, once locking per agent circuit can be done
1945 // consistently, this lock could probably be removed.
1946 lock (this)
1947 {
1948 if (!Scene.TryGetClient(agentID, out client))
1949 {
1950 createNew = true;
1951 }
1952 else
1953 {
1954 if (client.SceneAgent == null)
1955 {
1956 Scene.CloseAgent(agentID, true);
1957 createNew = true;
1958 }
1959 }
1960
1961 if (createNew)
1962 {
1963 LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, Throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO);
1964
1965
1966 client = new LLClientView(Scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
1967 client.OnLogout += LogoutHandler;
1968 client.DebugPacketLevel = DefaultClientPacketDebugLevel;
1969
1970 ((LLClientView)client).DisableFacelights = m_disableFacelights;
1971
1972 client.Start();
1973 }
1974 }
1975
1976 return client;
1977 }
1978
1979 /// <summary>
1980 /// Deactivates the client if we don't receive any packets within a certain amount of time (default 60 seconds).
1981 /// </summary>
1982 /// <remarks>
1983 /// If a connection is active then we will always receive packets even if nothing else is happening, due to
1984 /// regular client pings.
1985 /// </remarks>
1986 /// <param name='client'></param>
1987 /// <param name='timeoutTicks'></param>
1988 protected void DeactivateClientDueToTimeout(LLClientView client, int timeoutTicks)
1989 {
1990 lock (client.CloseSyncLock)
1991 {
1992 ClientLogoutsDueToNoReceives++;
1993
1994 if (client.SceneAgent != null)
1995 {
1996 m_log.WarnFormat(
1997 "[LLUDPSERVER]: No packets received from {0} agent of {1} for {2}ms in {3}. Disconnecting.",
1998 client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, timeoutTicks, Scene.Name);
1999
2000 if (!client.SceneAgent.IsChildAgent)
2001 client.Kick("Simulator logged you out due to connection timeout.");
2002 }
2003 }
2004
2005 if (!Scene.CloseAgent(client.AgentId, true))
2006 client.Close(true,true);
2007 }
2008
2009 protected void IncomingPacketHandler()
2010 {
2011 Thread.CurrentThread.Priority = ThreadPriority.Highest;
2012 IncomingPacket incomingPacket;
2013 // Set this culture for the thread that incoming packets are received
2014 // on to en-US to avoid number parsing issues
2015 Culture.SetCurrentCulture();
2016
2017 while (IsRunningInbound)
2018 {
2019 Scene.ThreadAlive(1);
2020 try
2021 {
2022 incomingPacket = packetInbox.Dequeue(250);
2023
2024 if (incomingPacket != null && IsRunningInbound)
2025 {
2026 ProcessInPacket(incomingPacket);
2027
2028 if (UsePools)
2029 {
2030 incomingPacket.Client = null;
2031 m_incomingPacketPool.ReturnObject(incomingPacket);
2032 }
2033 incomingPacket = null;
2034 }
2035 }
2036 catch(Exception ex)
2037 {
2038 m_log.Error("[LLUDPSERVER]: Error in the incoming packet handler loop: " + ex.Message, ex);
2039 }
2040
2041 Watchdog.UpdateThread();
2042 }
2043
2044 if (packetInbox.Count() > 0)
2045 m_log.Warn("[LLUDPSERVER]: IncomingPacketHandler is shutting down, dropping " + packetInbox.Count() + " packets");
2046 packetInbox.Clear();
2047
2048 Watchdog.RemoveThread();
2049 }
2050
2051 protected void OutgoingPacketHandler()
2052 {
2053 Thread.CurrentThread.Priority = ThreadPriority.Highest;
2054
2055 // Set this culture for the thread that outgoing packets are sent
2056 // on to en-US to avoid number parsing issues
2057 Culture.SetCurrentCulture();
2058
2059 // Typecast the function to an Action<IClientAPI> once here to avoid allocating a new
2060 // Action generic every round
2061 Action<IClientAPI> clientPacketHandler = ClientOutgoingPacketHandler;
2062
2063 while (base.IsRunningOutbound)
2064 {
2065 Scene.ThreadAlive(2);
2066
2067
2068 try
2069 {
2070 m_packetSent = false;
2071
2072 #region Update Timers
2073
2074 m_resendUnacked = false;
2075 m_sendAcks = false;
2076 m_sendPing = false;
2077
2078 // Update elapsed time
2079 double thisTick = Util.GetTimeStampMS();
2080
2081 // update some 1ms resolution chained timers
2082 m_elapsedMSOutgoingPacketHandler += thisTick - m_tickLastOutgoingPacketHandler;
2083 m_tickLastOutgoingPacketHandler = thisTick;
2084
2085 // Check for pending outgoing resends every 100ms
2086 if (m_elapsedMSOutgoingPacketHandler >= 100.0)
2087 {
2088 m_resendUnacked = true;
2089 m_elapsedMSOutgoingPacketHandler = 0.0;
2090 m_elapsed100MSOutgoingPacketHandler += 1;
2091 }
2092
2093 // Check for pending outgoing ACKs every 500ms
2094 if (m_elapsed100MSOutgoingPacketHandler >= 5)
2095 {
2096 m_sendAcks = true;
2097 m_elapsed100MSOutgoingPacketHandler = 0;
2098 m_elapsed500MSOutgoingPacketHandler += 1;
2099 }
2100
2101 // Send pings to clients every 5000ms
2102 if (m_elapsed500MSOutgoingPacketHandler >= 10)
2103 {
2104 m_sendPing = true;
2105 m_elapsed500MSOutgoingPacketHandler = 0;
2106 }
2107 #endregion Update Timers
2108
2109 // Handle outgoing packets, resends, acknowledgements, and pings for each
2110 // client. m_packetSent will be set to true if a packet is sent
2111 Scene.ForEachClient(clientPacketHandler);
2112
2113 m_currentOutgoingClient = null;
2114
2115 // If nothing was sent, sleep for the minimum amount of time before a
2116 // token bucket could get more tokens
2117
2118 if(Scene.GetNumberOfClients() == 0)
2119 {
2120 Thread.Sleep(100);
2121 }
2122 else if (!m_packetSent)
2123// Thread.Sleep((int)TickCountResolution); outch this is bad on linux
2124 Thread.Sleep(15); // match the 16ms of windows7, dont ask 16 or win may decide to do 32ms.
2125
2126 Watchdog.UpdateThread();
2127 }
2128 catch (Exception ex)
2129 {
2130 m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler loop threw an exception: " + ex.Message, ex);
2131 }
2132 }
2133
2134 Watchdog.RemoveThread();
2135 }
2136
2137 protected void ClientOutgoingPacketHandler(IClientAPI client)
2138 {
2139 m_currentOutgoingClient = client;
2140
2141 try
2142 {
2143 if (client is LLClientView)
2144 {
2145 LLClientView llClient = (LLClientView)client;
2146 LLUDPClient udpClient = llClient.UDPClient;
2147
2148 if (udpClient.IsConnected)
2149 {
2150 if (m_resendUnacked)
2151 HandleUnacked(llClient);
2152
2153 if (m_sendAcks)
2154 SendAcks(udpClient);
2155
2156 if (m_sendPing)
2157 SendPing(udpClient);
2158
2159 // Dequeue any outgoing packets that are within the throttle limits
2160 if (udpClient.DequeueOutgoing())
2161 m_packetSent = true;
2162 }
2163 }
2164 }
2165 catch (Exception ex)
2166 {
2167 m_log.Error(
2168 string.Format("[LLUDPSERVER]: OutgoingPacketHandler iteration for {0} threw ", client.Name), ex);
2169 }
2170 }
2171
2172 #region Emergency Monitoring
2173 // Alternative packet handler fuull of instrumentation
2174 // Handy for hunting bugs
2175 protected Stopwatch watch1 = new Stopwatch();
2176 protected Stopwatch watch2 = new Stopwatch();
2177
2178 protected float avgProcessingTicks = 0;
2179 protected float avgResendUnackedTicks = 0;
2180 protected float avgSendAcksTicks = 0;
2181 protected float avgSendPingTicks = 0;
2182 protected float avgDequeueTicks = 0;
2183 protected long nticks = 0;
2184 protected long nticksUnack = 0;
2185 protected long nticksAck = 0;
2186 protected long nticksPing = 0;
2187 protected int npacksSent = 0;
2188 protected int npackNotSent = 0;
2189
2190 /// <summary>
2191 /// Number of inbound packets processed since startup.
2192 /// </summary>
2193 public long IncomingPacketsProcessed { get; protected set; }
2194
2195 #endregion
2196
2197 protected void ProcessInPacket(IncomingPacket incomingPacket)
2198 {
2199 Packet packet = incomingPacket.Packet;
2200 LLClientView client = incomingPacket.Client;
2201
2202 if(!client.IsActive)
2203 return;
2204
2205 m_currentIncomingClient = client;
2206
2207 try
2208 {
2209 // Process this packet
2210 client.ProcessInPacket(packet);
2211 }
2212 catch(ThreadAbortException)
2213 {
2214 // If something is trying to abort the packet processing thread, take that as a hint that it's time to shut down
2215 m_log.Info("[LLUDPSERVER]: Caught a thread abort, shutting down the LLUDP server");
2216 Stop();
2217 }
2218 catch(Exception e)
2219 {
2220 // Don't let a failure in an individual client thread crash the whole sim.
2221 m_log.Error(
2222 string.Format(
2223 "[LLUDPSERVER]: Client packet handler for {0} for packet {1} threw ",
2224 client.Name,packet.Type),
2225 e);
2226 }
2227 finally
2228 {
2229 m_currentIncomingClient = null;
2230 }
2231
2232 IncomingPacketsProcessed++;
2233 }
2234
2235 protected void LogoutHandler(IClientAPI client)
2236 {
2237 client.SendLogoutPacket();
2238
2239 if (!client.IsLoggingOut)
2240 {
2241 client.IsLoggingOut = true;
2242 Scene.CloseAgent(client.AgentId, false);
2243 }
2244 }
2245 }
2246}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs
new file mode 100644
index 0000000..012a57d
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs
@@ -0,0 +1,880 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Text;
31using NDesk.Options;
32using OpenSim.Framework;
33using OpenSim.Framework.Console;
34using OpenSim.Region.Framework.Scenes;
35
36namespace OpenSim.Region.ClientStack.LindenUDP
37{
38 public class LLUDPServerCommands
39 {
40 private ICommandConsole m_console;
41 private LLUDPServer m_udpServer;
42
43 public LLUDPServerCommands(ICommandConsole console, LLUDPServer udpServer)
44 {
45 m_console = console;
46 m_udpServer = udpServer;
47 }
48
49 public void Register()
50 {
51/*
52 m_console.Commands.AddCommand(
53 "Comms", false, "show server throttles",
54 "show server throttles",
55 "Show information about server throttles",
56 HandleShowServerThrottlesCommand);
57
58 m_console.Commands.AddCommand(
59 "Debug", false, "debug lludp packet",
60 "debug lludp packet [--default | --all] <level> [<avatar-first-name> <avatar-last-name>]",
61 "Turn on packet debugging. This logs information when the client stack hands a processed packet off to downstream code or when upstream code first requests that a certain packet be sent.",
62 "If level > 255 then all incoming and outgoing packets are logged.\n"
63 + "If level <= 255 then incoming AgentUpdate and outgoing SimStats and SimulatorViewerTimeMessage packets are not logged.\n"
64 + "If level <= 200 then incoming RequestImage and outgoing ImagePacket, ImageData, LayerData and CoarseLocationUpdate packets are not logged.\n"
65 + "If level <= 100 then incoming ViewerEffect and AgentAnimation and outgoing ViewerEffect and AvatarAnimation packets are not logged.\n"
66 + "If level <= 50 then outgoing ImprovedTerseObjectUpdate packets are not logged.\n"
67 + "If level <= 0 then no packets are logged.\n"
68 + "If --default is specified then the level becomes the default logging level for all subsequent agents.\n"
69 + "If --all is specified then the level becomes the default logging level for all current and subsequent agents.\n"
70 + "In these cases, you cannot also specify an avatar name.\n"
71 + "If an avatar name is given then only packets from that avatar are logged.",
72 HandlePacketCommand);
73
74 m_console.Commands.AddCommand(
75 "Debug", false, "debug lludp data out",
76 "debug lludp data out <level> <avatar-first-name> <avatar-last-name>\"",
77 "Turn on debugging for final outgoing data to the given user's client.",
78 "This operates at a much lower level than the packet command and prints out available details when the data is actually sent.\n"
79 + "If level > 0 then information about all outgoing UDP data for this avatar is logged.\n"
80 + "If level <= 0 then no information about outgoing UDP data for this avatar is logged.",
81 HandleDataCommand);
82
83 m_console.Commands.AddCommand(
84 "Debug", false, "debug lludp drop",
85 "debug lludp drop <in|out> <add|remove> <packet-name>",
86 "Drop all in or outbound packets that match the given name",
87 "For test purposes.",
88 HandleDropCommand);
89
90 m_console.Commands.AddCommand(
91 "Debug",
92 false,
93 "debug lludp start",
94 "debug lludp start <in|out|all>",
95 "Control LLUDP packet processing.",
96 "No effect if packet processing has already started.\n"
97 + "in - start inbound processing.\n"
98 + "out - start outbound processing.\n"
99 + "all - start in and outbound processing.\n",
100 HandleStartCommand);
101
102 m_console.Commands.AddCommand(
103 "Debug",
104 false,
105 "debug lludp stop",
106 "debug lludp stop <in|out|all>",
107 "Stop LLUDP packet processing.",
108 "No effect if packet processing has already stopped.\n"
109 + "in - stop inbound processing.\n"
110 + "out - stop outbound processing.\n"
111 + "all - stop in and outbound processing.\n",
112 HandleStopCommand);
113
114 m_console.Commands.AddCommand(
115 "Debug",
116 false,
117 "debug lludp pool",
118 "debug lludp pool <on|off>",
119 "Turn object pooling within the lludp component on or off.",
120 HandlePoolCommand);
121
122 m_console.Commands.AddCommand(
123 "Debug",
124 false,
125 "debug lludp status",
126 "debug lludp status",
127 "Return status of LLUDP packet processing.",
128 HandleStatusCommand);
129
130 m_console.Commands.AddCommand(
131 "Debug",
132 false,
133 "debug lludp throttles log",
134 "debug lludp throttles log <level> [<avatar-first-name> <avatar-last-name>]",
135 "Change debug logging level for throttles.",
136 "If level >= 0 then throttle debug logging is performed.\n"
137 + "If level <= 0 then no throttle debug logging is performed.",
138 HandleThrottleCommand);
139
140 m_console.Commands.AddCommand(
141 "Debug",
142 false,
143 "debug lludp throttles get",
144 "debug lludp throttles get [<avatar-first-name> <avatar-last-name>]",
145 "Return debug settings for throttles.",
146 "adaptive - true/false, controls adaptive throttle setting.\n"
147 + "request - request drip rate in kbps.\n"
148 + "max - the max kbps throttle allowed for the specified existing clients. Use 'debug lludp get new-client-throttle-max' to see the setting for new clients.\n",
149 HandleThrottleGetCommand);
150
151 m_console.Commands.AddCommand(
152 "Debug",
153 false,
154 "debug lludp throttles set",
155 "debug lludp throttles set <param> <value> [<avatar-first-name> <avatar-last-name>]",
156 "Set a throttle parameter for the given client.",
157 "adaptive - true/false, controls adaptive throttle setting.\n"
158 + "current - current drip rate in kbps.\n"
159 + "request - requested drip rate in kbps.\n"
160 + "max - the max kbps throttle allowed for the specified existing clients. Use 'debug lludp set new-client-throttle-max' to change the settings for new clients.\n",
161 HandleThrottleSetCommand);
162
163 m_console.Commands.AddCommand(
164 "Debug",
165 false,
166 "debug lludp get",
167 "debug lludp get",
168 "Get debug parameters for the server.",
169 "max-scene-throttle - the current max cumulative kbps provided for this scene to clients.\n"
170 + "max-new-client-throttle - the max kbps throttle allowed to new clients. Use 'debug lludp throttles get max' to see the settings for existing clients.",
171 HandleGetCommand);
172
173 m_console.Commands.AddCommand(
174 "Debug",
175 false,
176 "debug lludp set",
177 "debug lludp set <param> <value>",
178 "Set a parameter for the server.",
179 "max-scene-throttle - the current max cumulative kbps provided for this scene to clients.\n"
180 + "max-new-client-throttle - the max kbps throttle allowed to each new client. Use 'debug lludp throttles set max' to set for existing clients.",
181 HandleSetCommand);
182
183 m_console.Commands.AddCommand(
184 "Debug",
185 false,
186 "debug lludp toggle agentupdate",
187 "debug lludp toggle agentupdate",
188 "Toggle whether agentupdate packets are processed or simply discarded.",
189 HandleAgentUpdateCommand);
190
191 MainConsole.Instance.Commands.AddCommand(
192 "Debug",
193 false,
194 "debug lludp oqre",
195 "debug lludp oqre <start|stop|status>",
196 "Start, stop or get status of OutgoingQueueRefillEngine.",
197 "If stopped then refill requests are processed directly via the threadpool.",
198 HandleOqreCommand);
199
200 m_console.Commands.AddCommand(
201 "Debug",
202 false,
203 "debug lludp client get",
204 "debug lludp client get [<avatar-first-name> <avatar-last-name>]",
205 "Get debug parameters for the client. If no name is given then all client information is returned.",
206 "process-unacked-sends - Do we take action if a sent reliable packet has not been acked.",
207 HandleClientGetCommand);
208
209 m_console.Commands.AddCommand(
210 "Debug",
211 false,
212 "debug lludp client set",
213 "debug lludp client set <param> <value> [<avatar-first-name> <avatar-last-name>]",
214 "Set a debug parameter for a particular client. If no name is given then the value is set on all clients.",
215 "process-unacked-sends - Do we take action if a sent reliable packet has not been acked.",
216 HandleClientSetCommand);
217*/
218 }
219
220 private void HandleShowServerThrottlesCommand(string module, string[] args)
221 {
222 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
223 return;
224
225 m_console.OutputFormat("Throttles for {0}", m_udpServer.Scene.Name);
226 ConsoleDisplayList cdl = new ConsoleDisplayList();
227 cdl.AddRow("Adaptive throttles", m_udpServer.ThrottleRates.AdaptiveThrottlesEnabled);
228
229 long maxSceneDripRate = (long)m_udpServer.Throttle.MaxDripRate;
230 cdl.AddRow(
231 "Max scene throttle",
232 maxSceneDripRate != 0 ? string.Format("{0} kbps", maxSceneDripRate * 8 / 1000) : "unset");
233
234 int maxClientDripRate = m_udpServer.ThrottleRates.Total;
235 cdl.AddRow(
236 "Max new client throttle",
237 maxClientDripRate != 0 ? string.Format("{0} kbps", maxClientDripRate * 8 / 1000) : "unset");
238
239 m_console.Output(cdl.ToString());
240
241 m_console.OutputFormat("{0}\n", GetServerThrottlesReport(m_udpServer));
242 }
243
244 private string GetServerThrottlesReport(LLUDPServer udpServer)
245 {
246 StringBuilder report = new StringBuilder();
247
248 report.AppendFormat(
249 "{0,7} {1,8} {2,7} {3,7} {4,7} {5,7} {6,9} {7,7}\n",
250 "Total",
251 "Resend",
252 "Land",
253 "Wind",
254 "Cloud",
255 "Task",
256 "Texture",
257 "Asset");
258
259 report.AppendFormat(
260 "{0,7} {1,8} {2,7} {3,7} {4,7} {5,7} {6,9} {7,7}\n",
261 "kb/s",
262 "kb/s",
263 "kb/s",
264 "kb/s",
265 "kb/s",
266 "kb/s",
267 "kb/s",
268 "kb/s");
269
270 ThrottleRates throttleRates = udpServer.ThrottleRates;
271 report.AppendFormat(
272 "{0,7} {1,8} {2,7} {3,7} {4,7} {5,7} {6,9} {7,7}",
273 (throttleRates.Total * 8) / 1000,
274 (throttleRates.Resend * 8) / 1000,
275 (throttleRates.Land * 8) / 1000,
276 (throttleRates.Wind * 8) / 1000,
277 (throttleRates.Cloud * 8) / 1000,
278 (throttleRates.Task * 8) / 1000,
279 (throttleRates.Texture * 8) / 1000,
280 (throttleRates.Asset * 8) / 1000);
281
282 return report.ToString();
283 }
284
285 protected string GetColumnEntry(string entry, int maxLength, int columnPadding)
286 {
287 return string.Format(
288 "{0,-" + maxLength + "}{1,-" + columnPadding + "}",
289 entry.Length > maxLength ? entry.Substring(0, maxLength) : entry,
290 "");
291 }
292
293 private void HandleDataCommand(string module, string[] args)
294 {
295 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
296 return;
297
298 if (args.Length != 7)
299 {
300 MainConsole.Instance.OutputFormat("Usage: debug lludp data out <true|false> <avatar-first-name> <avatar-last-name>");
301 return;
302 }
303
304 int level;
305 if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[4], out level))
306 return;
307
308 string firstName = args[5];
309 string lastName = args[6];
310
311 m_udpServer.Scene.ForEachScenePresence(sp =>
312 {
313 if (sp.Firstname == firstName && sp.Lastname == lastName)
314 {
315 MainConsole.Instance.OutputFormat(
316 "Data debug for {0} ({1}) set to {2} in {3}",
317 sp.Name, sp.IsChildAgent ? "child" : "root", level, m_udpServer.Scene.Name);
318
319 ((LLClientView)sp.ControllingClient).UDPClient.DebugDataOutLevel = level;
320 }
321 });
322 }
323
324 private void HandleThrottleCommand(string module, string[] args)
325 {
326 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
327 return;
328
329 bool all = args.Length == 5;
330 bool one = args.Length == 7;
331
332 if (!all && !one)
333 {
334 MainConsole.Instance.OutputFormat(
335 "Usage: debug lludp throttles log <level> [<avatar-first-name> <avatar-last-name>]");
336 return;
337 }
338
339 int level;
340 if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[4], out level))
341 return;
342
343 string firstName = null;
344 string lastName = null;
345
346 if (one)
347 {
348 firstName = args[5];
349 lastName = args[6];
350 }
351
352 m_udpServer.Scene.ForEachScenePresence(sp =>
353 {
354 if (all || (sp.Firstname == firstName && sp.Lastname == lastName))
355 {
356 MainConsole.Instance.OutputFormat(
357 "Throttle log level for {0} ({1}) set to {2} in {3}",
358 sp.Name, sp.IsChildAgent ? "child" : "root", level, m_udpServer.Scene.Name);
359
360 ((LLClientView)sp.ControllingClient).UDPClient.ThrottleDebugLevel = level;
361 }
362 });
363 }
364
365 private void HandleThrottleSetCommand(string module, string[] args)
366 {
367 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
368 return;
369
370 bool all = args.Length == 6;
371 bool one = args.Length == 8;
372
373 if (!all && !one)
374 {
375 MainConsole.Instance.OutputFormat(
376 "Usage: debug lludp throttles set <param> <value> [<avatar-first-name> <avatar-last-name>]");
377 return;
378 }
379
380 string param = args[4];
381 string rawValue = args[5];
382
383 string firstName = null;
384 string lastName = null;
385
386 if (one)
387 {
388 firstName = args[6];
389 lastName = args[7];
390 }
391
392 if (param == "adaptive")
393 {
394 bool newValue;
395 if (!ConsoleUtil.TryParseConsoleBool(MainConsole.Instance, rawValue, out newValue))
396 return;
397
398 m_udpServer.Scene.ForEachScenePresence(sp =>
399 {
400 if (all || (sp.Firstname == firstName && sp.Lastname == lastName))
401 {
402 MainConsole.Instance.OutputFormat(
403 "Setting param {0} to {1} for {2} ({3}) in {4}",
404 param, newValue, sp.Name, sp.IsChildAgent ? "child" : "root", m_udpServer.Scene.Name);
405
406 LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
407 udpClient.FlowThrottle.AdaptiveEnabled = newValue;
408 // udpClient.FlowThrottle.MaxDripRate = 0;
409 // udpClient.FlowThrottle.AdjustedDripRate = 0;
410 }
411 });
412 }
413 else if (param == "request")
414 {
415 int newValue;
416 if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, rawValue, out newValue))
417 return;
418
419 int newCurrentThrottleKbps = newValue * 1000 / 8;
420
421 m_udpServer.Scene.ForEachScenePresence(sp =>
422 {
423 if (all || (sp.Firstname == firstName && sp.Lastname == lastName))
424 {
425 MainConsole.Instance.OutputFormat(
426 "Setting param {0} to {1} for {2} ({3}) in {4}",
427 param, newValue, sp.Name, sp.IsChildAgent ? "child" : "root", m_udpServer.Scene.Name);
428
429 LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
430 udpClient.FlowThrottle.RequestedDripRate = newCurrentThrottleKbps;
431 }
432 });
433 }
434 else if (param == "max")
435 {
436 int newValue;
437 if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, rawValue, out newValue))
438 return;
439
440 int newThrottleMaxKbps = newValue * 1000 / 8;
441
442 m_udpServer.Scene.ForEachScenePresence(sp =>
443 {
444 if (all || (sp.Firstname == firstName && sp.Lastname == lastName))
445 {
446 MainConsole.Instance.OutputFormat(
447 "Setting param {0} to {1} for {2} ({3}) in {4}",
448 param, newValue, sp.Name, sp.IsChildAgent ? "child" : "root", m_udpServer.Scene.Name);
449
450 LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
451 udpClient.FlowThrottle.MaxDripRate = newThrottleMaxKbps;
452 }
453 });
454 }
455 }
456
457 private void HandleThrottleGetCommand(string module, string[] args)
458 {
459 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
460 return;
461
462 bool all = args.Length == 4;
463 bool one = args.Length == 6;
464
465 if (!all && !one)
466 {
467 MainConsole.Instance.OutputFormat(
468 "Usage: debug lludp throttles get [<avatar-first-name> <avatar-last-name>]");
469 return;
470 }
471
472 string firstName = null;
473 string lastName = null;
474
475 if (one)
476 {
477 firstName = args[4];
478 lastName = args[5];
479 }
480
481 m_udpServer.Scene.ForEachScenePresence(sp =>
482 {
483 if (all || (sp.Firstname == firstName && sp.Lastname == lastName))
484 {
485 m_console.OutputFormat(
486 "Status for {0} ({1}) in {2}",
487 sp.Name, sp.IsChildAgent ? "child" : "root", m_udpServer.Scene.Name);
488
489 LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
490
491 ConsoleDisplayList cdl = new ConsoleDisplayList();
492 cdl.AddRow("adaptive", udpClient.FlowThrottle.AdaptiveEnabled);
493 cdl.AddRow("current", string.Format("{0} kbps", udpClient.FlowThrottle.DripRate * 8 / 1000));
494 cdl.AddRow("request", string.Format("{0} kbps", udpClient.FlowThrottle.RequestedDripRate * 8 / 1000));
495 cdl.AddRow("max", string.Format("{0} kbps", udpClient.FlowThrottle.MaxDripRate * 8 / 1000));
496
497 m_console.Output(cdl.ToString());
498 }
499 });
500 }
501
502 private void HandleGetCommand(string module, string[] args)
503 {
504 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
505 return;
506
507 m_console.OutputFormat("Debug settings for {0}", m_udpServer.Scene.Name);
508 ConsoleDisplayList cdl = new ConsoleDisplayList();
509
510 long maxSceneDripRate = (long)m_udpServer.Throttle.MaxDripRate;
511 cdl.AddRow(
512 "max-scene-throttle",
513 maxSceneDripRate != 0 ? string.Format("{0} kbps", maxSceneDripRate * 8 / 1000) : "unset");
514
515 int maxClientDripRate = m_udpServer.ThrottleRates.Total;
516 cdl.AddRow(
517 "max-new-client-throttle",
518 maxClientDripRate != 0 ? string.Format("{0} kbps", maxClientDripRate * 8 / 1000) : "unset");
519
520 m_console.Output(cdl.ToString());
521 }
522
523 private void HandleSetCommand(string module, string[] args)
524 {
525 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
526 return;
527
528 if (args.Length != 5)
529 {
530 MainConsole.Instance.OutputFormat("Usage: debug lludp set <param> <value>");
531 return;
532 }
533
534 string param = args[3];
535 string rawValue = args[4];
536
537 int newValue;
538
539 if (param == "max-scene-throttle")
540 {
541 if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, rawValue, out newValue))
542 return;
543
544 m_udpServer.Throttle.MaxDripRate = newValue * 1000 / 8;
545 }
546 else if (param == "max-new-client-throttle")
547 {
548 if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, rawValue, out newValue))
549 return;
550
551 m_udpServer.ThrottleRates.Total = newValue * 1000 / 8;
552 }
553 else
554 {
555 return;
556 }
557
558 m_console.OutputFormat("{0} set to {1} in {2}", param, rawValue, m_udpServer.Scene.Name);
559 }
560
561/* not in use, nothing to set/get from lludp
562 private void HandleClientGetCommand(string module, string[] args)
563 {
564 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
565 return;
566
567 if (args.Length != 4 && args.Length != 6)
568 {
569 MainConsole.Instance.OutputFormat("Usage: debug lludp client get [<avatar-first-name> <avatar-last-name>]");
570 return;
571 }
572
573 string name = null;
574
575 if (args.Length == 6)
576 name = string.Format("{0} {1}", args[4], args[5]);
577
578 m_udpServer.Scene.ForEachScenePresence(
579 sp =>
580 {
581 if ((name == null || sp.Name == name) && sp.ControllingClient is LLClientView)
582 {
583 LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
584
585 m_console.OutputFormat(
586 "Client debug parameters for {0} ({1}) in {2}",
587 sp.Name, sp.IsChildAgent ? "child" : "root", m_udpServer.Scene.Name);
588 }
589 });
590 }
591
592 private void HandleClientSetCommand(string module, string[] args)
593 {
594 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
595 return;
596
597 if (args.Length != 6 && args.Length != 8)
598 {
599 MainConsole.Instance.OutputFormat("Usage: debug lludp client set <param> <value> [<avatar-first-name> <avatar-last-name>]");
600 return;
601 }
602
603 string param = args[4];
604 string rawValue = args[5];
605
606 string name = null;
607
608 if (args.Length == 8)
609 name = string.Format("{0} {1}", args[6], args[7]);
610 // nothing here now
611 }
612*/
613 private void HandlePacketCommand(string module, string[] args)
614 {
615 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
616 return;
617
618 bool setAsDefaultLevel = false;
619 bool setAll = false;
620 OptionSet optionSet = new OptionSet()
621 .Add("default", o => setAsDefaultLevel = (o != null))
622 .Add("all", o => setAll = (o != null));
623 List<string> filteredArgs = optionSet.Parse(args);
624
625 string name = null;
626
627 if (filteredArgs.Count == 6)
628 {
629 if (!(setAsDefaultLevel || setAll))
630 {
631 name = string.Format("{0} {1}", filteredArgs[4], filteredArgs[5]);
632 }
633 else
634 {
635 MainConsole.Instance.OutputFormat("ERROR: Cannot specify a user name when setting default/all logging level");
636 return;
637 }
638 }
639
640 if (filteredArgs.Count > 3)
641 {
642 int newDebug;
643 if (int.TryParse(filteredArgs[3], out newDebug))
644 {
645 if (setAsDefaultLevel || setAll)
646 {
647 m_udpServer.DefaultClientPacketDebugLevel = newDebug;
648
649 MainConsole.Instance.OutputFormat(
650 "Packet debug for {0} clients set to {1} in {2}",
651 (setAll ? "all" : "future"), m_udpServer.DefaultClientPacketDebugLevel, m_udpServer.Scene.Name);
652
653 if (setAll)
654 {
655 m_udpServer.Scene.ForEachScenePresence(sp =>
656 {
657 MainConsole.Instance.OutputFormat(
658 "Packet debug for {0} ({1}) set to {2} in {3}",
659 sp.Name, sp.IsChildAgent ? "child" : "root", newDebug, m_udpServer.Scene.Name);
660
661 sp.ControllingClient.DebugPacketLevel = newDebug;
662 });
663 }
664 }
665 else
666 {
667 m_udpServer.Scene.ForEachScenePresence(sp =>
668 {
669 if (name == null || sp.Name == name)
670 {
671 MainConsole.Instance.OutputFormat(
672 "Packet debug for {0} ({1}) set to {2} in {3}",
673 sp.Name, sp.IsChildAgent ? "child" : "root", newDebug, m_udpServer.Scene.Name);
674
675 sp.ControllingClient.DebugPacketLevel = newDebug;
676 }
677 });
678 }
679 }
680 else
681 {
682 MainConsole.Instance.Output("Usage: debug lludp packet [--default | --all] 0..255 [<first-name> <last-name>]");
683 }
684 }
685 }
686
687 private void HandleDropCommand(string module, string[] args)
688 {
689 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
690 return;
691
692 if (args.Length != 6)
693 {
694 MainConsole.Instance.Output("Usage: debug lludp drop <in|out> <add|remove> <packet-name>");
695 return;
696 }
697
698 string direction = args[3];
699 string subCommand = args[4];
700 string packetName = args[5];
701
702 if (subCommand == "add")
703 {
704 MainConsole.Instance.OutputFormat(
705 "Adding packet {0} to {1} drop list for all connections in {2}",
706 direction, packetName, m_udpServer.Scene.Name);
707
708 m_udpServer.Scene.ForEachScenePresence(
709 sp =>
710 {
711 LLClientView llcv = (LLClientView)sp.ControllingClient;
712
713 if (direction == "in")
714 llcv.AddInPacketToDropSet(packetName);
715 else if (direction == "out")
716 llcv.AddOutPacketToDropSet(packetName);
717 }
718 );
719 }
720 else if (subCommand == "remove")
721 {
722 MainConsole.Instance.OutputFormat(
723 "Removing packet {0} from {1} drop list for all connections in {2}",
724 direction, packetName, m_udpServer.Scene.Name);
725
726 m_udpServer.Scene.ForEachScenePresence(
727 sp =>
728 {
729 LLClientView llcv = (LLClientView)sp.ControllingClient;
730
731 if (direction == "in")
732 llcv.RemoveInPacketFromDropSet(packetName);
733 else if (direction == "out")
734 llcv.RemoveOutPacketFromDropSet(packetName);
735 }
736 );
737 }
738 }
739
740 private void HandleStartCommand(string module, string[] args)
741 {
742 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
743 return;
744
745 if (args.Length != 4)
746 {
747 MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>");
748 return;
749 }
750
751 string subCommand = args[3];
752
753 if (subCommand == "in" || subCommand == "all")
754 m_udpServer.StartInbound();
755
756 if (subCommand == "out" || subCommand == "all")
757 m_udpServer.StartOutbound();
758 }
759
760 private void HandleStopCommand(string module, string[] args)
761 {
762 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
763 return;
764
765 if (args.Length != 4)
766 {
767 MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>");
768 return;
769 }
770
771 string subCommand = args[3];
772
773 if (subCommand == "in" || subCommand == "all")
774 m_udpServer.StopInbound();
775
776 if (subCommand == "out" || subCommand == "all")
777 m_udpServer.StopOutbound();
778 }
779
780 private void HandlePoolCommand(string module, string[] args)
781 {
782 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
783 return;
784
785 if (args.Length != 4)
786 {
787 MainConsole.Instance.Output("Usage: debug lludp pool <on|off>");
788 return;
789 }
790
791 string enabled = args[3];
792
793 if (enabled == "on")
794 {
795 if (m_udpServer.EnablePools())
796 {
797 m_udpServer.EnablePoolStats();
798 MainConsole.Instance.OutputFormat("Packet pools enabled on {0}", m_udpServer.Scene.Name);
799 }
800 }
801 else if (enabled == "off")
802 {
803 if (m_udpServer.DisablePools())
804 {
805 m_udpServer.DisablePoolStats();
806 MainConsole.Instance.OutputFormat("Packet pools disabled on {0}", m_udpServer.Scene.Name);
807 }
808 }
809 else
810 {
811 MainConsole.Instance.Output("Usage: debug lludp pool <on|off>");
812 }
813 }
814
815 private void HandleAgentUpdateCommand(string module, string[] args)
816 {
817 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
818 return;
819
820 m_udpServer.DiscardInboundAgentUpdates = !m_udpServer.DiscardInboundAgentUpdates;
821
822 MainConsole.Instance.OutputFormat(
823 "Discard AgentUpdates now {0} for {1}", m_udpServer.DiscardInboundAgentUpdates, m_udpServer.Scene.Name);
824 }
825
826 private void HandleStatusCommand(string module, string[] args)
827 {
828 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
829 return;
830
831 MainConsole.Instance.OutputFormat(
832 "IN LLUDP packet processing for {0} is {1}", m_udpServer.Scene.Name, m_udpServer.IsRunningInbound ? "enabled" : "disabled");
833
834 MainConsole.Instance.OutputFormat(
835 "OUT LLUDP packet processing for {0} is {1}", m_udpServer.Scene.Name, m_udpServer.IsRunningOutbound ? "enabled" : "disabled");
836
837 MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_udpServer.Scene.Name, m_udpServer.UsePools ? "on" : "off");
838
839 MainConsole.Instance.OutputFormat(
840 "Packet debug level for new clients is {0}", m_udpServer.DefaultClientPacketDebugLevel);
841 }
842
843 private void HandleOqreCommand(string module, string[] args)
844 {
845 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
846 return;
847
848 if (args.Length != 4)
849 {
850 MainConsole.Instance.Output("Usage: debug lludp oqre <stop|start|status>");
851 return;
852 }
853
854 string subCommand = args[3];
855
856 if (subCommand == "stop")
857 {
858 m_udpServer.OqrEngine.Stop();
859 MainConsole.Instance.OutputFormat("Stopped OQRE for {0}", m_udpServer.Scene.Name);
860 }
861 else if (subCommand == "start")
862 {
863 m_udpServer.OqrEngine.Start();
864 MainConsole.Instance.OutputFormat("Started OQRE for {0}", m_udpServer.Scene.Name);
865 }
866 else if (subCommand == "status")
867 {
868 MainConsole.Instance.OutputFormat("OQRE in {0}", m_udpServer.Scene.Name);
869 MainConsole.Instance.OutputFormat("Running: {0}", m_udpServer.OqrEngine.IsRunning);
870 MainConsole.Instance.OutputFormat(
871 "Requests waiting: {0}",
872 m_udpServer.OqrEngine.IsRunning ? m_udpServer.OqrEngine.JobsWaiting.ToString() : "n/a");
873 }
874 else
875 {
876 MainConsole.Instance.OutputFormat("Unrecognized OQRE subcommand {0}", subCommand);
877 }
878 }
879 }
880} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
new file mode 100644
index 0000000..f362b06
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
@@ -0,0 +1,535 @@
1/*
2 * Copyright (c) 2006, Clutch, Inc.
3 * Original Author: Jeff Cesnik
4 * All rights reserved.
5 *
6 * - Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * - Redistributions of source code must retain the above copyright notice, this
10 * list of conditions and the following disclaimer.
11 * - Neither the name of the openmetaverse.org nor the names
12 * of its contributors may be used to endorse or promote products derived from
13 * this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Net;
30using System.Net.Sockets;
31using System.Threading;
32using log4net;
33using OpenSim.Framework;
34using OpenSim.Framework.Monitoring;
35
36namespace OpenMetaverse
37{
38 /// <summary>
39 /// Base UDP server
40 /// </summary>
41 public abstract class OpenSimUDPBase
42 {
43 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
44
45 /// <summary>
46 /// This method is called when an incoming packet is received
47 /// </summary>
48 /// <param name="buffer">Incoming packet buffer</param>
49 public abstract void PacketReceived(UDPPacketBuffer buffer);
50
51 /// <summary>UDP port to bind to in server mode</summary>
52 protected int m_udpPort;
53
54 /// <summary>Local IP address to bind to in server mode</summary>
55 protected IPAddress m_localBindAddress;
56
57 /// <summary>UDP socket, used in either client or server mode</summary>
58 private Socket m_udpSocket;
59
60 /// <summary>
61 /// Are we to use object pool(s) to reduce memory churn when receiving data?
62 /// </summary>
63 public bool UsePools { get; protected set; }
64
65 /// <summary>
66 /// Pool to use for handling data. May be null if UsePools = false;
67 /// </summary>
68 protected OpenSim.Framework.Pool<UDPPacketBuffer> Pool { get; private set; }
69
70 /// <summary>Returns true if the server is currently listening for inbound packets, otherwise false</summary>
71 public bool IsRunningInbound { get; private set; }
72
73 /// <summary>Returns true if the server is currently sending outbound packets, otherwise false</summary>
74 /// <remarks>If IsRunningOut = false, then any request to send a packet is simply dropped.</remarks>
75 public bool IsRunningOutbound { get; private set; }
76
77 /// <summary>
78 /// Number of UDP receives.
79 /// </summary>
80 public int UdpReceives { get; private set; }
81
82 /// <summary>
83 /// Number of UDP sends
84 /// </summary>
85 public int UdpSends { get; private set; }
86
87 /// <summary>
88 /// Number of receives over which to establish a receive time average.
89 /// </summary>
90 private readonly static int s_receiveTimeSamples = 500;
91
92 /// <summary>
93 /// Current number of samples taken to establish a receive time average.
94 /// </summary>
95 private int m_currentReceiveTimeSamples;
96
97 /// <summary>
98 /// Cumulative receive time for the sample so far.
99 /// </summary>
100 private int m_receiveTicksInCurrentSamplePeriod;
101
102 /// <summary>
103 /// The average time taken for each require receive in the last sample.
104 /// </summary>
105 public float AverageReceiveTicksForLastSamplePeriod { get; private set; }
106
107 public int Port
108 {
109 get { return m_udpPort; }
110 }
111
112 #region PacketDropDebugging
113 /// <summary>
114 /// For debugging purposes only... random number generator for dropping
115 /// outbound packets.
116 /// </summary>
117 private Random m_dropRandomGenerator = new Random();
118
119 /// <summary>
120 /// For debugging purposes only... parameters for a simplified
121 /// model of packet loss with bursts, overall drop rate should
122 /// be roughly 1 - m_dropLengthProbability / (m_dropProbabiliy + m_dropLengthProbability)
123 /// which is about 1% for parameters 0.0015 and 0.15
124 /// </summary>
125 private double m_dropProbability = 0.0030;
126 private double m_dropLengthProbability = 0.15;
127 private bool m_dropState = false;
128
129 /// <summary>
130 /// For debugging purposes only... parameters to control the time
131 /// duration over which packet loss bursts can occur, if no packets
132 /// have been sent for m_dropResetTicks milliseconds, then reset the
133 /// state of the packet dropper to its default.
134 /// </summary>
135 private int m_dropLastTick = 0;
136 private int m_dropResetTicks = 500;
137
138 /// <summary>
139 /// Debugging code used to simulate dropped packets with bursts
140 /// </summary>
141 private bool DropOutgoingPacket()
142 {
143 double rnum = m_dropRandomGenerator.NextDouble();
144
145 // if the connection has been idle for awhile (more than m_dropResetTicks) then
146 // reset the state to the default state, don't continue a burst
147 int curtick = Util.EnvironmentTickCount();
148 if (Util.EnvironmentTickCountSubtract(curtick, m_dropLastTick) > m_dropResetTicks)
149 m_dropState = false;
150
151 m_dropLastTick = curtick;
152
153 // if we are dropping packets, then the probability of dropping
154 // this packet is the probability that we stay in the burst
155 if (m_dropState)
156 {
157 m_dropState = (rnum < (1.0 - m_dropLengthProbability)) ? true : false;
158 }
159 else
160 {
161 m_dropState = (rnum < m_dropProbability) ? true : false;
162 }
163
164 return m_dropState;
165 }
166 #endregion PacketDropDebugging
167
168 /// <summary>
169 /// Default constructor
170 /// </summary>
171 /// <param name="bindAddress">Local IP address to bind the server to</param>
172 /// <param name="port">Port to listening for incoming UDP packets on</param>
173 /// /// <param name="usePool">Are we to use an object pool to get objects for handing inbound data?</param>
174 public OpenSimUDPBase(IPAddress bindAddress, int port)
175 {
176 m_localBindAddress = bindAddress;
177 m_udpPort = port;
178
179 // for debugging purposes only, initializes the random number generator
180 // used for simulating packet loss
181 // m_dropRandomGenerator = new Random();
182 }
183
184 ~OpenSimUDPBase()
185 {
186 if(m_udpSocket !=null)
187 try { m_udpSocket.Close(); } catch { }
188 }
189 /// <summary>
190 /// Start inbound UDP packet handling.
191 /// </summary>
192 /// <param name="recvBufferSize">The size of the receive buffer for
193 /// the UDP socket. This value is passed up to the operating system
194 /// and used in the system networking stack. Use zero to leave this
195 /// value as the default</param>
196 /// <param name="asyncPacketHandling">Set this to true to start
197 /// receiving more packets while current packet handler callbacks are
198 /// still running. Setting this to false will complete each packet
199 /// callback before the next packet is processed</param>
200 /// <remarks>This method will attempt to set the SIO_UDP_CONNRESET flag
201 /// on the socket to get newer versions of Windows to behave in a sane
202 /// manner (not throwing an exception when the remote side resets the
203 /// connection). This call is ignored on Mono where the flag is not
204 /// necessary</remarks>
205 public virtual void StartInbound(int recvBufferSize)
206 {
207 if (!IsRunningInbound)
208 {
209 m_log.DebugFormat("[UDPBASE]: Starting inbound UDP loop");
210
211 const int SIO_UDP_CONNRESET = -1744830452;
212
213 IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort);
214
215 m_udpSocket = new Socket(
216 AddressFamily.InterNetwork,
217 SocketType.Dgram,
218 ProtocolType.Udp);
219
220 try
221 {
222 if (m_udpSocket.Ttl < 128)
223 {
224 m_udpSocket.Ttl = 128;
225 }
226 }
227 catch (SocketException)
228 {
229 m_log.Debug("[UDPBASE]: Failed to increase default TTL");
230 }
231
232 try
233 {
234 // This udp socket flag is not supported under mono,
235 // so we'll catch the exception and continue
236 // Try does not protect some mono versions on mac
237 if(Util.IsWindows())
238 {
239 m_udpSocket.IOControl(SIO_UDP_CONNRESET, new byte[] { 0 }, null);
240 m_log.Debug("[UDPBASE]: SIO_UDP_CONNRESET flag set");
241 }
242 else
243 {
244 m_log.Debug("[UDPBASE]: SIO_UDP_CONNRESET flag not supported on this platform, ignoring");
245 }
246 }
247 catch
248 {
249 m_log.Debug("[UDPBASE]: SIO_UDP_CONNRESET flag not supported on this platform, ignoring");
250 }
251
252 // On at least Mono 3.2.8, multiple UDP sockets can bind to the same port by default. At the moment
253 // we never want two regions to listen on the same port as they cannot demultiplex each other's messages,
254 // leading to a confusing bug.
255 // By default, Windows does not allow two sockets to bind to the same port.
256 //
257 // Unfortunately, this also causes a crashed sim to leave the socket in a state
258 // where it appears to be in use but is really just hung from the old process
259 // crashing rather than closing it. While this protects agains misconfiguration,
260 // allowing crashed sims to be started up again right away, rather than having to
261 // wait 2 minutes for the socket to clear is more valuable. Commented 12/13/2016
262 // m_udpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false);
263
264 if (recvBufferSize != 0)
265 m_udpSocket.ReceiveBufferSize = recvBufferSize;
266
267 m_udpSocket.Bind(ipep);
268
269 if (m_udpPort == 0)
270 m_udpPort = ((IPEndPoint)m_udpSocket.LocalEndPoint).Port;
271
272 IsRunningInbound = true;
273
274 // kick off an async receive. The Start() method will return, the
275 // actual receives will occur asynchronously and will be caught in
276 // AsyncEndRecieve().
277 AsyncBeginReceive();
278 }
279 }
280
281 /// <summary>
282 /// Start outbound UDP packet handling.
283 /// </summary>
284 public virtual void StartOutbound()
285 {
286 m_log.DebugFormat("[UDPBASE]: Starting outbound UDP loop");
287
288 IsRunningOutbound = true;
289 }
290
291 public virtual void StopInbound()
292 {
293 if (IsRunningInbound)
294 {
295 m_log.DebugFormat("[UDPBASE]: Stopping inbound UDP loop");
296
297 IsRunningInbound = false;
298 m_udpSocket.Close();
299 }
300 }
301
302 public virtual void StopOutbound()
303 {
304 m_log.DebugFormat("[UDPBASE]: Stopping outbound UDP loop");
305
306 IsRunningOutbound = false;
307 }
308
309 public virtual bool EnablePools()
310 {
311 if (!UsePools)
312 {
313 Pool = new Pool<UDPPacketBuffer>(() => new UDPPacketBuffer(), 500);
314
315 UsePools = true;
316
317 return true;
318 }
319
320 return false;
321 }
322
323 public virtual bool DisablePools()
324 {
325 if (UsePools)
326 {
327 UsePools = false;
328
329 // We won't null out the pool to avoid a race condition with code that may be in the middle of using it.
330
331 return true;
332 }
333
334 return false;
335 }
336
337 private void AsyncBeginReceive()
338 {
339 UDPPacketBuffer buf;
340
341 // FIXME: Disabled for now as this causes issues with reused packet objects interfering with each other
342 // on Windows with m_asyncPacketHandling = true, though this has not been seen on Linux.
343 // Possibly some unexpected issue with fetching UDP data concurrently with multiple threads. Requires more investigation.
344// if (UsePools)
345// buf = Pool.GetObject();
346// else
347 buf = new UDPPacketBuffer();
348
349 if (IsRunningInbound)
350 {
351 try
352 {
353 // kick off an async read
354 m_udpSocket.BeginReceiveFrom(
355 //wrappedBuffer.Instance.Data,
356 buf.Data,
357 0,
358 UDPPacketBuffer.BUFFER_SIZE,
359 SocketFlags.None,
360 ref buf.RemoteEndPoint,
361 AsyncEndReceive,
362 //wrappedBuffer);
363 buf);
364 }
365 catch (SocketException e)
366 {
367 if (e.SocketErrorCode == SocketError.ConnectionReset)
368 {
369 m_log.Warn("[UDPBASE]: SIO_UDP_CONNRESET was ignored, attempting to salvage the UDP listener on port " + m_udpPort);
370 bool salvaged = false;
371 while (!salvaged)
372 {
373 try
374 {
375 m_udpSocket.BeginReceiveFrom(
376 //wrappedBuffer.Instance.Data,
377 buf.Data,
378 0,
379 UDPPacketBuffer.BUFFER_SIZE,
380 SocketFlags.None,
381 ref buf.RemoteEndPoint,
382 AsyncEndReceive,
383 //wrappedBuffer);
384 buf);
385 salvaged = true;
386 }
387 catch (SocketException) { }
388 catch (ObjectDisposedException) { return; }
389 }
390
391 m_log.Warn("[UDPBASE]: Salvaged the UDP listener on port " + m_udpPort);
392 }
393 }
394 catch (ObjectDisposedException e)
395 {
396 m_log.Error(
397 string.Format("[UDPBASE]: Error processing UDP begin receive {0}. Exception ", UdpReceives), e);
398 }
399 catch (Exception e)
400 {
401 m_log.Error(
402 string.Format("[UDPBASE]: Error processing UDP begin receive {0}. Exception ", UdpReceives), e);
403 }
404 }
405 }
406
407 private void AsyncEndReceive(IAsyncResult iar)
408 {
409 // Asynchronous receive operations will complete here through the call
410 // to AsyncBeginReceive
411 if (IsRunningInbound)
412 {
413 UdpReceives++;
414
415 try
416 {
417 // get the buffer that was created in AsyncBeginReceive
418 // this is the received data
419 UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState;
420
421 int startTick = Util.EnvironmentTickCount();
422
423 // get the length of data actually read from the socket, store it with the
424 // buffer
425 buffer.DataLength = m_udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint);
426
427 // call the abstract method PacketReceived(), passing the buffer that
428 // has just been filled from the socket read.
429 PacketReceived(buffer);
430
431 // If more than one thread can be calling AsyncEndReceive() at once (e.g. if m_asyncPacketHandler)
432 // then a particular stat may be inaccurate due to a race condition. We won't worry about this
433 // since this should be rare and won't cause a runtime problem.
434 if (m_currentReceiveTimeSamples >= s_receiveTimeSamples)
435 {
436 AverageReceiveTicksForLastSamplePeriod
437 = (float)m_receiveTicksInCurrentSamplePeriod / s_receiveTimeSamples;
438
439 m_receiveTicksInCurrentSamplePeriod = 0;
440 m_currentReceiveTimeSamples = 0;
441 }
442 else
443 {
444 m_receiveTicksInCurrentSamplePeriod += Util.EnvironmentTickCountSubtract(startTick);
445 m_currentReceiveTimeSamples++;
446 }
447 }
448 catch (SocketException se)
449 {
450 m_log.Error(
451 string.Format(
452 "[UDPBASE]: Error processing UDP end receive {0}, socket error code {1}. Exception ",
453 UdpReceives, se.ErrorCode),
454 se);
455 }
456 catch (ObjectDisposedException e)
457 {
458 m_log.Error(
459 string.Format("[UDPBASE]: Error processing UDP end receive {0}. Exception ", UdpReceives), e);
460 }
461 catch (Exception e)
462 {
463 m_log.Error(
464 string.Format("[UDPBASE]: Error processing UDP end receive {0}. Exception ", UdpReceives), e);
465 }
466 finally
467 {
468// if (UsePools)
469// Pool.ReturnObject(buffer);
470
471 AsyncBeginReceive();
472 }
473 }
474 }
475
476 public void AsyncBeginSend(UDPPacketBuffer buf)
477 {
478// if (IsRunningOutbound)
479// {
480
481 // This is strictly for debugging purposes to simulate dropped
482 // packets when testing throttles & retransmission code
483 // if (DropOutgoingPacket())
484 // return;
485
486 try
487 {
488 m_udpSocket.BeginSendTo(
489 buf.Data,
490 0,
491 buf.DataLength,
492 SocketFlags.None,
493 buf.RemoteEndPoint,
494 AsyncEndSend,
495 buf);
496 }
497 catch (SocketException) { }
498 catch (ObjectDisposedException) { }
499 // }
500 }
501
502 void AsyncEndSend(IAsyncResult result)
503 {
504 try
505 {
506// UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState;
507 m_udpSocket.EndSendTo(result);
508
509 UdpSends++;
510 }
511 catch (SocketException) { }
512 catch (ObjectDisposedException) { }
513 }
514
515 public void SyncSend(UDPPacketBuffer buf)
516 {
517 try
518 {
519 m_udpSocket.SendTo(
520 buf.Data,
521 0,
522 buf.DataLength,
523 SocketFlags.None,
524 buf.RemoteEndPoint
525 );
526 UdpSends++;
527 }
528 catch (SocketException e)
529 {
530 m_log.Warn("[UDPBASE]: sync send SocketException {0} " + e.Message);
531 }
532 catch (ObjectDisposedException) { }
533 }
534 }
535}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OutgoingPacket.cs b/OpenSim/Region/ClientStack/Linden/UDP/OutgoingPacket.cs
new file mode 100644
index 0000000..76c6c14
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/OutgoingPacket.cs
@@ -0,0 +1,75 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using OpenSim.Framework;
30using OpenMetaverse;
31
32namespace OpenSim.Region.ClientStack.LindenUDP
33{
34
35 public delegate void UnackedPacketMethod(OutgoingPacket oPacket);
36 /// <summary>
37 /// Holds a reference to the <seealso cref="LLUDPClient"/> this packet is
38 /// destined for, along with the serialized packet data, sequence number
39 /// (if this is a resend), number of times this packet has been resent,
40 /// the time of the last resend, and the throttling category for this
41 /// packet
42 /// </summary>
43 public sealed class OutgoingPacket
44 {
45 /// <summary>Client this packet is destined for</summary>
46 public LLUDPClient Client;
47 /// <summary>Packet data to send</summary>
48 public UDPPacketBuffer Buffer;
49 /// <summary>Sequence number of the wrapped packet</summary>
50 public uint SequenceNumber;
51 /// <summary>Number of times this packet has been resent</summary>
52 public int ResendCount;
53 /// <summary>Environment.TickCount when this packet was last sent over the wire</summary>
54 public int TickCount;
55 /// <summary>Category this packet belongs to</summary>
56 public ThrottleOutPacketType Category;
57 /// <summary>The delegate to be called if this packet is determined to be unacknowledged</summary>
58 public UnackedPacketMethod UnackedMethod;
59
60 /// <summary>
61 /// Default constructor
62 /// </summary>
63 /// <param name="client">Reference to the client this packet is destined for</param>
64 /// <param name="buffer">Serialized packet data. If the flags or sequence number
65 /// need to be updated, they will be injected directly into this binary buffer</param>
66 /// <param name="category">Throttling category for this packet</param>
67 public OutgoingPacket(LLUDPClient client, UDPPacketBuffer buffer, ThrottleOutPacketType category, UnackedPacketMethod method)
68 {
69 Client = client;
70 Buffer = buffer;
71 Category = category;
72 UnackedMethod = method;
73 }
74 }
75}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
new file mode 100644
index 0000000..f585bea
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
@@ -0,0 +1,299 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using OpenMetaverse;
32using OpenMetaverse.Packets;
33using log4net;
34using OpenSim.Framework.Monitoring;
35
36namespace OpenSim.Region.ClientStack.LindenUDP
37{
38 public sealed class PacketPool
39 {
40 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
41
42 private static readonly PacketPool instance = new PacketPool();
43
44 /// <summary>
45 /// Pool of packets available for reuse.
46 /// </summary>
47 private readonly Dictionary<PacketType, Stack<Packet>> pool = new Dictionary<PacketType, Stack<Packet>>();
48
49 private static Dictionary<Type, Stack<Object>> DataBlocks = new Dictionary<Type, Stack<Object>>();
50
51 public static PacketPool Instance
52 {
53 get { return instance; }
54 }
55
56 public bool RecyclePackets { get; set; }
57
58 public bool RecycleDataBlocks { get; set; }
59
60 /// <summary>
61 /// The number of packets pooled
62 /// </summary>
63 public int PacketsPooled
64 {
65 get
66 {
67 lock (pool)
68 return pool.Count;
69 }
70 }
71
72 /// <summary>
73 /// The number of blocks pooled.
74 /// </summary>
75 public int BlocksPooled
76 {
77 get
78 {
79 lock (DataBlocks)
80 return DataBlocks.Count;
81 }
82 }
83
84 /// <summary>
85 /// Number of packets requested.
86 /// </summary>
87 public long PacketsRequested { get; private set; }
88
89 /// <summary>
90 /// Number of packets reused.
91 /// </summary>
92 public long PacketsReused { get; private set; }
93
94 /// <summary>
95 /// Number of packet blocks requested.
96 /// </summary>
97 public long BlocksRequested { get; private set; }
98
99 /// <summary>
100 /// Number of packet blocks reused.
101 /// </summary>
102 public long BlocksReused { get; private set; }
103
104 private PacketPool()
105 {
106 // defaults
107 RecyclePackets = true;
108 RecycleDataBlocks = true;
109 }
110
111 /// <summary>
112 /// Gets a packet of the given type.
113 /// </summary>
114 /// <param name='type'></param>
115 /// <returns>Guaranteed to always return a packet, whether from the pool or newly constructed.</returns>
116 public Packet GetPacket(PacketType type)
117 {
118 PacketsRequested++;
119
120 Packet packet;
121
122 if (!RecyclePackets)
123 return Packet.BuildPacket(type);
124
125 lock (pool)
126 {
127 if (!pool.ContainsKey(type) || pool[type] == null || (pool[type]).Count == 0)
128 {
129// m_log.DebugFormat("[PACKETPOOL]: Building {0} packet", type);
130
131 // Creating a new packet if we cannot reuse an old package
132 packet = Packet.BuildPacket(type);
133 }
134 else
135 {
136// m_log.DebugFormat("[PACKETPOOL]: Pulling {0} packet", type);
137
138 // Recycle old packages
139 PacketsReused++;
140
141 packet = pool[type].Pop();
142 }
143 }
144
145 return packet;
146 }
147
148 private static PacketType GetType(byte[] bytes)
149 {
150 ushort id;
151 PacketFrequency freq;
152 bool isZeroCoded = (bytes[0] & Helpers.MSG_ZEROCODED) != 0;
153
154 if (bytes[6] == 0xFF)
155 {
156 if (bytes[7] == 0xFF)
157 {
158 freq = PacketFrequency.Low;
159 if (isZeroCoded && bytes[8] == 0)
160 id = bytes[10];
161 else
162 id = (ushort)((bytes[8] << 8) + bytes[9]);
163 }
164 else
165 {
166 freq = PacketFrequency.Medium;
167 id = bytes[7];
168 }
169 }
170 else
171 {
172 freq = PacketFrequency.High;
173 id = bytes[6];
174 }
175
176 return Packet.GetType(id, freq);
177 }
178
179 public Packet GetPacket(byte[] bytes, ref int packetEnd, byte[] zeroBuffer)
180 {
181 PacketType type = GetType(bytes);
182
183// Array.Clear(zeroBuffer, 0, zeroBuffer.Length);
184
185 int i = 0;
186 Packet packet = GetPacket(type);
187 if (packet == null)
188 m_log.WarnFormat("[PACKETPOOL]: Failed to get packet of type {0}", type);
189 else
190 packet.FromBytes(bytes, ref i, ref packetEnd, zeroBuffer);
191
192 return packet;
193 }
194
195 /// <summary>
196 /// Return a packet to the packet pool
197 /// </summary>
198 /// <param name="packet"></param>
199 public void ReturnPacket(Packet packet)
200 {
201 if (RecycleDataBlocks)
202 {
203 switch (packet.Type)
204 {
205 case PacketType.ObjectUpdate:
206 ObjectUpdatePacket oup = (ObjectUpdatePacket)packet;
207
208 foreach (ObjectUpdatePacket.ObjectDataBlock oupod in oup.ObjectData)
209 ReturnDataBlock<ObjectUpdatePacket.ObjectDataBlock>(oupod);
210
211 oup.ObjectData = null;
212 break;
213
214 case PacketType.ImprovedTerseObjectUpdate:
215 ImprovedTerseObjectUpdatePacket itoup = (ImprovedTerseObjectUpdatePacket)packet;
216
217 foreach (ImprovedTerseObjectUpdatePacket.ObjectDataBlock itoupod in itoup.ObjectData)
218 ReturnDataBlock<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>(itoupod);
219
220 itoup.ObjectData = null;
221 break;
222 }
223 }
224
225 if (RecyclePackets)
226 {
227 switch (packet.Type)
228 {
229 // List pooling packets here
230 case PacketType.AgentUpdate:
231 case PacketType.PacketAck:
232 case PacketType.ObjectUpdate:
233 case PacketType.ImprovedTerseObjectUpdate:
234 lock (pool)
235 {
236 PacketType type = packet.Type;
237
238 if (!pool.ContainsKey(type))
239 {
240 pool[type] = new Stack<Packet>();
241 }
242
243 if ((pool[type]).Count < 50)
244 {
245// m_log.DebugFormat("[PACKETPOOL]: Pushing {0} packet", type);
246
247 pool[type].Push(packet);
248 }
249 }
250 break;
251
252 // Other packets wont pool
253 default:
254 return;
255 }
256 }
257 }
258
259 public T GetDataBlock<T>() where T: new()
260 {
261 lock (DataBlocks)
262 {
263 BlocksRequested++;
264
265 Stack<Object> s;
266
267 if (DataBlocks.TryGetValue(typeof(T), out s))
268 {
269 if (s.Count > 0)
270 {
271 BlocksReused++;
272 return (T)s.Pop();
273 }
274 }
275 else
276 {
277 DataBlocks[typeof(T)] = new Stack<Object>();
278 }
279
280 return new T();
281 }
282 }
283
284 public void ReturnDataBlock<T>(T block) where T: new()
285 {
286 if (block == null)
287 return;
288
289 lock (DataBlocks)
290 {
291 if (!DataBlocks.ContainsKey(typeof(T)))
292 DataBlocks[typeof(T)] = new Stack<Object>();
293
294 if (DataBlocks[typeof(T)].Count < 50)
295 DataBlocks[typeof(T)].Push(block);
296 }
297 }
298 }
299} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs b/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..4a8f16d
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
1using System.Reflection;
2using System.Runtime.CompilerServices;
3using System.Runtime.InteropServices;
4using Mono.Addins;
5
6// General Information about an assembly is controlled through the following
7// set of attributes. Change these attribute values to modify the information
8// associated with an assembly.
9[assembly: AssemblyTitle("OpenSim.Region.ClientStack.LindenUDP")]
10[assembly: AssemblyDescription("")]
11[assembly: AssemblyConfiguration("")]
12[assembly: AssemblyCompany("http://opensimulator.org")]
13[assembly: AssemblyProduct("OpenSim")]
14[assembly: AssemblyCopyright("OpenSimulator developers")]
15[assembly: AssemblyTrademark("")]
16[assembly: AssemblyCulture("")]
17
18// Setting ComVisible to false makes the types in this assembly not visible
19// to COM components. If you need to access a type in this assembly from
20// COM, set the ComVisible attribute to true on that type.
21[assembly: ComVisible(false)]
22
23// The following GUID is for the ID of the typelib if this project is exposed to COM
24[assembly: Guid("9d3dbc6b-9d85-483b-af48-c1dfc261b7ac")]
25
26// Version information for an assembly consists of the following four values:
27//
28// Major Version
29// Minor Version
30// Build Number
31// Revision
32//
33[assembly: AssemblyVersion(OpenSim.VersionInfo.AssemblyVersionNumber)]
34
35[assembly: Addin("LindenUDP", OpenSim.VersionInfo.VersionNumber)]
36[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs
new file mode 100644
index 0000000..eb262d2
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs
@@ -0,0 +1,273 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Net;
30using log4net.Config;
31using Nini.Config;
32using NUnit.Framework;
33using OpenMetaverse;
34using OpenMetaverse.Packets;
35using OpenSim.Framework;
36using OpenSim.Framework.Monitoring;
37using OpenSim.Region.Framework.Scenes;
38using OpenSim.Tests.Common;
39
40namespace OpenSim.Region.ClientStack.LindenUDP.Tests
41{
42 /// <summary>
43 /// This will contain basic tests for the LindenUDP client stack
44 /// </summary>
45 [TestFixture]
46 public class BasicCircuitTests : OpenSimTestCase
47 {
48 private Scene m_scene;
49
50 [TestFixtureSetUp]
51 public void FixtureInit()
52 {
53 // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
54 Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest;
55 }
56
57 [TestFixtureTearDown]
58 public void TearDown()
59 {
60 // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
61 // threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression
62 // tests really shouldn't).
63 Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
64 }
65
66 [SetUp]
67 public override void SetUp()
68 {
69 base.SetUp();
70 m_scene = new SceneHelpers().SetupScene();
71 StatsManager.SimExtraStats = new SimExtraStatsCollector();
72 }
73
74// /// <summary>
75// /// Build an object name packet for test purposes
76// /// </summary>
77// /// <param name="objectLocalId"></param>
78// /// <param name="objectName"></param>
79// private ObjectNamePacket BuildTestObjectNamePacket(uint objectLocalId, string objectName)
80// {
81// ObjectNamePacket onp = new ObjectNamePacket();
82// ObjectNamePacket.ObjectDataBlock odb = new ObjectNamePacket.ObjectDataBlock();
83// odb.LocalID = objectLocalId;
84// odb.Name = Utils.StringToBytes(objectName);
85// onp.ObjectData = new ObjectNamePacket.ObjectDataBlock[] { odb };
86// onp.Header.Zerocoded = false;
87//
88// return onp;
89// }
90//
91 /// <summary>
92 /// Test adding a client to the stack
93 /// </summary>
94/*
95 [Test]
96 public void TestAddClient()
97 {
98 TestHelpers.InMethod();
99// TestHelpers.EnableLogging();
100
101 TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(m_scene);
102
103 UUID myAgentUuid = TestHelpers.ParseTail(0x1);
104 UUID mySessionUuid = TestHelpers.ParseTail(0x2);
105 uint myCircuitCode = 123456;
106 IPEndPoint testEp = new IPEndPoint(IPAddress.Loopback, 999);
107
108 UseCircuitCodePacket uccp = new UseCircuitCodePacket();
109
110 UseCircuitCodePacket.CircuitCodeBlock uccpCcBlock
111 = new UseCircuitCodePacket.CircuitCodeBlock();
112 uccpCcBlock.Code = myCircuitCode;
113 uccpCcBlock.ID = myAgentUuid;
114 uccpCcBlock.SessionID = mySessionUuid;
115 uccp.CircuitCode = uccpCcBlock;
116
117 byte[] uccpBytes = uccp.ToBytes();
118 UDPPacketBuffer upb = new UDPPacketBuffer(testEp, uccpBytes.Length);
119 upb.DataLength = uccpBytes.Length; // God knows why this isn't set by the constructor.
120 Buffer.BlockCopy(uccpBytes, 0, upb.Data, 0, uccpBytes.Length);
121
122 udpServer.PacketReceived(upb);
123
124 // Presence shouldn't exist since the circuit manager doesn't know about this circuit for authentication yet
125 Assert.That(m_scene.GetScenePresence(myAgentUuid), Is.Null);
126
127 AgentCircuitData acd = new AgentCircuitData();
128 acd.AgentID = myAgentUuid;
129 acd.SessionID = mySessionUuid;
130
131 m_scene.AuthenticateHandler.AddNewCircuit(myCircuitCode, acd);
132
133 udpServer.PacketReceived(upb);
134
135 // Should succeed now
136 ScenePresence sp = m_scene.GetScenePresence(myAgentUuid);
137 Assert.That(sp.UUID, Is.EqualTo(myAgentUuid));
138
139 Assert.That(udpServer.PacketsSent.Count, Is.EqualTo(1));
140
141 Packet packet = udpServer.PacketsSent[0];
142 Assert.That(packet, Is.InstanceOf(typeof(PacketAckPacket)));
143
144 PacketAckPacket ackPacket = packet as PacketAckPacket;
145 Assert.That(ackPacket.Packets.Length, Is.EqualTo(1));
146 Assert.That(ackPacket.Packets[0].ID, Is.EqualTo(0));
147 }
148
149 [Test]
150 public void TestLogoutClientDueToAck()
151 {
152 TestHelpers.InMethod();
153// TestHelpers.EnableLogging();
154
155 IniConfigSource ics = new IniConfigSource();
156 IConfig config = ics.AddConfig("ClientStack.LindenUDP");
157 config.Set("AckTimeout", -1);
158 TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(m_scene, ics);
159
160 ScenePresence sp
161 = ClientStackHelpers.AddChildClient(
162 m_scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456);
163
164 udpServer.ClientOutgoingPacketHandler(sp.ControllingClient, true, false, false);
165
166 ScenePresence spAfterAckTimeout = m_scene.GetScenePresence(sp.UUID);
167 Assert.That(spAfterAckTimeout, Is.Null);
168 }
169*/
170// /// <summary>
171// /// Test removing a client from the stack
172// /// </summary>
173// [Test]
174// public void TestRemoveClient()
175// {
176// TestHelper.InMethod();
177//
178// uint myCircuitCode = 123457;
179//
180// TestLLUDPServer testLLUDPServer;
181// TestLLPacketServer testLLPacketServer;
182// AgentCircuitManager acm;
183// SetupStack(new MockScene(), out testLLUDPServer, out testLLPacketServer, out acm);
184// AddClient(myCircuitCode, new IPEndPoint(IPAddress.Loopback, 1000), testLLUDPServer, acm);
185//
186// testLLUDPServer.RemoveClientCircuit(myCircuitCode);
187// Assert.IsFalse(testLLUDPServer.HasCircuit(myCircuitCode));
188//
189// // Check that removing a non-existent circuit doesn't have any bad effects
190// testLLUDPServer.RemoveClientCircuit(101);
191// Assert.IsFalse(testLLUDPServer.HasCircuit(101));
192// }
193//
194// /// <summary>
195// /// Make sure that the client stack reacts okay to malformed packets
196// /// </summary>
197// [Test]
198// public void TestMalformedPacketSend()
199// {
200// TestHelper.InMethod();
201//
202// uint myCircuitCode = 123458;
203// EndPoint testEp = new IPEndPoint(IPAddress.Loopback, 1001);
204// MockScene scene = new MockScene();
205//
206// TestLLUDPServer testLLUDPServer;
207// TestLLPacketServer testLLPacketServer;
208// AgentCircuitManager acm;
209// SetupStack(scene, out testLLUDPServer, out testLLPacketServer, out acm);
210// AddClient(myCircuitCode, testEp, testLLUDPServer, acm);
211//
212// byte[] data = new byte[] { 0x01, 0x02, 0x03, 0x04 };
213//
214// // Send two garbled 'packets' in succession
215// testLLUDPServer.LoadReceive(data, testEp);
216// testLLUDPServer.LoadReceive(data, testEp);
217// testLLUDPServer.ReceiveData(null);
218//
219// // Check that we are still here
220// Assert.IsTrue(testLLUDPServer.HasCircuit(myCircuitCode));
221// Assert.That(testLLPacketServer.GetTotalPacketsReceived(), Is.EqualTo(0));
222//
223// // Check that sending a valid packet to same circuit still succeeds
224// Assert.That(scene.ObjectNameCallsReceived, Is.EqualTo(0));
225//
226// testLLUDPServer.LoadReceive(BuildTestObjectNamePacket(1, "helloooo"), testEp);
227// testLLUDPServer.ReceiveData(null);
228//
229// Assert.That(testLLPacketServer.GetTotalPacketsReceived(), Is.EqualTo(1));
230// Assert.That(testLLPacketServer.GetPacketsReceivedFor(PacketType.ObjectName), Is.EqualTo(1));
231// }
232//
233// /// <summary>
234// /// Test that the stack continues to work even if some client has caused a
235// /// SocketException on Socket.BeginReceive()
236// /// </summary>
237// [Test]
238// public void TestExceptionOnBeginReceive()
239// {
240// TestHelper.InMethod();
241//
242// MockScene scene = new MockScene();
243//
244// uint circuitCodeA = 130000;
245// EndPoint epA = new IPEndPoint(IPAddress.Loopback, 1300);
246// UUID agentIdA = UUID.Parse("00000000-0000-0000-0000-000000001300");
247// UUID sessionIdA = UUID.Parse("00000000-0000-0000-0000-000000002300");
248//
249// uint circuitCodeB = 130001;
250// EndPoint epB = new IPEndPoint(IPAddress.Loopback, 1301);
251// UUID agentIdB = UUID.Parse("00000000-0000-0000-0000-000000001301");
252// UUID sessionIdB = UUID.Parse("00000000-0000-0000-0000-000000002301");
253//
254// TestLLUDPServer testLLUDPServer;
255// TestLLPacketServer testLLPacketServer;
256// AgentCircuitManager acm;
257// SetupStack(scene, out testLLUDPServer, out testLLPacketServer, out acm);
258// AddClient(circuitCodeA, epA, agentIdA, sessionIdA, testLLUDPServer, acm);
259// AddClient(circuitCodeB, epB, agentIdB, sessionIdB, testLLUDPServer, acm);
260//
261// testLLUDPServer.LoadReceive(BuildTestObjectNamePacket(1, "packet1"), epA);
262// testLLUDPServer.LoadReceive(BuildTestObjectNamePacket(1, "packet2"), epB);
263// testLLUDPServer.LoadReceiveWithBeginException(epA);
264// testLLUDPServer.LoadReceive(BuildTestObjectNamePacket(2, "packet3"), epB);
265// testLLUDPServer.ReceiveData(null);
266//
267// Assert.IsFalse(testLLUDPServer.HasCircuit(circuitCodeA));
268//
269// Assert.That(testLLPacketServer.GetTotalPacketsReceived(), Is.EqualTo(3));
270// Assert.That(testLLPacketServer.GetPacketsReceivedFor(PacketType.ObjectName), Is.EqualTo(3));
271// }
272 }
273}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs
new file mode 100644
index 0000000..6c57e6d
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs
@@ -0,0 +1,174 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.IO;
30using System.Net;
31using System.Reflection;
32using System.Threading;
33using log4net.Config;
34using Nini.Config;
35using NUnit.Framework;
36using OpenMetaverse;
37using OpenMetaverse.Packets;
38using OpenSim.Framework;
39using OpenSim.Region.CoreModules.Agent.TextureSender;
40using OpenSim.Region.Framework.Scenes;
41using OpenSim.Tests.Common;
42
43namespace OpenSim.Region.ClientStack.LindenUDP.Tests
44{
45 [TestFixture]
46 public class LLImageManagerTests : OpenSimTestCase
47 {
48 private AssetBase m_testImageAsset;
49 private Scene scene;
50 private LLImageManager llim;
51 private TestClient tc;
52
53 [TestFixtureSetUp]
54 public void FixtureInit()
55 {
56 // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
57 Util.FireAndForgetMethod = FireAndForgetMethod.None;
58
59 using (
60 Stream resource
61 = GetType().Assembly.GetManifestResourceStream(
62 "OpenSim.Region.ClientStack.LindenUDP.Tests.Resources.4-tile2.jp2"))
63 {
64 using (BinaryReader br = new BinaryReader(resource))
65 {
66 m_testImageAsset
67 = new AssetBase(
68 TestHelpers.ParseTail(0x1),
69 "Test Image",
70 (sbyte)AssetType.Texture,
71 TestHelpers.ParseTail(0x2).ToString());
72
73 m_testImageAsset.Data = br.ReadBytes(99999999);
74 }
75 }
76 }
77
78 [TestFixtureTearDown]
79 public void TearDown()
80 {
81 // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
82 // threads. Possibly, later tests should be rewritten not to worry about such things.
83 Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
84 }
85
86 [SetUp]
87 public override void SetUp()
88 {
89 base.SetUp();
90
91 UUID userId = TestHelpers.ParseTail(0x3);
92
93 J2KDecoderModule j2kdm = new J2KDecoderModule();
94
95 SceneHelpers sceneHelpers = new SceneHelpers();
96 scene = sceneHelpers.SetupScene();
97 SceneHelpers.SetupSceneModules(scene, j2kdm);
98
99 tc = new TestClient(SceneHelpers.GenerateAgentData(userId), scene);
100 llim = new LLImageManager(tc, scene.AssetService, j2kdm);
101 }
102
103 [Test]
104 public void TestSendImage()
105 {
106 TestHelpers.InMethod();
107// XmlConfigurator.Configure();
108
109 scene.AssetService.Store(m_testImageAsset);
110
111 TextureRequestArgs args = new TextureRequestArgs();
112 args.RequestedAssetID = m_testImageAsset.FullID;
113 args.DiscardLevel = 0;
114 args.PacketNumber = 1;
115 args.Priority = 5;
116 args.requestSequence = 1;
117
118 llim.EnqueueReq(args);
119 llim.ProcessImageQueue(20);
120
121 Assert.That(tc.SentImageDataPackets.Count, Is.EqualTo(1));
122 }
123
124 [Test]
125 public void TestDiscardImage()
126 {
127 TestHelpers.InMethod();
128// XmlConfigurator.Configure();
129
130 scene.AssetService.Store(m_testImageAsset);
131
132 TextureRequestArgs args = new TextureRequestArgs();
133 args.RequestedAssetID = m_testImageAsset.FullID;
134 args.DiscardLevel = 0;
135 args.PacketNumber = 1;
136 args.Priority = 5;
137 args.requestSequence = 1;
138 llim.EnqueueReq(args);
139
140 // Now create a discard request
141 TextureRequestArgs discardArgs = new TextureRequestArgs();
142 discardArgs.RequestedAssetID = m_testImageAsset.FullID;
143 discardArgs.DiscardLevel = -1;
144 discardArgs.PacketNumber = 1;
145 discardArgs.Priority = 0;
146 discardArgs.requestSequence = 2;
147 llim.EnqueueReq(discardArgs);
148
149 llim.ProcessImageQueue(20);
150
151 Assert.That(tc.SentImageDataPackets.Count, Is.EqualTo(0));
152 }
153
154 [Test]
155 public void TestMissingImage()
156 {
157 TestHelpers.InMethod();
158// XmlConfigurator.Configure();
159
160 TextureRequestArgs args = new TextureRequestArgs();
161 args.RequestedAssetID = m_testImageAsset.FullID;
162 args.DiscardLevel = 0;
163 args.PacketNumber = 1;
164 args.Priority = 5;
165 args.requestSequence = 1;
166
167 llim.EnqueueReq(args);
168 llim.ProcessImageQueue(20);
169
170 Assert.That(tc.SentImageDataPackets.Count, Is.EqualTo(0));
171 Assert.That(tc.SentImageNotInDatabasePackets.Count, Is.EqualTo(1));
172 }
173 }
174} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs
new file mode 100644
index 0000000..1731aa9
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs
@@ -0,0 +1,104 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using Nini.Config;
29using NUnit.Framework;
30using OpenMetaverse;
31using OpenMetaverse.Packets;
32using OpenSim.Framework;
33using OpenSim.Tests.Common;
34
35namespace OpenSim.Region.ClientStack.LindenUDP.Tests
36{
37 /// <summary>
38 /// Tests for the LL packet handler
39 /// </summary>
40 [TestFixture]
41 public class PacketHandlerTests : OpenSimTestCase
42 {
43// [Test]
44// /// <summary>
45// /// More a placeholder, really
46// /// </summary>
47// public void InPacketTest()
48// {
49// TestHelper.InMethod();
50//
51// AgentCircuitData agent = new AgentCircuitData();
52// agent.AgentID = UUID.Random();
53// agent.firstname = "testfirstname";
54// agent.lastname = "testlastname";
55// agent.SessionID = UUID.Zero;
56// agent.SecureSessionID = UUID.Zero;
57// agent.circuitcode = 123;
58// agent.BaseFolder = UUID.Zero;
59// agent.InventoryFolder = UUID.Zero;
60// agent.startpos = Vector3.Zero;
61// agent.CapsPath = "http://wibble.com";
62//
63// TestLLUDPServer testLLUDPServer;
64// TestLLPacketServer testLLPacketServer;
65// AgentCircuitManager acm;
66// IScene scene = new MockScene();
67// SetupStack(scene, out testLLUDPServer, out testLLPacketServer, out acm);
68//
69// TestClient testClient = new TestClient(agent, scene);
70//
71// LLPacketHandler packetHandler
72// = new LLPacketHandler(testClient, testLLPacketServer, new ClientStackUserSettings());
73//
74// packetHandler.InPacket(new AgentAnimationPacket());
75// LLQueItem receivedPacket = packetHandler.PacketQueue.Dequeue();
76//
77// Assert.That(receivedPacket, Is.Not.Null);
78// Assert.That(receivedPacket.Incoming, Is.True);
79// Assert.That(receivedPacket.Packet, Is.TypeOf(typeof(AgentAnimationPacket)));
80// }
81//
82// /// <summary>
83// /// Add a client for testing
84// /// </summary>
85// /// <param name="scene"></param>
86// /// <param name="testLLUDPServer"></param>
87// /// <param name="testPacketServer"></param>
88// /// <param name="acm">Agent circuit manager used in setting up the stack</param>
89// protected void SetupStack(
90// IScene scene, out TestLLUDPServer testLLUDPServer, out TestLLPacketServer testPacketServer,
91// out AgentCircuitManager acm)
92// {
93// IConfigSource configSource = new IniConfigSource();
94// ClientStackUserSettings userSettings = new ClientStackUserSettings();
95// testLLUDPServer = new TestLLUDPServer();
96// acm = new AgentCircuitManager();
97//
98// uint port = 666;
99// testLLUDPServer.Initialise(null, ref port, 0, false, configSource, acm);
100// testPacketServer = new TestLLPacketServer(testLLUDPServer, userSettings);
101// testLLUDPServer.LocalScene = scene;
102// }
103 }
104}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/Resources/4-tile2.jp2 b/OpenSim/Region/ClientStack/Linden/UDP/Tests/Resources/4-tile2.jp2
new file mode 100644
index 0000000..8c63104
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/Resources/4-tile2.jp2
Binary files differ
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs
new file mode 100644
index 0000000..873b1e5
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs
@@ -0,0 +1,432 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using Nini.Config;
30using NUnit.Framework;
31using OpenMetaverse.Packets;
32using OpenSim.Framework;
33using OpenSim.Region.Framework.Scenes;
34using OpenSim.Tests.Common;
35
36namespace OpenSim.Region.ClientStack.LindenUDP.Tests
37{
38 /*
39 [TestFixture]
40 public class ThrottleTests : OpenSimTestCase
41 {
42 [TestFixtureSetUp]
43 public void FixtureInit()
44 {
45 // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
46 Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest;
47 }
48
49 [TestFixtureTearDown]
50 public void TearDown()
51 {
52 // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
53 // threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression
54 // tests really shouldn't).
55 Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
56 }
57
58 [Test]
59 public void TestSetRequestDripRate()
60 {
61
62 TestHelpers.InMethod();
63
64 TokenBucket tb = new TokenBucket(null, 5000f,10000f);
65 AssertRates(tb, 5000, 0, 5000, 0);
66
67 tb.RequestedDripRate = 4000f;
68 AssertRates(tb, 4000, 0, 4000, 0);
69
70 tb.RequestedDripRate = 6000;
71 AssertRates(tb, 6000, 0, 6000, 0);
72
73 }
74
75 [Test]
76 public void TestSetRequestDripRateWithMax()
77 {
78 TestHelpers.InMethod();
79
80 TokenBucket tb = new TokenBucket(null, 5000,15000);
81 AssertRates(tb, 5000, 0, 5000, 10000);
82
83 tb.RequestedDripRate = 4000;
84 AssertRates(tb, 4000, 0, 4000, 10000);
85
86 tb.RequestedDripRate = 6000;
87 AssertRates(tb, 6000, 0, 6000, 10000);
88
89 tb.RequestedDripRate = 12000;
90 AssertRates(tb, 10000, 0, 10000, 10000);
91 }
92
93 [Test]
94 public void TestSetRequestDripRateWithChildren()
95 {
96 TestHelpers.InMethod();
97
98 TokenBucket tbParent = new TokenBucket("tbParent", null, 0);
99 TokenBucket tbChild1 = new TokenBucket("tbChild1", tbParent, 3000);
100 TokenBucket tbChild2 = new TokenBucket("tbChild2", tbParent, 5000);
101
102 AssertRates(tbParent, 8000, 8000, 8000, 0);
103 AssertRates(tbChild1, 3000, 0, 3000, 0);
104 AssertRates(tbChild2, 5000, 0, 5000, 0);
105
106 // Test: Setting a parent request greater than total children requests.
107 tbParent.RequestedDripRate = 10000;
108
109 AssertRates(tbParent, 10000, 8000, 8000, 0);
110 AssertRates(tbChild1, 3000, 0, 3000, 0);
111 AssertRates(tbChild2, 5000, 0, 5000, 0);
112
113 // Test: Setting a parent request lower than total children requests.
114 tbParent.RequestedDripRate = 6000;
115
116 AssertRates(tbParent, 6000, 8000, 6000, 0);
117 AssertRates(tbChild1, 3000, 0, 6000 / 8 * 3, 0);
118 AssertRates(tbChild2, 5000, 0, 6000 / 8 * 5, 0);
119
120 }
121
122 private void AssertRates(
123 TokenBucket tb, double requestedDripRate, double totalDripRequest, double dripRate, double maxDripRate)
124 {
125 Assert.AreEqual((int)requestedDripRate, tb.RequestedDripRate, "Requested drip rate");
126 Assert.AreEqual((int)totalDripRequest, tb.TotalDripRequest, "Total drip request");
127 Assert.AreEqual((int)dripRate, tb.DripRate, "Drip rate");
128 Assert.AreEqual((int)maxDripRate, tb.MaxDripRate, "Max drip rate");
129 }
130
131 [Test]
132 public void TestClientThrottleSetNoLimit()
133 {
134 TestHelpers.InMethod();
135// TestHelpers.EnableLogging();
136
137 Scene scene = new SceneHelpers().SetupScene();
138 TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene);
139
140 ScenePresence sp
141 = ClientStackHelpers.AddChildClient(
142 scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456);
143
144 LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
145
146 udpServer.Throttle.DebugLevel = 1;
147 udpClient.ThrottleDebugLevel = 1;
148
149 int resendBytes = 1000;
150 int landBytes = 2000;
151 int windBytes = 3000;
152 int cloudBytes = 4000;
153 int taskBytes = 5000;
154 int textureBytes = 6000;
155 int assetBytes = 7000;
156
157 SetThrottles(
158 udpClient, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes);
159
160 // We expect this to be lower because of the minimum bound set by MTU
161 int totalBytes = LLUDPServer.MTU + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes;
162
163 AssertThrottles(
164 udpClient,
165 LLUDPServer.MTU, landBytes, windBytes, cloudBytes, taskBytes,
166 textureBytes, assetBytes, totalBytes, 0, 0);
167 }
168
169 [Test]
170 public void TestClientThrottleAdaptiveNoLimit()
171 {
172 TestHelpers.InMethod();
173// TestHelpers.EnableLogging();
174
175 Scene scene = new SceneHelpers().SetupScene();
176
177 IniConfigSource ics = new IniConfigSource();
178 IConfig config = ics.AddConfig("ClientStack.LindenUDP");
179 config.Set("enable_adaptive_throttles", true);
180 config.Set("adaptive_throttle_min_bps", 32000);
181
182 TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene, ics);
183
184 ScenePresence sp
185 = ClientStackHelpers.AddChildClient(
186 scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456);
187
188 LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
189
190 udpServer.Throttle.DebugLevel = 1;
191 udpClient.ThrottleDebugLevel = 1;
192
193 // Total is 275000
194 int resendBytes = 5000; // this is set low to test the minimum throttle override
195 int landBytes = 20000;
196 int windBytes = 30000;
197 int cloudBytes = 40000;
198 int taskBytes = 50000;
199 int textureBytes = 60000;
200 int assetBytes = 70000;
201 int totalBytes = resendBytes + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes;
202
203 SetThrottles(
204 udpClient, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes);
205
206 // Ratio of current adaptive drip rate to requested bytes, minimum rate is 32000
207 double commitRatio = 32000.0 / totalBytes;
208
209 AssertThrottles(
210 udpClient,
211 LLUDPServer.MTU, landBytes * commitRatio, windBytes * commitRatio, cloudBytes * commitRatio, taskBytes * commitRatio,
212 textureBytes * commitRatio, assetBytes * commitRatio, udpClient.FlowThrottle.AdjustedDripRate, totalBytes, 0);
213
214 // Test an increase in target throttle, ack of 20 packets adds 20 * LLUDPServer.MTU bytes
215 // to the throttle, recompute commitratio from those numbers
216 udpClient.FlowThrottle.AcknowledgePackets(20);
217 commitRatio = (32000.0 + 20.0 * LLUDPServer.MTU) / totalBytes;
218
219 AssertThrottles(
220 udpClient,
221 LLUDPServer.MTU, landBytes * commitRatio, windBytes * commitRatio, cloudBytes * commitRatio, taskBytes * commitRatio,
222 textureBytes * commitRatio, assetBytes * commitRatio, udpClient.FlowThrottle.AdjustedDripRate, totalBytes, 0);
223
224 // Test a decrease in target throttle, adaptive throttle should cut the rate by 50% with a floor
225 // set by the minimum adaptive rate
226 udpClient.FlowThrottle.ExpirePackets(1);
227 commitRatio = (32000.0 + (20.0 * LLUDPServer.MTU)/Math.Pow(2,1)) / totalBytes;
228
229 AssertThrottles(
230 udpClient,
231 LLUDPServer.MTU, landBytes * commitRatio, windBytes * commitRatio, cloudBytes * commitRatio, taskBytes * commitRatio,
232 textureBytes * commitRatio, assetBytes * commitRatio, udpClient.FlowThrottle.AdjustedDripRate, totalBytes, 0);
233 }
234
235 /// <summary>
236 /// Test throttle setttings where max client throttle has been limited server side.
237 /// </summary>
238 [Test]
239 public void TestSingleClientThrottleRegionLimited()
240 {
241 TestHelpers.InMethod();
242 // TestHelpers.EnableLogging();
243
244 int resendBytes = 6000;
245 int landBytes = 8000;
246 int windBytes = 10000;
247 int cloudBytes = 12000;
248 int taskBytes = 14000;
249 int textureBytes = 16000;
250 int assetBytes = 18000;
251 int totalBytes
252 = (int)((resendBytes + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes) / 2);
253
254 Scene scene = new SceneHelpers().SetupScene();
255 TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene);
256 udpServer.Throttle.RequestedDripRate = totalBytes;
257
258 ScenePresence sp1
259 = ClientStackHelpers.AddChildClient(
260 scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456);
261
262 LLUDPClient udpClient1 = ((LLClientView)sp1.ControllingClient).UDPClient;
263
264 SetThrottles(
265 udpClient1, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes);
266
267 AssertThrottles(
268 udpClient1,
269 resendBytes / 2, landBytes / 2, windBytes / 2, cloudBytes / 2, taskBytes / 2,
270 textureBytes / 2, assetBytes / 2, totalBytes, 0, 0);
271
272 // Test: Now add another client
273 ScenePresence sp2
274 = ClientStackHelpers.AddChildClient(
275 scene, udpServer, TestHelpers.ParseTail(0x10), TestHelpers.ParseTail(0x20), 123457);
276
277 LLUDPClient udpClient2 = ((LLClientView)sp2.ControllingClient).UDPClient;
278 // udpClient.ThrottleDebugLevel = 1;
279
280 SetThrottles(
281 udpClient2, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes);
282
283 AssertThrottles(
284 udpClient1,
285 resendBytes / 4, landBytes / 4, windBytes / 4, cloudBytes / 4, taskBytes / 4,
286 textureBytes / 4, assetBytes / 4, totalBytes / 2, 0, 0);
287
288 AssertThrottles(
289 udpClient2,
290 resendBytes / 4, landBytes / 4, windBytes / 4, cloudBytes / 4, taskBytes / 4,
291 textureBytes / 4, assetBytes / 4, totalBytes / 2, 0, 0);
292 }
293
294 /// <summary>
295 /// Test throttle setttings where max client throttle has been limited server side.
296 /// </summary>
297 [Test]
298 public void TestClientThrottlePerClientLimited()
299 {
300 TestHelpers.InMethod();
301 // TestHelpers.EnableLogging();
302
303 int resendBytes = 4000;
304 int landBytes = 6000;
305 int windBytes = 8000;
306 int cloudBytes = 10000;
307 int taskBytes = 12000;
308 int textureBytes = 14000;
309 int assetBytes = 16000;
310 int totalBytes
311 = (int)((resendBytes + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes) / 2);
312
313 Scene scene = new SceneHelpers().SetupScene();
314 TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene);
315 udpServer.ThrottleRates.Total = totalBytes;
316
317 ScenePresence sp
318 = ClientStackHelpers.AddChildClient(
319 scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456);
320
321 LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
322 // udpClient.ThrottleDebugLevel = 1;
323
324 SetThrottles(
325 udpClient, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes);
326
327 AssertThrottles(
328 udpClient,
329 resendBytes / 2, landBytes / 2, windBytes / 2, cloudBytes / 2, taskBytes / 2,
330 textureBytes / 2, assetBytes / 2, totalBytes, 0, totalBytes);
331 }
332
333 [Test]
334 public void TestClientThrottlePerClientAndRegionLimited()
335 {
336 TestHelpers.InMethod();
337 //TestHelpers.EnableLogging();
338
339 int resendBytes = 4000;
340 int landBytes = 6000;
341 int windBytes = 8000;
342 int cloudBytes = 10000;
343 int taskBytes = 12000;
344 int textureBytes = 14000;
345 int assetBytes = 16000;
346
347 // current total 70000
348 int totalBytes = resendBytes + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes;
349
350 Scene scene = new SceneHelpers().SetupScene();
351 TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene);
352 udpServer.ThrottleRates.Total = (int)(totalBytes * 1.1);
353 udpServer.Throttle.RequestedDripRate = (int)(totalBytes * 1.5);
354
355 ScenePresence sp1
356 = ClientStackHelpers.AddChildClient(
357 scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456);
358
359 LLUDPClient udpClient1 = ((LLClientView)sp1.ControllingClient).UDPClient;
360 udpClient1.ThrottleDebugLevel = 1;
361
362 SetThrottles(
363 udpClient1, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes);
364
365 AssertThrottles(
366 udpClient1,
367 resendBytes, landBytes, windBytes, cloudBytes, taskBytes,
368 textureBytes, assetBytes, totalBytes, 0, totalBytes * 1.1);
369
370 // Now add another client
371 ScenePresence sp2
372 = ClientStackHelpers.AddChildClient(
373 scene, udpServer, TestHelpers.ParseTail(0x10), TestHelpers.ParseTail(0x20), 123457);
374
375 LLUDPClient udpClient2 = ((LLClientView)sp2.ControllingClient).UDPClient;
376 udpClient2.ThrottleDebugLevel = 1;
377
378 SetThrottles(
379 udpClient2, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes);
380
381 AssertThrottles(
382 udpClient1,
383 resendBytes * 0.75, landBytes * 0.75, windBytes * 0.75, cloudBytes * 0.75, taskBytes * 0.75,
384 textureBytes * 0.75, assetBytes * 0.75, totalBytes * 0.75, 0, totalBytes * 1.1);
385
386 AssertThrottles(
387 udpClient2,
388 resendBytes * 0.75, landBytes * 0.75, windBytes * 0.75, cloudBytes * 0.75, taskBytes * 0.75,
389 textureBytes * 0.75, assetBytes * 0.75, totalBytes * 0.75, 0, totalBytes * 1.1);
390 }
391
392 private void AssertThrottles(
393 LLUDPClient udpClient,
394 double resendBytes, double landBytes, double windBytes, double cloudBytes, double taskBytes, double textureBytes, double assetBytes,
395 double totalBytes, double targetBytes, double maxBytes)
396 {
397 ClientInfo ci = udpClient.GetClientInfo();
398
399// Console.WriteLine(
400// "Resend={0}, Land={1}, Wind={2}, Cloud={3}, Task={4}, Texture={5}, Asset={6}, TOTAL = {7}",
401// ci.resendThrottle, ci.landThrottle, ci.windThrottle, ci.cloudThrottle, ci.taskThrottle, ci.textureThrottle, ci.assetThrottle, ci.totalThrottle);
402
403 Assert.AreEqual((int)resendBytes, ci.resendThrottle, "Resend");
404 Assert.AreEqual((int)landBytes, ci.landThrottle, "Land");
405 Assert.AreEqual((int)windBytes, ci.windThrottle, "Wind");
406 Assert.AreEqual((int)cloudBytes, ci.cloudThrottle, "Cloud");
407 Assert.AreEqual((int)taskBytes, ci.taskThrottle, "Task");
408 Assert.AreEqual((int)textureBytes, ci.textureThrottle, "Texture");
409 Assert.AreEqual((int)assetBytes, ci.assetThrottle, "Asset");
410 Assert.AreEqual((int)totalBytes, ci.totalThrottle, "Total");
411 Assert.AreEqual((int)targetBytes, ci.targetThrottle, "Target");
412 Assert.AreEqual((int)maxBytes, ci.maxThrottle, "Max");
413 }
414
415 private void SetThrottles(
416 LLUDPClient udpClient, int resendBytes, int landBytes, int windBytes, int cloudBytes, int taskBytes, int textureBytes, int assetBytes)
417 {
418 byte[] throttles = new byte[28];
419
420 Array.Copy(BitConverter.GetBytes((float)resendBytes * 8), 0, throttles, 0, 4);
421 Array.Copy(BitConverter.GetBytes((float)landBytes * 8), 0, throttles, 4, 4);
422 Array.Copy(BitConverter.GetBytes((float)windBytes * 8), 0, throttles, 8, 4);
423 Array.Copy(BitConverter.GetBytes((float)cloudBytes * 8), 0, throttles, 12, 4);
424 Array.Copy(BitConverter.GetBytes((float)taskBytes * 8), 0, throttles, 16, 4);
425 Array.Copy(BitConverter.GetBytes((float)textureBytes * 8), 0, throttles, 20, 4);
426 Array.Copy(BitConverter.GetBytes((float)assetBytes * 8), 0, throttles, 24, 4);
427
428 udpClient.SetThrottles(throttles);
429 }
430 }
431 */
432} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs
new file mode 100644
index 0000000..f8ec97a
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs
@@ -0,0 +1,141 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using OpenSim.Framework;
30using Nini.Config;
31
32namespace OpenSim.Region.ClientStack.LindenUDP
33{
34 /// <summary>
35 /// Holds drip rates and maximum burst rates for throttling with hierarchical
36 /// token buckets. The maximum burst rates set here are hard limits and can
37 /// not be overridden by client requests
38 /// </summary>
39 public sealed class ThrottleRates
40 {
41 /// <summary>Drip rate for resent packets</summary>
42 public int Resend;
43 /// <summary>Drip rate for terrain packets</summary>
44 public int Land;
45 /// <summary>Drip rate for wind packets</summary>
46 public int Wind;
47 /// <summary>Drip rate for cloud packets</summary>
48 public int Cloud;
49 /// <summary>Drip rate for task packets</summary>
50 public int Task;
51 /// <summary>Drip rate for texture packets</summary>
52 public int Texture;
53 /// <summary>Drip rate for asset packets</summary>
54 public int Asset;
55
56 /// <summary>Drip rate for the parent token bucket</summary>
57 public int Total;
58
59 /// <summary>Flag used to enable adaptive throttles</summary>
60 public bool AdaptiveThrottlesEnabled;
61
62 /// <summary>
63 /// Set the minimum rate that the adaptive throttles can set. The viewer
64 /// can still throttle lower than this, but the adaptive throttles will
65 /// never decrease rates below this no matter how many packets are dropped
66 /// </summary>
67 public Int64 MinimumAdaptiveThrottleRate;
68
69 /// <summary>Amount of the texture throttle to steal for the task throttle</summary>
70 public double CannibalizeTextureRate;
71
72 public int ClientMaxRate;
73 public float BrustTime;
74
75 /// <summary>
76 /// Default constructor
77 /// </summary>
78 /// <param name="config">Config source to load defaults from</param>
79 public ThrottleRates(IConfigSource config)
80 {
81 try
82 {
83 IConfig throttleConfig = config.Configs["ClientStack.LindenUDP"];
84
85 // Current default total is 66750
86 Resend = throttleConfig.GetInt("resend_default", 6625);
87 Land = throttleConfig.GetInt("land_default", 9125);
88 Wind = throttleConfig.GetInt("wind_default", 1750);
89 Cloud = throttleConfig.GetInt("cloud_default", 1750);
90 Task = throttleConfig.GetInt("task_default", 18500);
91 Texture = throttleConfig.GetInt("texture_default", 18500);
92 Asset = throttleConfig.GetInt("asset_default", 10500);
93
94 Total = Resend + Land + Wind + Cloud + Task + Texture + Asset;
95 // 5120000 bps default max
96 ClientMaxRate = throttleConfig.GetInt("client_throttle_max_bps", 640000);
97 if (ClientMaxRate > 1000000)
98 ClientMaxRate = 1000000; // no more than 8Mbps
99
100 BrustTime = (float)throttleConfig.GetInt("client_throttle_burtsTimeMS", 10);
101 BrustTime *= 1e-3f;
102
103 // Adaptive is broken
104// AdaptiveThrottlesEnabled = throttleConfig.GetBoolean("enable_adaptive_throttles", false);
105 AdaptiveThrottlesEnabled = false;
106 MinimumAdaptiveThrottleRate = throttleConfig.GetInt("adaptive_throttle_min_bps", 32000);
107
108 // http textures do use udp bandwidth setting
109// CannibalizeTextureRate = (double)throttleConfig.GetFloat("CannibalizeTextureRate", 0.0f);
110// CannibalizeTextureRate = Util.Clamp<double>(CannibalizeTextureRate,0.0, 0.9);
111 CannibalizeTextureRate = 0f;
112
113 }
114 catch (Exception) { }
115 }
116
117 public int GetRate(ThrottleOutPacketType type)
118 {
119 switch (type)
120 {
121 case ThrottleOutPacketType.Resend:
122 return Resend;
123 case ThrottleOutPacketType.Land:
124 return Land;
125 case ThrottleOutPacketType.Wind:
126 return Wind;
127 case ThrottleOutPacketType.Cloud:
128 return Cloud;
129 case ThrottleOutPacketType.Task:
130 return Task;
131 case ThrottleOutPacketType.Texture:
132 return Texture;
133 case ThrottleOutPacketType.Asset:
134 return Asset;
135 case ThrottleOutPacketType.Unknown:
136 default:
137 return 0;
138 }
139 }
140 }
141}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs
new file mode 100644
index 0000000..1daf091
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs
@@ -0,0 +1,417 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Reflection;
32using OpenSim.Framework;
33
34using log4net;
35
36namespace OpenSim.Region.ClientStack.LindenUDP
37{
38 /// <summary>
39 /// A hierarchical token bucket for bandwidth throttling. See
40 /// http://en.wikipedia.org/wiki/Token_bucket for more information
41 /// </summary>
42 public class TokenBucket
43 {
44 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
45
46 private static Int32 m_counter = 0;
47
48// private Int32 m_identifier;
49
50 protected const float m_timeScale = 1e-3f;
51
52 /// <summary>
53 /// This is the number of m_minimumDripRate bytes
54 /// allowed in a burst
55 /// roughtly, with this settings, the maximum time system will take
56 /// to recheck a bucket in ms
57 ///
58 /// </summary>
59 protected const float m_quantumsPerBurst = 5;
60
61 /// <summary>
62 /// </summary>
63 protected const float m_minimumDripRate = 1500;
64
65 /// <summary>Time of the last drip</summary>
66 protected double m_lastDrip;
67
68 /// <summary>
69 /// The number of bytes that can be sent at this moment. This is the
70 /// current number of tokens in the bucket
71 /// </summary>
72 protected float m_tokenCount;
73
74 /// <summary>
75 /// Map of children buckets and their requested maximum burst rate
76 /// </summary>
77
78 protected Dictionary<TokenBucket, float> m_children = new Dictionary<TokenBucket, float>();
79
80#region Properties
81
82 /// <summary>
83 /// The parent bucket of this bucket, or null if this bucket has no
84 /// parent. The parent bucket will limit the aggregate bandwidth of all
85 /// of its children buckets
86 /// </summary>
87 protected TokenBucket m_parent;
88 public TokenBucket Parent
89 {
90 get { return m_parent; }
91 set { m_parent = value; }
92 }
93 /// <summary>
94 /// This is the maximum number
95 /// of tokens that can accumulate in the bucket at any one time. This
96 /// also sets the total request for leaf nodes
97 /// </summary>
98 protected float m_burst;
99
100 protected float m_maxDripRate = 0;
101 public virtual float MaxDripRate
102 {
103 get { return m_maxDripRate; }
104 set { m_maxDripRate = value; }
105 }
106
107 public float RequestedBurst
108 {
109 get { return m_burst; }
110 set {
111 float rate = (value < 0 ? 0 : value);
112 if (rate < 1.5f * m_minimumDripRate)
113 rate = 1.5f * m_minimumDripRate;
114 else if (rate > m_minimumDripRate * m_quantumsPerBurst)
115 rate = m_minimumDripRate * m_quantumsPerBurst;
116
117 m_burst = rate;
118 }
119 }
120
121 public float Burst
122 {
123 get {
124 float rate = RequestedBurst * BurstModifier();
125 if (rate < m_minimumDripRate)
126 rate = m_minimumDripRate;
127 return (float)rate;
128 }
129 }
130
131 /// <summary>
132 /// The requested drip rate for this particular bucket.
133 /// </summary>
134 /// <remarks>
135 /// 0 then TotalDripRequest is used instead.
136 /// Can never be above MaxDripRate.
137 /// Tokens are added to the bucket at any time
138 /// <seealso cref="RemoveTokens"/> is called, at the granularity of
139 /// the system tick interval (typically around 15-22ms)</remarks>
140 protected float m_dripRate;
141
142 public float RequestedDripRate
143 {
144 get { return (m_dripRate == 0 ? m_totalDripRequest : m_dripRate); }
145 set {
146 m_dripRate = (value < 0 ? 0 : value);
147 m_totalDripRequest = m_dripRate;
148
149 if (m_parent != null)
150 m_parent.RegisterRequest(this,m_dripRate);
151 }
152 }
153
154 public float DripRate
155 {
156 get {
157 float rate = Math.Min(RequestedDripRate,TotalDripRequest);
158 if (m_parent == null)
159 return rate;
160
161 rate *= m_parent.DripRateModifier();
162 if (rate < m_minimumDripRate)
163 rate = m_minimumDripRate;
164
165 return (float)rate;
166 }
167 }
168
169 /// <summary>
170 /// The current total of the requested maximum burst rates of children buckets.
171 /// </summary>
172 protected float m_totalDripRequest;
173 public float TotalDripRequest
174 {
175 get { return m_totalDripRequest; }
176 set { m_totalDripRequest = value; }
177 }
178
179#endregion Properties
180
181#region Constructor
182
183
184 /// <summary>
185 /// Default constructor
186 /// </summary>
187 /// <param name="identifier">Identifier for this token bucket</param>
188 /// <param name="parent">Parent bucket if this is a child bucket, or
189 /// null if this is a root bucket</param>
190 /// <param name="maxBurst">Maximum size of the bucket in bytes, or
191 /// zero if this bucket has no maximum capacity</param>
192 /// <param name="dripRate">Rate that the bucket fills, in bytes per
193 /// second. If zero, the bucket always remains full</param>
194 public TokenBucket(TokenBucket parent, float dripRate, float MaxBurst)
195 {
196 m_counter++;
197
198 Parent = parent;
199 RequestedDripRate = dripRate;
200 RequestedBurst = MaxBurst;
201 m_lastDrip = Util.GetTimeStampMS() + 100000.0; // skip first drip
202 }
203
204#endregion Constructor
205
206 /// <summary>
207 /// Compute a modifier for the MaxBurst rate. This is 1.0, meaning
208 /// no modification if the requested bandwidth is less than the
209 /// max burst bandwidth all the way to the root of the throttle
210 /// hierarchy. However, if any of the parents is over-booked, then
211 /// the modifier will be less than 1.
212 /// </summary>
213 protected float DripRateModifier()
214 {
215 float driprate = DripRate;
216 return driprate >= TotalDripRequest ? 1.0f : (driprate / TotalDripRequest);
217 }
218
219 /// <summary>
220 /// </summary>
221 protected float BurstModifier()
222 {
223 // for now... burst rate is always m_quantumsPerBurst (constant)
224 // larger than drip rate so the ratio of burst requests is the
225 // same as the drip ratio
226 return DripRateModifier();
227 }
228
229 /// <summary>
230 /// Register drip rate requested by a child of this throttle. Pass the
231 /// changes up the hierarchy.
232 /// </summary>
233 public void RegisterRequest(TokenBucket child, float request)
234 {
235 lock (m_children)
236 {
237 m_children[child] = request;
238
239 m_totalDripRequest = 0;
240 foreach (KeyValuePair<TokenBucket, float> cref in m_children)
241 m_totalDripRequest += cref.Value;
242 }
243
244 // Pass the new values up to the parent
245 if (m_parent != null)
246 m_parent.RegisterRequest(this, Math.Min(RequestedDripRate, TotalDripRequest));
247 }
248
249 /// <summary>
250 /// Remove the rate requested by a child of this throttle. Pass the
251 /// changes up the hierarchy.
252 /// </summary>
253 public void UnregisterRequest(TokenBucket child)
254 {
255 lock (m_children)
256 {
257 m_children.Remove(child);
258
259 m_totalDripRequest = 0;
260 foreach (KeyValuePair<TokenBucket, float> cref in m_children)
261 m_totalDripRequest += cref.Value;
262 }
263
264 // Pass the new values up to the parent
265 if (Parent != null)
266 Parent.RegisterRequest(this,Math.Min(RequestedDripRate, TotalDripRequest));
267 }
268
269 /// <summary>
270 /// Remove a given number of tokens from the bucket
271 /// </summary>
272 /// <param name="amount">Number of tokens to remove from the bucket</param>
273 /// <returns>True if the requested number of tokens were removed from
274 /// the bucket, otherwise false</returns>
275 public bool RemoveTokens(int amount)
276 {
277 // Deposit tokens for this interval
278 Drip();
279
280 // If we have enough tokens then remove them and return
281 if (m_tokenCount - amount >= 0)
282 {
283 // we don't have to remove from the parent, the drip rate is already
284 // reflective of the drip rate limits in the parent
285 m_tokenCount -= amount;
286 return true;
287 }
288
289 return false;
290 }
291
292 public bool CheckTokens(int amount)
293 {
294 return (m_tokenCount - amount >= 0);
295 }
296
297 public int GetCatBytesCanSend(int timeMS)
298 {
299// return (int)(m_tokenCount + timeMS * m_dripRate * 1e-3);
300 return (int)(timeMS * DripRate * 1e-3);
301 }
302
303 /// <summary>
304 /// Add tokens to the bucket over time. The number of tokens added each
305 /// call depends on the length of time that has passed since the last
306 /// call to Drip
307 /// </summary>
308 /// <returns>True if tokens were added to the bucket, otherwise false</returns>
309 protected void Drip()
310 {
311 // This should never happen... means we are a leaf node and were created
312 // with no drip rate...
313 if (DripRate == 0)
314 {
315 m_log.WarnFormat("[TOKENBUCKET] something odd is happening and drip rate is 0 for {0}", m_counter);
316 return;
317 }
318
319 double now = Util.GetTimeStampMS();
320 double deltaMS = now - m_lastDrip;
321 m_lastDrip = now;
322
323 if (deltaMS <= 0)
324 return;
325
326 m_tokenCount += (float)deltaMS * DripRate * m_timeScale;
327
328 float burst = Burst;
329 if (m_tokenCount > burst)
330 m_tokenCount = burst;
331 }
332 }
333
334 public class AdaptiveTokenBucket : TokenBucket
335 {
336 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
337
338 public bool AdaptiveEnabled { get; set; }
339
340 /// <summary>
341 /// The minimum rate for flow control. Minimum drip rate is one
342 /// packet per second.
343 /// </summary>
344
345 protected const float m_minimumFlow = 50000;
346
347 // <summary>
348 // The maximum rate for flow control. Drip rate can never be
349 // greater than this.
350 // </summary>
351
352 public override float MaxDripRate
353 {
354 get { return (m_maxDripRate == 0 ? m_totalDripRequest : m_maxDripRate); }
355 set
356 {
357 m_maxDripRate = (value == 0 ? m_totalDripRequest : Math.Max(value, m_minimumFlow));
358 }
359 }
360
361 private bool m_enabled = false;
362
363 // <summary>
364 // Adjust drip rate in response to network conditions.
365 // </summary>
366 public float AdjustedDripRate
367 {
368 get { return m_dripRate; }
369 set
370 {
371 m_dripRate = OpenSim.Framework.Util.Clamp<float>(value, m_minimumFlow, MaxDripRate);
372
373 if (m_parent != null)
374 m_parent.RegisterRequest(this, m_dripRate);
375 }
376 }
377
378
379 // <summary>
380 //
381 // </summary>
382 public AdaptiveTokenBucket(TokenBucket parent, float maxDripRate, float maxBurst, bool enabled)
383 : base(parent, maxDripRate, maxBurst)
384 {
385 m_enabled = enabled;
386
387 m_maxDripRate = (maxDripRate == 0 ? m_totalDripRequest : Math.Max(maxDripRate, m_minimumFlow));
388
389 if (enabled)
390 m_dripRate = m_maxDripRate * .5f;
391 else
392 m_dripRate = m_maxDripRate;
393 if (m_parent != null)
394 m_parent.RegisterRequest(this, m_dripRate);
395 }
396
397 /// <summary>
398 /// Reliable packets sent to the client for which we never received an ack adjust the drip rate down.
399 /// <param name="packets">Number of packets that expired without successful delivery</param>
400 /// </summary>
401 public void ExpirePackets(Int32 count)
402 {
403 // m_log.WarnFormat("[ADAPTIVEBUCKET] drop {0} by {1} expired packets",AdjustedDripRate,count);
404 if (m_enabled)
405 AdjustedDripRate = (Int64)(AdjustedDripRate / Math.Pow(2, count));
406 }
407
408 // <summary>
409 //
410 // </summary>
411 public void AcknowledgePackets(Int32 count)
412 {
413 if (m_enabled)
414 AdjustedDripRate = AdjustedDripRate + count;
415 }
416 }
417}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs b/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs
new file mode 100644
index 0000000..76f4c6f
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs
@@ -0,0 +1,252 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Net;
31using System.Threading;
32using OpenMetaverse;
33
34//using System.Reflection;
35//using log4net;
36
37namespace OpenSim.Region.ClientStack.LindenUDP
38{
39 /// <summary>
40 /// Special collection that is optimized for tracking unacknowledged packets
41 /// </summary>
42 public sealed class UnackedPacketCollection
43 {
44 /// <summary>
45 /// Holds information about a pending acknowledgement
46 /// </summary>
47 private struct PendingAck
48 {
49 /// <summary>Sequence number of the packet to remove</summary>
50 public uint SequenceNumber;
51 /// <summary>Environment.TickCount value when the remove was queued.
52 /// This is used to update round-trip times for packets</summary>
53 public int RemoveTime;
54 /// <summary>Whether or not this acknowledgement was attached to a
55 /// resent packet. If so, round-trip time will not be calculated</summary>
56 public bool FromResend;
57
58 public PendingAck(uint sequenceNumber, int currentTime, bool fromResend)
59 {
60 SequenceNumber = sequenceNumber;
61 RemoveTime = currentTime;
62 FromResend = fromResend;
63 }
64 }
65
66 //private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
67
68 /// <summary>Holds the actual unacked packet data, sorted by sequence number</summary>
69 private Dictionary<uint, OutgoingPacket> m_packets = new Dictionary<uint, OutgoingPacket>();
70 /// <summary>Holds packets that need to be added to the unacknowledged list</summary>
71 private LocklessQueue<OutgoingPacket> m_pendingAdds = new LocklessQueue<OutgoingPacket>();
72 /// <summary>Holds information about pending acknowledgements</summary>
73 private LocklessQueue<PendingAck> m_pendingAcknowledgements = new LocklessQueue<PendingAck>();
74 /// <summary>Holds information about pending removals</summary>
75 private LocklessQueue<uint> m_pendingRemoves = new LocklessQueue<uint>();
76
77
78 public void Clear()
79 {
80 m_packets.Clear();
81 m_pendingAdds = null;
82 m_pendingAcknowledgements = null;
83 m_pendingRemoves = null;
84 }
85
86 /// <summary>
87 /// Add an unacked packet to the collection
88 /// </summary>
89 /// <param name="packet">Packet that is awaiting acknowledgement</param>
90 /// <returns>True if the packet was successfully added, false if the
91 /// packet already existed in the collection</returns>
92 /// <remarks>This does not immediately add the ACK to the collection,
93 /// it only queues it so it can be added in a thread-safe way later</remarks>
94 public void Add(OutgoingPacket packet)
95 {
96 m_pendingAdds.Enqueue(packet);
97 Interlocked.Add(ref packet.Client.UnackedBytes, packet.Buffer.DataLength);
98 }
99
100 /// <summary>
101 /// Marks a packet as acknowledged
102 /// This method is used when an acknowledgement is received from the network for a previously
103 /// sent packet. Effects of removal this way are to update unacked byte count, adjust RTT
104 /// and increase throttle to the coresponding client.
105 /// </summary>
106 /// <param name="sequenceNumber">Sequence number of the packet to
107 /// acknowledge</param>
108 /// <param name="currentTime">Current value of Environment.TickCount</param>
109 /// <remarks>This does not immediately acknowledge the packet, it only
110 /// queues the ack so it can be handled in a thread-safe way later</remarks>
111 public void Acknowledge(uint sequenceNumber, int currentTime, bool fromResend)
112 {
113 m_pendingAcknowledgements.Enqueue(new PendingAck(sequenceNumber, currentTime, fromResend));
114 }
115
116 /// <summary>
117 /// Marks a packet as no longer needing acknowledgement without a received acknowledgement.
118 /// This method is called when a packet expires and we no longer need an acknowledgement.
119 /// When some reliable packet types expire, they are handled in a way other than simply
120 /// resending them. The only effect of removal this way is to update unacked byte count.
121 /// </summary>
122 /// <param name="sequenceNumber">Sequence number of the packet to
123 /// acknowledge</param>
124 /// <remarks>The does not immediately remove the packet, it only queues the removal
125 /// so it can be handled in a thread safe way later</remarks>
126 public void Remove(uint sequenceNumber)
127 {
128 m_pendingRemoves.Enqueue(sequenceNumber);
129 }
130
131 /// <summary>
132 /// Returns a list of all of the packets with a TickCount older than
133 /// the specified timeout
134 /// </summary>
135 /// <remarks>
136 /// This function is not thread safe, and cannot be called
137 /// multiple times concurrently
138 /// </remarks>
139 /// <param name="timeoutMS">Number of ticks (milliseconds) before a
140 /// packet is considered expired
141 /// </param>
142 /// <returns>
143 /// A list of all expired packets according to the given
144 /// expiration timeout
145 /// </returns>
146 public List<OutgoingPacket> GetExpiredPackets(int timeoutMS)
147 {
148 ProcessQueues();
149
150 List<OutgoingPacket> expiredPackets = null;
151
152 if (m_packets.Count > 0)
153 {
154 int now = Environment.TickCount & Int32.MaxValue;
155
156 foreach (OutgoingPacket packet in m_packets.Values)
157 {
158 // TickCount of zero means a packet is in the resend queue
159 // but hasn't actually been sent over the wire yet
160 if (packet.TickCount == 0)
161 continue;
162
163 if (now - packet.TickCount >= timeoutMS)
164 {
165 if (expiredPackets == null)
166 expiredPackets = new List<OutgoingPacket>();
167
168 // The TickCount will be set to the current time when the packet
169 // is actually sent out again
170 packet.TickCount = 0;
171
172 // As with other network applications, assume that an expired packet is
173 // an indication of some network problem, slow transmission
174 packet.Client.FlowThrottle.ExpirePackets(1);
175
176 expiredPackets.Add(packet);
177 }
178 }
179 }
180
181 // if (expiredPackets != null)
182 // m_log.DebugFormat("[UNACKED PACKET COLLECTION]: Found {0} expired packets on timeout of {1}", expiredPackets.Count, timeoutMS);
183
184 return expiredPackets;
185 }
186
187 private void ProcessQueues()
188 {
189 // Process all the pending adds
190 OutgoingPacket pendingAdd;
191 while (m_pendingAdds.TryDequeue(out pendingAdd))
192 if (pendingAdd != null)
193 m_packets[pendingAdd.SequenceNumber] = pendingAdd;
194
195 // Process all the pending removes, including updating statistics and round-trip times
196 PendingAck pendingAcknowledgement;
197 while (m_pendingAcknowledgements.TryDequeue(out pendingAcknowledgement))
198 {
199 //m_log.DebugFormat("[UNACKED PACKET COLLECTION]: Processing ack {0}", pendingAcknowledgement.SequenceNumber);
200 OutgoingPacket ackedPacket;
201 if (m_packets.TryGetValue(pendingAcknowledgement.SequenceNumber, out ackedPacket))
202 {
203 if (ackedPacket != null)
204 {
205 m_packets.Remove(pendingAcknowledgement.SequenceNumber);
206
207 // As with other network applications, assume that an acknowledged packet is an
208 // indication that the network can handle a little more load, speed up the transmission
209 ackedPacket.Client.FlowThrottle.AcknowledgePackets(1);
210
211 // Update stats
212 Interlocked.Add(ref ackedPacket.Client.UnackedBytes, -ackedPacket.Buffer.DataLength);
213
214 if (!pendingAcknowledgement.FromResend)
215 {
216 // Calculate the round-trip time for this packet and its ACK
217 int rtt = pendingAcknowledgement.RemoveTime - ackedPacket.TickCount;
218 if (rtt > 0)
219 ackedPacket.Client.UpdateRoundTrip(rtt);
220 }
221 }
222 else
223 {
224 // m_log.WarnFormat("[UNACKED PACKET COLLECTION]: found null packet for sequence number {0} to ack",
225 // pendingAcknowledgement.SequenceNumber);
226 }
227 }
228 else
229 {
230 // m_log.WarnFormat("[UNACKED PACKET COLLECTION]: Could not find packet with sequence number {0} to ack",
231 // pendingAcknowledgement.SequenceNumber);
232 }
233 }
234
235 uint pendingRemove;
236 while(m_pendingRemoves.TryDequeue(out pendingRemove))
237 {
238 OutgoingPacket removedPacket;
239 if (m_packets.TryGetValue(pendingRemove, out removedPacket))
240 {
241 if (removedPacket != null)
242 {
243 m_packets.Remove(pendingRemove);
244
245 // Update stats
246 Interlocked.Add(ref removedPacket.Client.UnackedBytes, -removedPacket.Buffer.DataLength);
247 }
248 }
249 }
250 }
251 }
252} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/Properties/AssemblyInfo.cs b/OpenSim/Region/ClientStack/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..e859653
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Properties/AssemblyInfo.cs
@@ -0,0 +1,33 @@
1using System.Reflection;
2using System.Runtime.CompilerServices;
3using System.Runtime.InteropServices;
4
5// General Information about an assembly is controlled through the following
6// set of attributes. Change these attribute values to modify the information
7// associated with an assembly.
8[assembly: AssemblyTitle("OpenSim.Region.ClientStack")]
9[assembly: AssemblyDescription("")]
10[assembly: AssemblyConfiguration("")]
11[assembly: AssemblyCompany("http://opensimulator.org")]
12[assembly: AssemblyProduct("OpenSIm")]
13[assembly: AssemblyCopyright("OpenSimulator developers")]
14[assembly: AssemblyTrademark("")]
15[assembly: AssemblyCulture("")]
16
17// Setting ComVisible to false makes the types in this assembly not visible
18// to COM components. If you need to access a type in this assembly from
19// COM, set the ComVisible attribute to true on that type.
20[assembly: ComVisible(false)]
21
22// The following GUID is for the ID of the typelib if this project is exposed to COM
23[assembly: Guid("02ced54a-a802-4474-9e94-f03a44fde922")]
24
25// Version information for an assembly consists of the following four values:
26//
27// Major Version
28// Minor Version
29// Build Number
30// Revision
31//
32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")]