diff options
Diffstat (limited to 'OpenSim/Region/ClientStack')
27 files changed, 2069 insertions, 1218 deletions
diff --git a/OpenSim/Region/ClientStack/IClientNetworkServer.cs b/OpenSim/Region/ClientStack/IClientNetworkServer.cs index 54a441b..bb7e6d0 100644 --- a/OpenSim/Region/ClientStack/IClientNetworkServer.cs +++ b/OpenSim/Region/ClientStack/IClientNetworkServer.cs | |||
@@ -38,11 +38,22 @@ namespace OpenSim.Region.ClientStack | |||
38 | IPAddress _listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, | 38 | IPAddress _listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, |
39 | AgentCircuitManager authenticateClass); | 39 | AgentCircuitManager authenticateClass); |
40 | 40 | ||
41 | void NetworkStop(); | ||
42 | bool HandlesRegion(Location x); | 41 | bool HandlesRegion(Location x); |
43 | void AddScene(IScene x); | ||
44 | 42 | ||
43 | /// <summary> | ||
44 | /// Add the given scene to be handled by this IClientNetworkServer. | ||
45 | /// </summary> | ||
46 | /// <param name='scene'></param> | ||
47 | void AddScene(IScene scene); | ||
48 | |||
49 | /// <summary> | ||
50 | /// Start sending and receiving data. | ||
51 | /// </summary> | ||
45 | void Start(); | 52 | void Start(); |
53 | |||
54 | /// <summary> | ||
55 | /// Stop sending and receiving data. | ||
56 | /// </summary> | ||
46 | void Stop(); | 57 | void Stop(); |
47 | } | 58 | } |
48 | } | 59 | } |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs new file mode 100644 index 0000000..bbadc55 --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs | |||
@@ -0,0 +1,136 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Specialized; | ||
31 | using System.Drawing; | ||
32 | using System.Drawing.Imaging; | ||
33 | using System.Reflection; | ||
34 | using System.IO; | ||
35 | using System.Web; | ||
36 | using log4net; | ||
37 | using Nini.Config; | ||
38 | using Mono.Addins; | ||
39 | using OpenMetaverse; | ||
40 | using OpenMetaverse.StructuredData; | ||
41 | using OpenSim.Framework; | ||
42 | using OpenSim.Framework.Servers; | ||
43 | using OpenSim.Framework.Servers.HttpServer; | ||
44 | using OpenSim.Region.Framework.Interfaces; | ||
45 | using OpenSim.Region.Framework.Scenes; | ||
46 | using OpenSim.Services.Interfaces; | ||
47 | using Caps = OpenSim.Framework.Capabilities.Caps; | ||
48 | using OpenSim.Capabilities.Handlers; | ||
49 | |||
50 | namespace OpenSim.Region.ClientStack.Linden | ||
51 | { | ||
52 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AvatarPickerSearchModule")] | ||
53 | public class AvatarPickerSearchModule : INonSharedRegionModule | ||
54 | { | ||
55 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
56 | |||
57 | private Scene m_scene; | ||
58 | private IPeople m_People; | ||
59 | private bool m_Enabled = false; | ||
60 | |||
61 | private string m_URL; | ||
62 | |||
63 | #region ISharedRegionModule Members | ||
64 | |||
65 | public void Initialise(IConfigSource source) | ||
66 | { | ||
67 | IConfig config = source.Configs["ClientStack.LindenCaps"]; | ||
68 | if (config == null) | ||
69 | return; | ||
70 | |||
71 | m_URL = config.GetString("Cap_AvatarPickerSearch", string.Empty); | ||
72 | // Cap doesn't exist | ||
73 | if (m_URL != string.Empty) | ||
74 | m_Enabled = true; | ||
75 | } | ||
76 | |||
77 | public void AddRegion(Scene s) | ||
78 | { | ||
79 | if (!m_Enabled) | ||
80 | return; | ||
81 | |||
82 | m_scene = s; | ||
83 | } | ||
84 | |||
85 | public void RemoveRegion(Scene s) | ||
86 | { | ||
87 | if (!m_Enabled) | ||
88 | return; | ||
89 | |||
90 | m_scene.EventManager.OnRegisterCaps -= RegisterCaps; | ||
91 | m_scene = null; | ||
92 | } | ||
93 | |||
94 | public void RegionLoaded(Scene s) | ||
95 | { | ||
96 | if (!m_Enabled) | ||
97 | return; | ||
98 | |||
99 | m_People = m_scene.RequestModuleInterface<IPeople>(); | ||
100 | m_scene.EventManager.OnRegisterCaps += RegisterCaps; | ||
101 | } | ||
102 | |||
103 | public void PostInitialise() | ||
104 | { | ||
105 | } | ||
106 | |||
107 | public void Close() { } | ||
108 | |||
109 | public string Name { get { return "AvatarPickerSearchModule"; } } | ||
110 | |||
111 | public Type ReplaceableInterface | ||
112 | { | ||
113 | get { return null; } | ||
114 | } | ||
115 | |||
116 | #endregion | ||
117 | |||
118 | public void RegisterCaps(UUID agentID, Caps caps) | ||
119 | { | ||
120 | UUID capID = UUID.Random(); | ||
121 | |||
122 | if (m_URL == "localhost") | ||
123 | { | ||
124 | // m_log.DebugFormat("[AVATAR PICKER SEARCH]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); | ||
125 | caps.RegisterHandler( | ||
126 | "AvatarPickerSearch", | ||
127 | new AvatarPickerSearchHandler("/CAPS/" + capID + "/", m_People, "AvatarPickerSearch", "Search for avatars by name")); | ||
128 | } | ||
129 | else | ||
130 | { | ||
131 | // m_log.DebugFormat("[AVATAR PICKER SEARCH]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName); | ||
132 | caps.RegisterHandler("AvatarPickerSearch", m_URL); | ||
133 | } | ||
134 | } | ||
135 | } | ||
136 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs index 8241e07..61b9045 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs | |||
@@ -248,7 +248,19 @@ namespace OpenSim.Region.ClientStack.Linden | |||
248 | //m_capsHandlers["MapLayer"] = | 248 | //m_capsHandlers["MapLayer"] = |
249 | // new LLSDStreamhandler<OSDMapRequest, OSDMapLayerResponse>("POST", | 249 | // new LLSDStreamhandler<OSDMapRequest, OSDMapLayerResponse>("POST", |
250 | // capsBase + m_mapLayerPath, | 250 | // capsBase + m_mapLayerPath, |
251 | // GetMapLayer); | 251 | // GetMapLayer); |
252 | |||
253 | IRequestHandler getObjectPhysicsDataHandler | ||
254 | = new RestStreamHandler( | ||
255 | "POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData, "GetObjectPhysicsData", null); | ||
256 | m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler); | ||
257 | |||
258 | IRequestHandler getObjectCostHandler = new RestStreamHandler("POST", capsBase + m_getObjectCostPath, GetObjectCost); | ||
259 | m_HostCapsObj.RegisterHandler("GetObjectCost", getObjectCostHandler); | ||
260 | IRequestHandler ResourceCostSelectedHandler = new RestStreamHandler("POST", capsBase + m_ResourceCostSelectedPath, ResourceCostSelected); | ||
261 | m_HostCapsObj.RegisterHandler("ResourceCostSelected", ResourceCostSelectedHandler); | ||
262 | |||
263 | |||
252 | IRequestHandler req | 264 | IRequestHandler req |
253 | = new RestStreamHandler( | 265 | = new RestStreamHandler( |
254 | "POST", capsBase + m_notecardTaskUpdatePath, ScriptTaskInventory, "UpdateScript", null); | 266 | "POST", capsBase + m_notecardTaskUpdatePath, ScriptTaskInventory, "UpdateScript", null); |
@@ -282,13 +294,12 @@ namespace OpenSim.Region.ClientStack.Linden | |||
282 | m_HostCapsObj.RegisterHandler("UpdateNotecardAgentInventory", req); | 294 | m_HostCapsObj.RegisterHandler("UpdateNotecardAgentInventory", req); |
283 | m_HostCapsObj.RegisterHandler("UpdateScriptAgentInventory", req); | 295 | m_HostCapsObj.RegisterHandler("UpdateScriptAgentInventory", req); |
284 | m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req); | 296 | m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req); |
285 | IRequestHandler getObjectPhysicsDataHandler = new RestStreamHandler("POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData); | 297 | |
286 | m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler); | 298 | |
287 | IRequestHandler getObjectCostHandler = new RestStreamHandler("POST", capsBase + m_getObjectCostPath, GetObjectCost); | 299 | |
288 | m_HostCapsObj.RegisterHandler("GetObjectCost", getObjectCostHandler); | 300 | IRequestHandler UpdateAgentInformationHandler |
289 | IRequestHandler ResourceCostSelectedHandler = new RestStreamHandler("POST", capsBase + m_ResourceCostSelectedPath, ResourceCostSelected); | 301 | = new RestStreamHandler( |
290 | m_HostCapsObj.RegisterHandler("ResourceCostSelected", ResourceCostSelectedHandler); | 302 | "POST", capsBase + m_UpdateAgentInformationPath, UpdateAgentInformation, "UpdateAgentInformation", null); |
291 | IRequestHandler UpdateAgentInformationHandler = new RestStreamHandler("POST", capsBase + m_UpdateAgentInformationPath, UpdateAgentInformation); | ||
292 | m_HostCapsObj.RegisterHandler("UpdateAgentInformation", UpdateAgentInformationHandler); | 303 | m_HostCapsObj.RegisterHandler("UpdateAgentInformation", UpdateAgentInformationHandler); |
293 | 304 | ||
294 | m_HostCapsObj.RegisterHandler( | 305 | m_HostCapsObj.RegisterHandler( |
@@ -361,18 +372,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
361 | foreach (OSD c in capsRequested) | 372 | foreach (OSD c in capsRequested) |
362 | validCaps.Add(c.AsString()); | 373 | validCaps.Add(c.AsString()); |
363 | 374 | ||
364 | Hashtable caps = m_HostCapsObj.CapsHandlers.GetCapsDetails(true, validCaps); | 375 | string result = LLSDHelpers.SerialiseLLSDReply(m_HostCapsObj.GetCapsDetails(true, validCaps)); |
365 | |||
366 | // Add the external too | ||
367 | foreach (KeyValuePair<string, string> kvp in m_HostCapsObj.ExternalCapsHandlers) | ||
368 | { | ||
369 | if (!validCaps.Contains(kvp.Key)) | ||
370 | continue; | ||
371 | |||
372 | caps[kvp.Key] = kvp.Value; | ||
373 | } | ||
374 | |||
375 | string result = LLSDHelpers.SerialiseLLSDReply(caps); | ||
376 | 376 | ||
377 | //m_log.DebugFormat("[CAPS] CapsRequest {0}", result); | 377 | //m_log.DebugFormat("[CAPS] CapsRequest {0}", result); |
378 | 378 | ||
@@ -748,6 +748,10 @@ namespace OpenSim.Region.ClientStack.Linden | |||
748 | inType = (sbyte)InventoryType.Sound; | 748 | inType = (sbyte)InventoryType.Sound; |
749 | assType = (sbyte)AssetType.Sound; | 749 | assType = (sbyte)AssetType.Sound; |
750 | } | 750 | } |
751 | else if (inventoryType == "snapshot") | ||
752 | { | ||
753 | inType = (sbyte)InventoryType.Snapshot; | ||
754 | } | ||
751 | else if (inventoryType == "animation") | 755 | else if (inventoryType == "animation") |
752 | { | 756 | { |
753 | inType = (sbyte)InventoryType.Animation; | 757 | inType = (sbyte)InventoryType.Animation; |
@@ -1380,6 +1384,17 @@ namespace OpenSim.Region.ClientStack.Linden | |||
1380 | 1384 | ||
1381 | resp[uuid.ToString()] = object_data; | 1385 | resp[uuid.ToString()] = object_data; |
1382 | } | 1386 | } |
1387 | else | ||
1388 | { | ||
1389 | OSDMap object_data = new OSDMap(); | ||
1390 | object_data["linked_set_resource_cost"] = 0; | ||
1391 | object_data["resource_cost"] = 0; | ||
1392 | object_data["physics_cost"] = 0; | ||
1393 | object_data["linked_set_physics_cost"] = 0; | ||
1394 | |||
1395 | resp[uuid.ToString()] = object_data; | ||
1396 | } | ||
1397 | |||
1383 | } | 1398 | } |
1384 | } | 1399 | } |
1385 | 1400 | ||
@@ -1444,7 +1459,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
1444 | } | 1459 | } |
1445 | } | 1460 | } |
1446 | 1461 | ||
1447 | if (simul != 0) | 1462 | // if (simul != 0) |
1448 | { | 1463 | { |
1449 | OSDMap object_data = new OSDMap(); | 1464 | OSDMap object_data = new OSDMap(); |
1450 | 1465 | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs index eb40eb1..ca6c3ca 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs | |||
@@ -65,12 +65,18 @@ namespace OpenSim.Region.ClientStack.Linden | |||
65 | /// </value> | 65 | /// </value> |
66 | public int DebugLevel { get; set; } | 66 | public int DebugLevel { get; set; } |
67 | 67 | ||
68 | // Viewer post requests timeout in 60 secs | ||
69 | // https://bitbucket.org/lindenlab/viewer-release/src/421c20423df93d650cc305dc115922bb30040999/indra/llmessage/llhttpclient.cpp?at=default#cl-44 | ||
70 | // | ||
71 | private const int VIEWER_TIMEOUT = 60 * 1000; | ||
72 | // Just to be safe, we work on a 10 sec shorter cycle | ||
73 | private const int SERVER_EQ_TIME_NO_EVENTS = VIEWER_TIMEOUT - (10 * 1000); | ||
74 | |||
68 | protected Scene m_scene; | 75 | protected Scene m_scene; |
69 | 76 | ||
70 | private Dictionary<UUID, int> m_ids = new Dictionary<UUID, int>(); | 77 | private Dictionary<UUID, int> m_ids = new Dictionary<UUID, int>(); |
71 | 78 | ||
72 | private Dictionary<UUID, Queue<OSD>> queues = new Dictionary<UUID, Queue<OSD>>(); | 79 | private Dictionary<UUID, Queue<OSD>> queues = new Dictionary<UUID, Queue<OSD>>(); |
73 | private Dictionary<UUID, UUID> m_QueueUUIDAvatarMapping = new Dictionary<UUID, UUID>(); | ||
74 | private Dictionary<UUID, UUID> m_AvatarQueueUUIDMapping = new Dictionary<UUID, UUID>(); | 80 | private Dictionary<UUID, UUID> m_AvatarQueueUUIDMapping = new Dictionary<UUID, UUID>(); |
75 | 81 | ||
76 | #region INonSharedRegionModule methods | 82 | #region INonSharedRegionModule methods |
@@ -84,7 +90,6 @@ namespace OpenSim.Region.ClientStack.Linden | |||
84 | scene.RegisterModuleInterface<IEventQueue>(this); | 90 | scene.RegisterModuleInterface<IEventQueue>(this); |
85 | 91 | ||
86 | scene.EventManager.OnClientClosed += ClientClosed; | 92 | scene.EventManager.OnClientClosed += ClientClosed; |
87 | scene.EventManager.OnMakeChildAgent += MakeChildAgent; | ||
88 | scene.EventManager.OnRegisterCaps += OnRegisterCaps; | 93 | scene.EventManager.OnRegisterCaps += OnRegisterCaps; |
89 | 94 | ||
90 | MainConsole.Instance.Commands.AddCommand( | 95 | MainConsole.Instance.Commands.AddCommand( |
@@ -113,7 +118,6 @@ namespace OpenSim.Region.ClientStack.Linden | |||
113 | return; | 118 | return; |
114 | 119 | ||
115 | scene.EventManager.OnClientClosed -= ClientClosed; | 120 | scene.EventManager.OnClientClosed -= ClientClosed; |
116 | scene.EventManager.OnMakeChildAgent -= MakeChildAgent; | ||
117 | scene.EventManager.OnRegisterCaps -= OnRegisterCaps; | 121 | scene.EventManager.OnRegisterCaps -= OnRegisterCaps; |
118 | 122 | ||
119 | scene.UnregisterModuleInterface<IEventQueue>(this); | 123 | scene.UnregisterModuleInterface<IEventQueue>(this); |
@@ -172,29 +176,6 @@ namespace OpenSim.Region.ClientStack.Linden | |||
172 | } | 176 | } |
173 | 177 | ||
174 | /// <summary> | 178 | /// <summary> |
175 | /// Always returns a valid queue | ||
176 | /// </summary> | ||
177 | /// <param name="agentId"></param> | ||
178 | /// <returns></returns> | ||
179 | private Queue<OSD> TryGetQueue(UUID agentId) | ||
180 | { | ||
181 | lock (queues) | ||
182 | { | ||
183 | if (!queues.ContainsKey(agentId)) | ||
184 | { | ||
185 | /* | ||
186 | m_log.DebugFormat( | ||
187 | "[EVENTQUEUE]: Adding new queue for agent {0} in region {1}", | ||
188 | agentId, m_scene.RegionInfo.RegionName); | ||
189 | */ | ||
190 | queues[agentId] = new Queue<OSD>(); | ||
191 | } | ||
192 | |||
193 | return queues[agentId]; | ||
194 | } | ||
195 | } | ||
196 | |||
197 | /// <summary> | ||
198 | /// May return a null queue | 179 | /// May return a null queue |
199 | /// </summary> | 180 | /// </summary> |
200 | /// <param name="agentId"></param> | 181 | /// <param name="agentId"></param> |
@@ -221,8 +202,17 @@ namespace OpenSim.Region.ClientStack.Linden | |||
221 | { | 202 | { |
222 | Queue<OSD> queue = GetQueue(avatarID); | 203 | Queue<OSD> queue = GetQueue(avatarID); |
223 | if (queue != null) | 204 | if (queue != null) |
205 | { | ||
224 | lock (queue) | 206 | lock (queue) |
225 | queue.Enqueue(ev); | 207 | queue.Enqueue(ev); |
208 | } | ||
209 | else | ||
210 | { | ||
211 | OSDMap evMap = (OSDMap)ev; | ||
212 | m_log.WarnFormat( | ||
213 | "[EVENTQUEUE]: (Enqueue) No queue found for agent {0} when placing message {1} in region {2}", | ||
214 | avatarID, evMap["message"], m_scene.Name); | ||
215 | } | ||
226 | } | 216 | } |
227 | catch (NullReferenceException e) | 217 | catch (NullReferenceException e) |
228 | { | 218 | { |
@@ -237,77 +227,22 @@ namespace OpenSim.Region.ClientStack.Linden | |||
237 | 227 | ||
238 | private void ClientClosed(UUID agentID, Scene scene) | 228 | private void ClientClosed(UUID agentID, Scene scene) |
239 | { | 229 | { |
240 | // m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", agentID, m_scene.RegionInfo.RegionName); | 230 | //m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", agentID, m_scene.RegionInfo.RegionName); |
241 | |||
242 | int count = 0; | ||
243 | while (queues.ContainsKey(agentID) && queues[agentID].Count > 0 && count++ < 5) | ||
244 | { | ||
245 | Thread.Sleep(1000); | ||
246 | } | ||
247 | 231 | ||
248 | lock (queues) | 232 | lock (queues) |
249 | { | ||
250 | queues.Remove(agentID); | 233 | queues.Remove(agentID); |
251 | } | ||
252 | 234 | ||
253 | List<UUID> removeitems = new List<UUID>(); | ||
254 | lock (m_AvatarQueueUUIDMapping) | 235 | lock (m_AvatarQueueUUIDMapping) |
255 | { | 236 | m_AvatarQueueUUIDMapping.Remove(agentID); |
256 | foreach (UUID ky in m_AvatarQueueUUIDMapping.Keys) | ||
257 | { | ||
258 | // m_log.DebugFormat("[EVENTQUEUE]: Found key {0} in m_AvatarQueueUUIDMapping while looking for {1}", ky, AgentID); | ||
259 | if (ky == agentID) | ||
260 | { | ||
261 | removeitems.Add(ky); | ||
262 | } | ||
263 | } | ||
264 | |||
265 | foreach (UUID ky in removeitems) | ||
266 | { | ||
267 | UUID eventQueueGetUuid = m_AvatarQueueUUIDMapping[ky]; | ||
268 | m_AvatarQueueUUIDMapping.Remove(ky); | ||
269 | 237 | ||
270 | string eqgPath = GenerateEqgCapPath(eventQueueGetUuid); | 238 | lock (m_ids) |
271 | MainServer.Instance.RemovePollServiceHTTPHandler("", eqgPath); | ||
272 | |||
273 | // m_log.DebugFormat( | ||
274 | // "[EVENT QUEUE GET MODULE]: Removed EQG handler {0} for {1} in {2}", | ||
275 | // eqgPath, agentID, m_scene.RegionInfo.RegionName); | ||
276 | } | ||
277 | } | ||
278 | |||
279 | UUID searchval = UUID.Zero; | ||
280 | |||
281 | removeitems.Clear(); | ||
282 | |||
283 | lock (m_QueueUUIDAvatarMapping) | ||
284 | { | 239 | { |
285 | foreach (UUID ky in m_QueueUUIDAvatarMapping.Keys) | 240 | if (!m_ids.ContainsKey(agentID)) |
286 | { | 241 | m_ids.Remove(agentID); |
287 | searchval = m_QueueUUIDAvatarMapping[ky]; | ||
288 | |||
289 | if (searchval == agentID) | ||
290 | { | ||
291 | removeitems.Add(ky); | ||
292 | } | ||
293 | } | ||
294 | |||
295 | foreach (UUID ky in removeitems) | ||
296 | m_QueueUUIDAvatarMapping.Remove(ky); | ||
297 | } | 242 | } |
298 | } | ||
299 | 243 | ||
300 | private void MakeChildAgent(ScenePresence avatar) | 244 | // m_log.DebugFormat("[EVENTQUEUE]: Deleted queues for {0} in region {1}", agentID, m_scene.RegionInfo.RegionName); |
301 | { | 245 | |
302 | //m_log.DebugFormat("[EVENTQUEUE]: Make Child agent {0} in region {1}.", avatar.UUID, m_scene.RegionInfo.RegionName); | ||
303 | //lock (m_ids) | ||
304 | // { | ||
305 | //if (m_ids.ContainsKey(avatar.UUID)) | ||
306 | //{ | ||
307 | // close the event queue. | ||
308 | //m_ids[avatar.UUID] = -1; | ||
309 | //} | ||
310 | //} | ||
311 | } | 246 | } |
312 | 247 | ||
313 | /// <summary> | 248 | /// <summary> |
@@ -322,85 +257,109 @@ namespace OpenSim.Region.ClientStack.Linden | |||
322 | public void OnRegisterCaps(UUID agentID, Caps caps) | 257 | public void OnRegisterCaps(UUID agentID, Caps caps) |
323 | { | 258 | { |
324 | // Register an event queue for the client | 259 | // Register an event queue for the client |
325 | 260 | m_log.DebugFormat( | |
326 | //m_log.DebugFormat( | 261 | "[EVENTQUEUE]: OnRegisterCaps: agentID {0} caps {1} region {2}", |
327 | // "[EVENTQUEUE]: OnRegisterCaps: agentID {0} caps {1} region {2}", | 262 | agentID, caps, m_scene.RegionInfo.RegionName); |
328 | // agentID, caps, m_scene.RegionInfo.RegionName); | ||
329 | |||
330 | // Let's instantiate a Queue for this agent right now | ||
331 | TryGetQueue(agentID); | ||
332 | 263 | ||
333 | UUID eventQueueGetUUID; | 264 | UUID eventQueueGetUUID; |
265 | Queue<OSD> queue; | ||
266 | Random rnd = new Random(Environment.TickCount); | ||
267 | int nrnd = rnd.Next(30000000); | ||
268 | if (nrnd < 0) | ||
269 | nrnd = -nrnd; | ||
334 | 270 | ||
335 | lock (m_AvatarQueueUUIDMapping) | 271 | lock (queues) |
336 | { | 272 | { |
337 | // Reuse open queues. The client does! | 273 | if (queues.ContainsKey(agentID)) |
338 | if (m_AvatarQueueUUIDMapping.ContainsKey(agentID)) | 274 | queue = queues[agentID]; |
275 | else | ||
276 | queue = null; | ||
277 | |||
278 | if (queue == null) | ||
339 | { | 279 | { |
340 | //m_log.DebugFormat("[EVENTQUEUE]: Found Existing UUID!"); | 280 | queue = new Queue<OSD>(); |
341 | eventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID]; | 281 | queues[agentID] = queue; |
282 | |||
283 | // push markers to handle old responses still waiting | ||
284 | // this will cost at most viewer getting two forced noevents | ||
285 | // even being a new queue better be safe | ||
286 | queue.Enqueue(null); | ||
287 | queue.Enqueue(null); // one should be enough | ||
288 | |||
289 | lock (m_AvatarQueueUUIDMapping) | ||
290 | { | ||
291 | eventQueueGetUUID = UUID.Random(); | ||
292 | if (m_AvatarQueueUUIDMapping.ContainsKey(agentID)) | ||
293 | { | ||
294 | // oops this should not happen ? | ||
295 | m_log.DebugFormat("[EVENTQUEUE]: Found Existing UUID without a queue"); | ||
296 | eventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID]; | ||
297 | } | ||
298 | m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID); | ||
299 | } | ||
300 | lock (m_ids) | ||
301 | { | ||
302 | if (!m_ids.ContainsKey(agentID)) | ||
303 | m_ids.Add(agentID, nrnd); | ||
304 | else | ||
305 | m_ids[agentID] = nrnd; | ||
306 | } | ||
342 | } | 307 | } |
343 | else | 308 | else |
344 | { | 309 | { |
345 | eventQueueGetUUID = UUID.Random(); | 310 | // push markers to handle old responses still waiting |
346 | //m_log.DebugFormat("[EVENTQUEUE]: Using random UUID!"); | 311 | // this will cost at most viewer getting two forced noevents |
312 | // even being a new queue better be safe | ||
313 | queue.Enqueue(null); | ||
314 | queue.Enqueue(null); // one should be enough | ||
315 | |||
316 | // reuse or not to reuse TODO FIX | ||
317 | lock (m_AvatarQueueUUIDMapping) | ||
318 | { | ||
319 | // Reuse open queues. The client does! | ||
320 | // Its reuse caps path not queues those are been reused already | ||
321 | if (m_AvatarQueueUUIDMapping.ContainsKey(agentID)) | ||
322 | { | ||
323 | m_log.DebugFormat("[EVENTQUEUE]: Found Existing UUID!"); | ||
324 | eventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID]; | ||
325 | } | ||
326 | else | ||
327 | { | ||
328 | eventQueueGetUUID = UUID.Random(); | ||
329 | m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID); | ||
330 | m_log.DebugFormat("[EVENTQUEUE]: Using random UUID!"); | ||
331 | } | ||
332 | } | ||
333 | lock (m_ids) | ||
334 | { | ||
335 | // change to negative numbers so they are changed at end of sending first marker | ||
336 | // old data on a queue may be sent on a response for a new caps | ||
337 | // but at least will be sent with coerent IDs | ||
338 | if (!m_ids.ContainsKey(agentID)) | ||
339 | m_ids.Add(agentID, -nrnd); // should not happen | ||
340 | else | ||
341 | m_ids[agentID] = -m_ids[agentID]; | ||
342 | } | ||
347 | } | 343 | } |
348 | } | 344 | } |
349 | 345 | ||
350 | lock (m_QueueUUIDAvatarMapping) | 346 | caps.RegisterPollHandler( |
351 | { | 347 | "EventQueueGet", |
352 | if (!m_QueueUUIDAvatarMapping.ContainsKey(eventQueueGetUUID)) | 348 | new PollServiceEventArgs(null, GenerateEqgCapPath(eventQueueGetUUID), HasEvents, GetEvents, NoEvents, agentID, SERVER_EQ_TIME_NO_EVENTS)); |
353 | m_QueueUUIDAvatarMapping.Add(eventQueueGetUUID, agentID); | ||
354 | } | ||
355 | |||
356 | lock (m_AvatarQueueUUIDMapping) | ||
357 | { | ||
358 | if (!m_AvatarQueueUUIDMapping.ContainsKey(agentID)) | ||
359 | m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID); | ||
360 | } | ||
361 | |||
362 | string eventQueueGetPath = GenerateEqgCapPath(eventQueueGetUUID); | ||
363 | |||
364 | // Register this as a caps handler | ||
365 | // FIXME: Confusingly, we need to register separate as a capability so that the client is told about | ||
366 | // EventQueueGet when it receive capability information, but then we replace the rest handler immediately | ||
367 | // afterwards with the poll service. So for now, we'll pass a null instead to simplify code reading, but | ||
368 | // really it should be possible to directly register the poll handler as a capability. | ||
369 | caps.RegisterHandler("EventQueueGet", new RestHTTPHandler("POST", eventQueueGetPath, null)); | ||
370 | // delegate(Hashtable m_dhttpMethod) | ||
371 | // { | ||
372 | // return ProcessQueue(m_dhttpMethod, agentID, caps); | ||
373 | // })); | ||
374 | |||
375 | // This will persist this beyond the expiry of the caps handlers | ||
376 | // TODO: Add EventQueueGet name/description for diagnostics | ||
377 | MainServer.Instance.AddPollServiceHTTPHandler( | ||
378 | eventQueueGetPath, | ||
379 | new PollServiceEventArgs(null, HasEvents, GetEvents, NoEvents, agentID, 40000)); | ||
380 | |||
381 | // m_log.DebugFormat( | ||
382 | // "[EVENT QUEUE GET MODULE]: Registered EQG handler {0} for {1} in {2}", | ||
383 | // eventQueueGetPath, agentID, m_scene.RegionInfo.RegionName); | ||
384 | |||
385 | Random rnd = new Random(Environment.TickCount); | ||
386 | lock (m_ids) | ||
387 | { | ||
388 | if (!m_ids.ContainsKey(agentID)) | ||
389 | m_ids.Add(agentID, rnd.Next(30000000)); | ||
390 | } | ||
391 | } | 349 | } |
392 | 350 | ||
393 | public bool HasEvents(UUID requestID, UUID agentID) | 351 | public bool HasEvents(UUID requestID, UUID agentID) |
394 | { | 352 | { |
395 | // Don't use this, because of race conditions at agent closing time | ||
396 | //Queue<OSD> queue = TryGetQueue(agentID); | ||
397 | |||
398 | Queue<OSD> queue = GetQueue(agentID); | 353 | Queue<OSD> queue = GetQueue(agentID); |
399 | if (queue != null) | 354 | if (queue != null) |
400 | lock (queue) | 355 | lock (queue) |
356 | { | ||
357 | //m_log.WarnFormat("POLLED FOR EVENTS BY {0} in {1} -- {2}", agentID, m_scene.RegionInfo.RegionName, queue.Count); | ||
401 | return queue.Count > 0; | 358 | return queue.Count > 0; |
359 | } | ||
402 | 360 | ||
403 | return false; | 361 | //m_log.WarnFormat("POLLED FOR EVENTS BY {0} unknown agent", agentID); |
362 | return true; | ||
404 | } | 363 | } |
405 | 364 | ||
406 | /// <summary> | 365 | /// <summary> |
@@ -414,65 +373,80 @@ namespace OpenSim.Region.ClientStack.Linden | |||
414 | OSDMap ev = (OSDMap)element; | 373 | OSDMap ev = (OSDMap)element; |
415 | m_log.DebugFormat( | 374 | m_log.DebugFormat( |
416 | "Eq OUT {0,-30} to {1,-20} {2,-20}", | 375 | "Eq OUT {0,-30} to {1,-20} {2,-20}", |
417 | ev["message"], m_scene.GetScenePresence(agentId).Name, m_scene.RegionInfo.RegionName); | 376 | ev["message"], m_scene.GetScenePresence(agentId).Name, m_scene.Name); |
418 | } | 377 | } |
419 | } | 378 | } |
420 | 379 | ||
421 | public Hashtable GetEvents(UUID requestID, UUID pAgentId) | 380 | public Hashtable GetEvents(UUID requestID, UUID pAgentId) |
422 | { | 381 | { |
423 | if (DebugLevel >= 2) | 382 | if (DebugLevel >= 2) |
424 | m_log.DebugFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.RegionInfo.RegionName); | 383 | m_log.WarnFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.Name); |
425 | 384 | ||
426 | Queue<OSD> queue = TryGetQueue(pAgentId); | 385 | Queue<OSD> queue = GetQueue(pAgentId); |
427 | OSD element; | 386 | if (queue == null) |
428 | lock (queue) | ||
429 | { | 387 | { |
430 | if (queue.Count == 0) | 388 | return NoEvents(requestID, pAgentId); |
431 | return NoEvents(requestID, pAgentId); | ||
432 | element = queue.Dequeue(); // 15s timeout | ||
433 | } | 389 | } |
434 | 390 | ||
391 | OSD element = null;; | ||
392 | OSDArray array = new OSDArray(); | ||
435 | int thisID = 0; | 393 | int thisID = 0; |
436 | lock (m_ids) | 394 | bool negativeID = false; |
437 | thisID = m_ids[pAgentId]; | ||
438 | 395 | ||
439 | OSDArray array = new OSDArray(); | 396 | lock (queue) |
440 | if (element == null) // didn't have an event in 15s | ||
441 | { | ||
442 | // Send it a fake event to keep the client polling! It doesn't like 502s like the proxys say! | ||
443 | array.Add(EventQueueHelper.KeepAliveEvent()); | ||
444 | //m_log.DebugFormat("[EVENTQUEUE]: adding fake event for {0} in region {1}", pAgentId, m_scene.RegionInfo.RegionName); | ||
445 | } | ||
446 | else | ||
447 | { | 397 | { |
448 | if (DebugLevel > 0) | 398 | if (queue.Count == 0) |
449 | LogOutboundDebugMessage(element, pAgentId); | 399 | return NoEvents(requestID, pAgentId); |
450 | 400 | ||
451 | array.Add(element); | 401 | lock (m_ids) |
402 | thisID = m_ids[pAgentId]; | ||
452 | 403 | ||
453 | lock (queue) | 404 | if (thisID < 0) |
454 | { | 405 | { |
455 | while (queue.Count > 0) | 406 | negativeID = true; |
456 | { | 407 | thisID = -thisID; |
457 | element = queue.Dequeue(); | 408 | } |
409 | |||
410 | while (queue.Count > 0) | ||
411 | { | ||
412 | element = queue.Dequeue(); | ||
413 | // add elements until a marker is found | ||
414 | // so they get into a response | ||
415 | if (element == null) | ||
416 | break; | ||
417 | if (DebugLevel > 0) | ||
418 | LogOutboundDebugMessage(element, pAgentId); | ||
419 | array.Add(element); | ||
420 | thisID++; | ||
421 | } | ||
422 | } | ||
458 | 423 | ||
459 | if (DebugLevel > 0) | 424 | OSDMap events = null; |
460 | LogOutboundDebugMessage(element, pAgentId); | ||
461 | 425 | ||
462 | array.Add(element); | 426 | if (array.Count > 0) |
463 | thisID++; | 427 | { |
464 | } | 428 | events = new OSDMap(); |
465 | } | 429 | events.Add("events", array); |
430 | events.Add("id", new OSDInteger(thisID)); | ||
466 | } | 431 | } |
467 | 432 | ||
468 | OSDMap events = new OSDMap(); | 433 | if (negativeID && element == null) |
469 | events.Add("events", array); | 434 | { |
435 | Random rnd = new Random(Environment.TickCount); | ||
436 | thisID = rnd.Next(30000000); | ||
437 | if (thisID < 0) | ||
438 | thisID = -thisID; | ||
439 | } | ||
470 | 440 | ||
471 | events.Add("id", new OSDInteger(thisID)); | ||
472 | lock (m_ids) | 441 | lock (m_ids) |
473 | { | 442 | { |
474 | m_ids[pAgentId] = thisID + 1; | 443 | m_ids[pAgentId] = thisID + 1; |
475 | } | 444 | } |
445 | |||
446 | // if there where no elements before a marker send a NoEvents | ||
447 | if (array.Count == 0) | ||
448 | return NoEvents(requestID, pAgentId); | ||
449 | |||
476 | Hashtable responsedata = new Hashtable(); | 450 | Hashtable responsedata = new Hashtable(); |
477 | responsedata["int_response_code"] = 200; | 451 | responsedata["int_response_code"] = 200; |
478 | responsedata["content_type"] = "application/xml"; | 452 | responsedata["content_type"] = "application/xml"; |
@@ -495,289 +469,53 @@ namespace OpenSim.Region.ClientStack.Linden | |||
495 | responsedata["http_protocol_version"] = "HTTP/1.0"; | 469 | responsedata["http_protocol_version"] = "HTTP/1.0"; |
496 | return responsedata; | 470 | return responsedata; |
497 | } | 471 | } |
498 | 472 | ||
499 | // public Hashtable ProcessQueue(Hashtable request, UUID agentID, Caps caps) | ||
500 | // { | ||
501 | // // TODO: this has to be redone to not busy-wait (and block the thread), | ||
502 | // // TODO: as soon as we have a non-blocking way to handle HTTP-requests. | ||
503 | // | ||
504 | //// if (m_log.IsDebugEnabled) | ||
505 | //// { | ||
506 | //// String debug = "[EVENTQUEUE]: Got request for agent {0} in region {1} from thread {2}: [ "; | ||
507 | //// foreach (object key in request.Keys) | ||
508 | //// { | ||
509 | //// debug += key.ToString() + "=" + request[key].ToString() + " "; | ||
510 | //// } | ||
511 | //// m_log.DebugFormat(debug + " ]", agentID, m_scene.RegionInfo.RegionName, System.Threading.Thread.CurrentThread.Name); | ||
512 | //// } | ||
513 | // | ||
514 | // Queue<OSD> queue = TryGetQueue(agentID); | ||
515 | // OSD element; | ||
516 | // | ||
517 | // lock (queue) | ||
518 | // element = queue.Dequeue(); // 15s timeout | ||
519 | // | ||
520 | // Hashtable responsedata = new Hashtable(); | ||
521 | // | ||
522 | // int thisID = 0; | ||
523 | // lock (m_ids) | ||
524 | // thisID = m_ids[agentID]; | ||
525 | // | ||
526 | // if (element == null) | ||
527 | // { | ||
528 | // //m_log.ErrorFormat("[EVENTQUEUE]: Nothing to process in " + m_scene.RegionInfo.RegionName); | ||
529 | // if (thisID == -1) // close-request | ||
530 | // { | ||
531 | // m_log.ErrorFormat("[EVENTQUEUE]: 404 in " + m_scene.RegionInfo.RegionName); | ||
532 | // responsedata["int_response_code"] = 404; //501; //410; //404; | ||
533 | // responsedata["content_type"] = "text/plain"; | ||
534 | // responsedata["keepalive"] = false; | ||
535 | // responsedata["str_response_string"] = "Closed EQG"; | ||
536 | // return responsedata; | ||
537 | // } | ||
538 | // responsedata["int_response_code"] = 502; | ||
539 | // responsedata["content_type"] = "text/plain"; | ||
540 | // responsedata["keepalive"] = false; | ||
541 | // responsedata["str_response_string"] = "Upstream error: "; | ||
542 | // responsedata["error_status_text"] = "Upstream error:"; | ||
543 | // responsedata["http_protocol_version"] = "HTTP/1.0"; | ||
544 | // return responsedata; | ||
545 | // } | ||
546 | // | ||
547 | // OSDArray array = new OSDArray(); | ||
548 | // if (element == null) // didn't have an event in 15s | ||
549 | // { | ||
550 | // // Send it a fake event to keep the client polling! It doesn't like 502s like the proxys say! | ||
551 | // array.Add(EventQueueHelper.KeepAliveEvent()); | ||
552 | // //m_log.DebugFormat("[EVENTQUEUE]: adding fake event for {0} in region {1}", agentID, m_scene.RegionInfo.RegionName); | ||
553 | // } | ||
554 | // else | ||
555 | // { | ||
556 | // array.Add(element); | ||
557 | // | ||
558 | // if (element is OSDMap) | ||
559 | // { | ||
560 | // OSDMap ev = (OSDMap)element; | ||
561 | // m_log.DebugFormat( | ||
562 | // "[EVENT QUEUE GET MODULE]: Eq OUT {0} to {1}", | ||
563 | // ev["message"], m_scene.GetScenePresence(agentID).Name); | ||
564 | // } | ||
565 | // | ||
566 | // lock (queue) | ||
567 | // { | ||
568 | // while (queue.Count > 0) | ||
569 | // { | ||
570 | // element = queue.Dequeue(); | ||
571 | // | ||
572 | // if (element is OSDMap) | ||
573 | // { | ||
574 | // OSDMap ev = (OSDMap)element; | ||
575 | // m_log.DebugFormat( | ||
576 | // "[EVENT QUEUE GET MODULE]: Eq OUT {0} to {1}", | ||
577 | // ev["message"], m_scene.GetScenePresence(agentID).Name); | ||
578 | // } | ||
579 | // | ||
580 | // array.Add(element); | ||
581 | // thisID++; | ||
582 | // } | ||
583 | // } | ||
584 | // } | ||
585 | // | ||
586 | // OSDMap events = new OSDMap(); | ||
587 | // events.Add("events", array); | ||
588 | // | ||
589 | // events.Add("id", new OSDInteger(thisID)); | ||
590 | // lock (m_ids) | ||
591 | // { | ||
592 | // m_ids[agentID] = thisID + 1; | ||
593 | // } | ||
594 | // | ||
595 | // responsedata["int_response_code"] = 200; | ||
596 | // responsedata["content_type"] = "application/xml"; | ||
597 | // responsedata["keepalive"] = false; | ||
598 | // responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(events); | ||
599 | // | ||
600 | // m_log.DebugFormat("[EVENTQUEUE]: sending response for {0} in region {1}: {2}", agentID, m_scene.RegionInfo.RegionName, responsedata["str_response_string"]); | ||
601 | // | ||
602 | // return responsedata; | ||
603 | // } | ||
604 | |||
605 | // public Hashtable EventQueuePath2(Hashtable request) | ||
606 | // { | ||
607 | // string capuuid = (string)request["uri"]; //path.Replace("/CAPS/EQG/",""); | ||
608 | // // pull off the last "/" in the path. | ||
609 | // Hashtable responsedata = new Hashtable(); | ||
610 | // capuuid = capuuid.Substring(0, capuuid.Length - 1); | ||
611 | // capuuid = capuuid.Replace("/CAPS/EQG/", ""); | ||
612 | // UUID AvatarID = UUID.Zero; | ||
613 | // UUID capUUID = UUID.Zero; | ||
614 | // | ||
615 | // // parse the path and search for the avatar with it registered | ||
616 | // if (UUID.TryParse(capuuid, out capUUID)) | ||
617 | // { | ||
618 | // lock (m_QueueUUIDAvatarMapping) | ||
619 | // { | ||
620 | // if (m_QueueUUIDAvatarMapping.ContainsKey(capUUID)) | ||
621 | // { | ||
622 | // AvatarID = m_QueueUUIDAvatarMapping[capUUID]; | ||
623 | // } | ||
624 | // } | ||
625 | // | ||
626 | // if (AvatarID != UUID.Zero) | ||
627 | // { | ||
628 | // return ProcessQueue(request, AvatarID, m_scene.CapsModule.GetCapsForUser(AvatarID)); | ||
629 | // } | ||
630 | // else | ||
631 | // { | ||
632 | // responsedata["int_response_code"] = 404; | ||
633 | // responsedata["content_type"] = "text/plain"; | ||
634 | // responsedata["keepalive"] = false; | ||
635 | // responsedata["str_response_string"] = "Not Found"; | ||
636 | // responsedata["error_status_text"] = "Not Found"; | ||
637 | // responsedata["http_protocol_version"] = "HTTP/1.0"; | ||
638 | // return responsedata; | ||
639 | // // return 404 | ||
640 | // } | ||
641 | // } | ||
642 | // else | ||
643 | // { | ||
644 | // responsedata["int_response_code"] = 404; | ||
645 | // responsedata["content_type"] = "text/plain"; | ||
646 | // responsedata["keepalive"] = false; | ||
647 | // responsedata["str_response_string"] = "Not Found"; | ||
648 | // responsedata["error_status_text"] = "Not Found"; | ||
649 | // responsedata["http_protocol_version"] = "HTTP/1.0"; | ||
650 | // return responsedata; | ||
651 | // // return 404 | ||
652 | // } | ||
653 | // } | ||
654 | |||
655 | public OSD EventQueueFallBack(string path, OSD request, string endpoint) | ||
656 | { | ||
657 | // This is a fallback element to keep the client from loosing EventQueueGet | ||
658 | // Why does CAPS fail sometimes!? | ||
659 | m_log.Warn("[EVENTQUEUE]: In the Fallback handler! We lost the Queue in the rest handler!"); | ||
660 | string capuuid = path.Replace("/CAPS/EQG/",""); | ||
661 | capuuid = capuuid.Substring(0, capuuid.Length - 1); | ||
662 | |||
663 | // UUID AvatarID = UUID.Zero; | ||
664 | UUID capUUID = UUID.Zero; | ||
665 | if (UUID.TryParse(capuuid, out capUUID)) | ||
666 | { | ||
667 | /* Don't remove this yet code cleaners! | ||
668 | * Still testing this! | ||
669 | * | ||
670 | lock (m_QueueUUIDAvatarMapping) | ||
671 | { | ||
672 | if (m_QueueUUIDAvatarMapping.ContainsKey(capUUID)) | ||
673 | { | ||
674 | AvatarID = m_QueueUUIDAvatarMapping[capUUID]; | ||
675 | } | ||
676 | } | ||
677 | |||
678 | |||
679 | if (AvatarID != UUID.Zero) | ||
680 | { | ||
681 | // Repair the CAP! | ||
682 | //OpenSim.Framework.Capabilities.Caps caps = m_scene.GetCapsHandlerForUser(AvatarID); | ||
683 | //string capsBase = "/CAPS/EQG/"; | ||
684 | //caps.RegisterHandler("EventQueueGet", | ||
685 | //new RestHTTPHandler("POST", capsBase + capUUID.ToString() + "/", | ||
686 | //delegate(Hashtable m_dhttpMethod) | ||
687 | //{ | ||
688 | // return ProcessQueue(m_dhttpMethod, AvatarID, caps); | ||
689 | //})); | ||
690 | // start new ID sequence. | ||
691 | Random rnd = new Random(System.Environment.TickCount); | ||
692 | lock (m_ids) | ||
693 | { | ||
694 | if (!m_ids.ContainsKey(AvatarID)) | ||
695 | m_ids.Add(AvatarID, rnd.Next(30000000)); | ||
696 | } | ||
697 | |||
698 | |||
699 | int thisID = 0; | ||
700 | lock (m_ids) | ||
701 | thisID = m_ids[AvatarID]; | ||
702 | |||
703 | BlockingLLSDQueue queue = GetQueue(AvatarID); | ||
704 | OSDArray array = new OSDArray(); | ||
705 | LLSD element = queue.Dequeue(15000); // 15s timeout | ||
706 | if (element == null) | ||
707 | { | ||
708 | |||
709 | array.Add(EventQueueHelper.KeepAliveEvent()); | ||
710 | } | ||
711 | else | ||
712 | { | ||
713 | array.Add(element); | ||
714 | while (queue.Count() > 0) | ||
715 | { | ||
716 | array.Add(queue.Dequeue(1)); | ||
717 | thisID++; | ||
718 | } | ||
719 | } | ||
720 | OSDMap events = new OSDMap(); | ||
721 | events.Add("events", array); | ||
722 | |||
723 | events.Add("id", new LLSDInteger(thisID)); | ||
724 | |||
725 | lock (m_ids) | ||
726 | { | ||
727 | m_ids[AvatarID] = thisID + 1; | ||
728 | } | ||
729 | |||
730 | return events; | ||
731 | } | ||
732 | else | ||
733 | { | ||
734 | return new LLSD(); | ||
735 | } | ||
736 | * | ||
737 | */ | ||
738 | } | ||
739 | else | ||
740 | { | ||
741 | //return new LLSD(); | ||
742 | } | ||
743 | |||
744 | return new OSDString("shutdown404!"); | ||
745 | } | ||
746 | |||
747 | public void DisableSimulator(ulong handle, UUID avatarID) | 473 | public void DisableSimulator(ulong handle, UUID avatarID) |
748 | { | 474 | { |
749 | OSD item = EventQueueHelper.DisableSimulator(handle); | 475 | OSD item = EventQueueHelper.DisableSimulator(handle); |
750 | Enqueue(item, avatarID); | 476 | Enqueue(item, avatarID); |
751 | } | 477 | } |
752 | 478 | ||
753 | public virtual void EnableSimulator(ulong handle, IPEndPoint endPoint, UUID avatarID) | 479 | public virtual void EnableSimulator(ulong handle, IPEndPoint endPoint, UUID avatarID, int regionSizeX, int regionSizeY) |
754 | { | 480 | { |
755 | OSD item = EventQueueHelper.EnableSimulator(handle, endPoint); | 481 | m_log.DebugFormat("{0} EnableSimulator. handle={1}, avatarID={2}, regionSize={3},{4}>", |
482 | "[EVENT QUEUE GET MODULE]", handle, avatarID, regionSizeX, regionSizeY); | ||
483 | |||
484 | OSD item = EventQueueHelper.EnableSimulator(handle, endPoint, regionSizeX, regionSizeY); | ||
756 | Enqueue(item, avatarID); | 485 | Enqueue(item, avatarID); |
757 | } | 486 | } |
758 | 487 | ||
759 | public virtual void EstablishAgentCommunication(UUID avatarID, IPEndPoint endPoint, string capsPath) | 488 | public virtual void EstablishAgentCommunication(UUID avatarID, IPEndPoint endPoint, string capsPath, |
489 | ulong regionHandle, int regionSizeX, int regionSizeY) | ||
760 | { | 490 | { |
761 | OSD item = EventQueueHelper.EstablishAgentCommunication(avatarID, endPoint.ToString(), capsPath); | 491 | m_log.DebugFormat("{0} EstablishAgentCommunication. handle={1}, avatarID={2}, regionSize={3},{4}>", |
492 | "[EVENT QUEUE GET MODULE]", regionHandle, avatarID, regionSizeX, regionSizeY); | ||
493 | OSD item = EventQueueHelper.EstablishAgentCommunication(avatarID, endPoint.ToString(), capsPath, regionHandle, regionSizeX, regionSizeY); | ||
762 | Enqueue(item, avatarID); | 494 | Enqueue(item, avatarID); |
763 | } | 495 | } |
764 | 496 | ||
765 | public virtual void TeleportFinishEvent(ulong regionHandle, byte simAccess, | 497 | public virtual void TeleportFinishEvent(ulong regionHandle, byte simAccess, |
766 | IPEndPoint regionExternalEndPoint, | 498 | IPEndPoint regionExternalEndPoint, |
767 | uint locationID, uint flags, string capsURL, | 499 | uint locationID, uint flags, string capsURL, |
768 | UUID avatarID) | 500 | UUID avatarID, int regionSizeX, int regionSizeY) |
769 | { | 501 | { |
502 | m_log.DebugFormat("{0} TeleportFinishEvent. handle={1}, avatarID={2}, regionSize={3},{4}>", | ||
503 | "[EVENT QUEUE GET MODULE]", regionHandle, avatarID, regionSizeX, regionSizeY); | ||
504 | |||
770 | OSD item = EventQueueHelper.TeleportFinishEvent(regionHandle, simAccess, regionExternalEndPoint, | 505 | OSD item = EventQueueHelper.TeleportFinishEvent(regionHandle, simAccess, regionExternalEndPoint, |
771 | locationID, flags, capsURL, avatarID); | 506 | locationID, flags, capsURL, avatarID, regionSizeX, regionSizeY); |
772 | Enqueue(item, avatarID); | 507 | Enqueue(item, avatarID); |
773 | } | 508 | } |
774 | 509 | ||
775 | public virtual void CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt, | 510 | public virtual void CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt, |
776 | IPEndPoint newRegionExternalEndPoint, | 511 | IPEndPoint newRegionExternalEndPoint, |
777 | string capsURL, UUID avatarID, UUID sessionID) | 512 | string capsURL, UUID avatarID, UUID sessionID, int regionSizeX, int regionSizeY) |
778 | { | 513 | { |
514 | m_log.DebugFormat("{0} CrossRegion. handle={1}, avatarID={2}, regionSize={3},{4}>", | ||
515 | "[EVENT QUEUE GET MODULE]", handle, avatarID, regionSizeX, regionSizeY); | ||
516 | |||
779 | OSD item = EventQueueHelper.CrossRegion(handle, pos, lookAt, newRegionExternalEndPoint, | 517 | OSD item = EventQueueHelper.CrossRegion(handle, pos, lookAt, newRegionExternalEndPoint, |
780 | capsURL, avatarID, sessionID); | 518 | capsURL, avatarID, sessionID, regionSizeX, regionSizeY); |
781 | Enqueue(item, avatarID); | 519 | Enqueue(item, avatarID); |
782 | } | 520 | } |
783 | 521 | ||
@@ -794,12 +532,12 @@ namespace OpenSim.Region.ClientStack.Linden | |||
794 | 532 | ||
795 | } | 533 | } |
796 | 534 | ||
797 | public void ChatterBoxSessionAgentListUpdates(UUID sessionID, UUID fromAgent, UUID toAgent, bool canVoiceChat, | 535 | public void ChatterBoxSessionAgentListUpdates(UUID sessionID, UUID fromAgent, UUID anotherAgent, bool canVoiceChat, |
798 | bool isModerator, bool textMute) | 536 | bool isModerator, bool textMute) |
799 | { | 537 | { |
800 | OSD item = EventQueueHelper.ChatterBoxSessionAgentListUpdates(sessionID, fromAgent, canVoiceChat, | 538 | OSD item = EventQueueHelper.ChatterBoxSessionAgentListUpdates(sessionID, fromAgent, canVoiceChat, |
801 | isModerator, textMute); | 539 | isModerator, textMute); |
802 | Enqueue(item, toAgent); | 540 | Enqueue(item, fromAgent); |
803 | //m_log.InfoFormat("########### eq ChatterBoxSessionAgentListUpdates #############\n{0}", item); | 541 | //m_log.InfoFormat("########### eq ChatterBoxSessionAgentListUpdates #############\n{0}", item); |
804 | } | 542 | } |
805 | 543 | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs index 7dcf137..3fb7de2 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs | |||
@@ -70,13 +70,15 @@ namespace OpenSim.Region.ClientStack.Linden | |||
70 | return llsdEvent; | 70 | return llsdEvent; |
71 | } | 71 | } |
72 | 72 | ||
73 | public static OSD EnableSimulator(ulong handle, IPEndPoint endPoint) | 73 | public static OSD EnableSimulator(ulong handle, IPEndPoint endPoint, int regionSizeX, int regionSizeY) |
74 | { | 74 | { |
75 | OSDMap llsdSimInfo = new OSDMap(3); | 75 | OSDMap llsdSimInfo = new OSDMap(5); |
76 | 76 | ||
77 | llsdSimInfo.Add("Handle", new OSDBinary(ulongToByteArray(handle))); | 77 | llsdSimInfo.Add("Handle", new OSDBinary(ulongToByteArray(handle))); |
78 | llsdSimInfo.Add("IP", new OSDBinary(endPoint.Address.GetAddressBytes())); | 78 | llsdSimInfo.Add("IP", new OSDBinary(endPoint.Address.GetAddressBytes())); |
79 | llsdSimInfo.Add("Port", new OSDInteger(endPoint.Port)); | 79 | llsdSimInfo.Add("Port", new OSDInteger(endPoint.Port)); |
80 | llsdSimInfo.Add("RegionSizeX", new OSDInteger(regionSizeX)); | ||
81 | llsdSimInfo.Add("RegionSizeY", new OSDInteger(regionSizeY)); | ||
80 | 82 | ||
81 | OSDArray arr = new OSDArray(1); | 83 | OSDArray arr = new OSDArray(1); |
82 | arr.Add(llsdSimInfo); | 84 | arr.Add(llsdSimInfo); |
@@ -104,7 +106,8 @@ namespace OpenSim.Region.ClientStack.Linden | |||
104 | 106 | ||
105 | public static OSD CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt, | 107 | public static OSD CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt, |
106 | IPEndPoint newRegionExternalEndPoint, | 108 | IPEndPoint newRegionExternalEndPoint, |
107 | string capsURL, UUID agentID, UUID sessionID) | 109 | string capsURL, UUID agentID, UUID sessionID, |
110 | int regionSizeX, int regionSizeY) | ||
108 | { | 111 | { |
109 | OSDArray lookAtArr = new OSDArray(3); | 112 | OSDArray lookAtArr = new OSDArray(3); |
110 | lookAtArr.Add(OSD.FromReal(lookAt.X)); | 113 | lookAtArr.Add(OSD.FromReal(lookAt.X)); |
@@ -130,11 +133,13 @@ namespace OpenSim.Region.ClientStack.Linden | |||
130 | OSDArray agentDataArr = new OSDArray(1); | 133 | OSDArray agentDataArr = new OSDArray(1); |
131 | agentDataArr.Add(agentDataMap); | 134 | agentDataArr.Add(agentDataMap); |
132 | 135 | ||
133 | OSDMap regionDataMap = new OSDMap(4); | 136 | OSDMap regionDataMap = new OSDMap(6); |
134 | regionDataMap.Add("RegionHandle", OSD.FromBinary(ulongToByteArray(handle))); | 137 | regionDataMap.Add("RegionHandle", OSD.FromBinary(ulongToByteArray(handle))); |
135 | regionDataMap.Add("SeedCapability", OSD.FromString(capsURL)); | 138 | regionDataMap.Add("SeedCapability", OSD.FromString(capsURL)); |
136 | regionDataMap.Add("SimIP", OSD.FromBinary(newRegionExternalEndPoint.Address.GetAddressBytes())); | 139 | regionDataMap.Add("SimIP", OSD.FromBinary(newRegionExternalEndPoint.Address.GetAddressBytes())); |
137 | regionDataMap.Add("SimPort", OSD.FromInteger(newRegionExternalEndPoint.Port)); | 140 | regionDataMap.Add("SimPort", OSD.FromInteger(newRegionExternalEndPoint.Port)); |
141 | regionDataMap.Add("RegionSizeX", new OSDInteger(regionSizeX)); | ||
142 | regionDataMap.Add("RegionSizeY", new OSDInteger(regionSizeY)); | ||
138 | 143 | ||
139 | OSDArray regionDataArr = new OSDArray(1); | 144 | OSDArray regionDataArr = new OSDArray(1); |
140 | regionDataArr.Add(regionDataMap); | 145 | regionDataArr.Add(regionDataMap); |
@@ -148,8 +153,9 @@ namespace OpenSim.Region.ClientStack.Linden | |||
148 | } | 153 | } |
149 | 154 | ||
150 | public static OSD TeleportFinishEvent( | 155 | public static OSD TeleportFinishEvent( |
151 | ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint, | 156 | ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint, |
152 | uint locationID, uint flags, string capsURL, UUID agentID) | 157 | uint locationID, uint flags, string capsURL, UUID agentID, |
158 | int regionSizeX, int regionSizeY) | ||
153 | { | 159 | { |
154 | // not sure why flags get overwritten here | 160 | // not sure why flags get overwritten here |
155 | if ((flags & (uint)TeleportFlags.IsFlying) != 0) | 161 | if ((flags & (uint)TeleportFlags.IsFlying) != 0) |
@@ -167,6 +173,8 @@ namespace OpenSim.Region.ClientStack.Linden | |||
167 | info.Add("SimPort", OSD.FromInteger(regionExternalEndPoint.Port)); | 173 | info.Add("SimPort", OSD.FromInteger(regionExternalEndPoint.Port)); |
168 | // info.Add("TeleportFlags", OSD.FromULong(1L << 4)); // AgentManager.TeleportFlags.ViaLocation | 174 | // info.Add("TeleportFlags", OSD.FromULong(1L << 4)); // AgentManager.TeleportFlags.ViaLocation |
169 | info.Add("TeleportFlags", OSD.FromUInteger(flags)); | 175 | info.Add("TeleportFlags", OSD.FromUInteger(flags)); |
176 | info.Add("RegionSizeX", new OSDInteger(regionSizeX)); | ||
177 | info.Add("RegionSizeY", new OSDInteger(regionSizeY)); | ||
170 | 178 | ||
171 | OSDArray infoArr = new OSDArray(); | 179 | OSDArray infoArr = new OSDArray(); |
172 | infoArr.Add(info); | 180 | infoArr.Add(info); |
@@ -194,12 +202,18 @@ namespace OpenSim.Region.ClientStack.Linden | |||
194 | return BuildEvent("ScriptRunningReply", body); | 202 | return BuildEvent("ScriptRunningReply", body); |
195 | } | 203 | } |
196 | 204 | ||
197 | public static OSD EstablishAgentCommunication(UUID agentID, string simIpAndPort, string seedcap) | 205 | public static OSD EstablishAgentCommunication(UUID agentID, string simIpAndPort, string seedcap, |
206 | ulong regionHandle, int regionSizeX, int regionSizeY) | ||
198 | { | 207 | { |
199 | OSDMap body = new OSDMap(3); | 208 | OSDMap body = new OSDMap(6) |
200 | body.Add("agent-id", new OSDUUID(agentID)); | 209 | { |
201 | body.Add("sim-ip-and-port", new OSDString(simIpAndPort)); | 210 | {"agent-id", new OSDUUID(agentID)}, |
202 | body.Add("seed-capability", new OSDString(seedcap)); | 211 | {"sim-ip-and-port", new OSDString(simIpAndPort)}, |
212 | {"seed-capability", new OSDString(seedcap)}, | ||
213 | {"region-handle", OSD.FromULong(regionHandle)}, | ||
214 | {"region-size-x", OSD.FromInteger(regionSizeX)}, | ||
215 | {"region-size-y", OSD.FromInteger(regionSizeY)} | ||
216 | }; | ||
203 | 217 | ||
204 | return BuildEvent("EstablishAgentCommunication", body); | 218 | return BuildEvent("EstablishAgentCommunication", body); |
205 | } | 219 | } |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs index 141af8a..9e24bce 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs | |||
@@ -76,7 +76,7 @@ namespace OpenSim.Region.ClientStack.Linden.Tests | |||
76 | } | 76 | } |
77 | 77 | ||
78 | [Test] | 78 | [Test] |
79 | public void AddForClient() | 79 | public void TestAddForClient() |
80 | { | 80 | { |
81 | TestHelpers.InMethod(); | 81 | TestHelpers.InMethod(); |
82 | // log4net.Config.XmlConfigurator.Configure(); | 82 | // log4net.Config.XmlConfigurator.Configure(); |
@@ -88,15 +88,15 @@ namespace OpenSim.Region.ClientStack.Linden.Tests | |||
88 | } | 88 | } |
89 | 89 | ||
90 | [Test] | 90 | [Test] |
91 | public void RemoveForClient() | 91 | public void TestRemoveForClient() |
92 | { | 92 | { |
93 | TestHelpers.InMethod(); | 93 | TestHelpers.InMethod(); |
94 | // log4net.Config.XmlConfigurator.Configure(); | 94 | // TestHelpers.EnableLogging(); |
95 | 95 | ||
96 | UUID spId = TestHelpers.ParseTail(0x1); | 96 | UUID spId = TestHelpers.ParseTail(0x1); |
97 | 97 | ||
98 | SceneHelpers.AddScenePresence(m_scene, spId); | 98 | SceneHelpers.AddScenePresence(m_scene, spId); |
99 | m_scene.IncomingCloseAgent(spId, false); | 99 | m_scene.CloseAgent(spId, false); |
100 | 100 | ||
101 | // TODO: Add more assertions for the other aspects of event queues | 101 | // TODO: Add more assertions for the other aspects of event queues |
102 | Assert.That(MainServer.Instance.GetPollServiceHandlerKeys().Count, Is.EqualTo(0)); | 102 | Assert.That(MainServer.Instance.GetPollServiceHandlerKeys().Count, Is.EqualTo(0)); |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs index 6ec1115..7b15284 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs | |||
@@ -246,8 +246,8 @@ namespace OpenSim.Region.ClientStack.Linden | |||
246 | 246 | ||
247 | private Scene m_scene; | 247 | private Scene m_scene; |
248 | private MeshCapsDataThrottler m_throttler; | 248 | private MeshCapsDataThrottler m_throttler; |
249 | public PollServiceMeshEventArgs(UUID pId, Scene scene) : | 249 | public PollServiceMeshEventArgs(string uri, UUID pId, Scene scene) : |
250 | base(null, null, null, null, pId, int.MaxValue) | 250 | base(null, uri, null, null, null, pId, int.MaxValue) |
251 | { | 251 | { |
252 | m_scene = scene; | 252 | m_scene = scene; |
253 | m_throttler = new MeshCapsDataThrottler(100000, 1400000, 10000, scene, pId); | 253 | m_throttler = new MeshCapsDataThrottler(100000, 1400000, 10000, scene, pId); |
@@ -361,7 +361,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
361 | string capUrl = "/CAPS/" + UUID.Random() + "/"; | 361 | string capUrl = "/CAPS/" + UUID.Random() + "/"; |
362 | 362 | ||
363 | // Register this as a poll service | 363 | // Register this as a poll service |
364 | PollServiceMeshEventArgs args = new PollServiceMeshEventArgs(agentID, m_scene); | 364 | PollServiceMeshEventArgs args = new PollServiceMeshEventArgs(capUrl, agentID, m_scene); |
365 | 365 | ||
366 | args.Type = PollServiceEventArgs.EventType.Mesh; | 366 | args.Type = PollServiceEventArgs.EventType.Mesh; |
367 | MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args); | 367 | MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args); |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs index 0570144..e053054 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs | |||
@@ -84,6 +84,8 @@ namespace OpenSim.Region.ClientStack.Linden | |||
84 | 84 | ||
85 | private Dictionary<UUID,PollServiceTextureEventArgs> m_pollservices = new Dictionary<UUID,PollServiceTextureEventArgs>(); | 85 | private Dictionary<UUID,PollServiceTextureEventArgs> m_pollservices = new Dictionary<UUID,PollServiceTextureEventArgs>(); |
86 | 86 | ||
87 | private string m_URL; | ||
88 | |||
87 | #region ISharedRegionModule Members | 89 | #region ISharedRegionModule Members |
88 | 90 | ||
89 | public void Initialise(IConfigSource source) | 91 | public void Initialise(IConfigSource source) |
@@ -215,7 +217,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
215 | private Scene m_scene; | 217 | private Scene m_scene; |
216 | private CapsDataThrottler m_throttler = new CapsDataThrottler(100000, 1400000,10000); | 218 | private CapsDataThrottler m_throttler = new CapsDataThrottler(100000, 1400000,10000); |
217 | public PollServiceTextureEventArgs(UUID pId, Scene scene) : | 219 | public PollServiceTextureEventArgs(UUID pId, Scene scene) : |
218 | base(null, null, null, null, pId, int.MaxValue) | 220 | base(null, "", null, null, null, pId, int.MaxValue) |
219 | { | 221 | { |
220 | m_scene = scene; | 222 | m_scene = scene; |
221 | // x is request id, y is userid | 223 | // x is request id, y is userid |
@@ -368,7 +370,11 @@ namespace OpenSim.Region.ClientStack.Linden | |||
368 | port = MainServer.Instance.SSLPort; | 370 | port = MainServer.Instance.SSLPort; |
369 | protocol = "https"; | 371 | protocol = "https"; |
370 | } | 372 | } |
371 | caps.RegisterHandler("GetTexture", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl)); | 373 | IExternalCapsModule handler = m_scene.RequestModuleInterface<IExternalCapsModule>(); |
374 | if (handler != null) | ||
375 | handler.RegisterExternalUserCapsHandler(agentID, caps, "GetTexture", capUrl); | ||
376 | else | ||
377 | caps.RegisterHandler("GetTexture", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl)); | ||
372 | m_pollservices[agentID] = args; | 378 | m_pollservices[agentID] = args; |
373 | m_capsDict[agentID] = capUrl; | 379 | m_capsDict[agentID] = capUrl; |
374 | } | 380 | } |
@@ -380,13 +386,11 @@ namespace OpenSim.Region.ClientStack.Linden | |||
380 | 386 | ||
381 | private void DeregisterCaps(UUID agentID, Caps caps) | 387 | private void DeregisterCaps(UUID agentID, Caps caps) |
382 | { | 388 | { |
383 | string capUrl; | ||
384 | PollServiceTextureEventArgs args; | 389 | PollServiceTextureEventArgs args; |
385 | if (m_capsDict.TryGetValue(agentID, out capUrl)) | 390 | |
386 | { | 391 | MainServer.Instance.RemoveHTTPHandler("", m_URL); |
387 | MainServer.Instance.RemoveHTTPHandler("", capUrl); | 392 | m_capsDict.Remove(agentID); |
388 | m_capsDict.Remove(agentID); | 393 | |
389 | } | ||
390 | if (m_pollservices.TryGetValue(agentID, out args)) | 394 | if (m_pollservices.TryGetValue(agentID, out args)) |
391 | { | 395 | { |
392 | m_pollservices.Remove(agentID); | 396 | m_pollservices.Remove(agentID); |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs index 92805e2..94f8bc1 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs | |||
@@ -155,6 +155,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
155 | Quaternion rotation = Quaternion.Identity; | 155 | Quaternion rotation = Quaternion.Identity; |
156 | Vector3 scale = Vector3.Zero; | 156 | Vector3 scale = Vector3.Zero; |
157 | int state = 0; | 157 | int state = 0; |
158 | int lastattach = 0; | ||
158 | 159 | ||
159 | if (r.Type != OSDType.Map) // not a proper req | 160 | if (r.Type != OSDType.Map) // not a proper req |
160 | return responsedata; | 161 | return responsedata; |
@@ -224,6 +225,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
224 | 225 | ||
225 | ray_target_id = ObjMap["RayTargetId"].AsUUID(); | 226 | ray_target_id = ObjMap["RayTargetId"].AsUUID(); |
226 | state = ObjMap["State"].AsInteger(); | 227 | state = ObjMap["State"].AsInteger(); |
228 | lastattach = ObjMap["LastAttachPoint"].AsInteger(); | ||
227 | try | 229 | try |
228 | { | 230 | { |
229 | ray_end = ((OSDArray)ObjMap["RayEnd"]).AsVector3(); | 231 | ray_end = ((OSDArray)ObjMap["RayEnd"]).AsVector3(); |
@@ -290,6 +292,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
290 | 292 | ||
291 | //session_id = rm["session_id"].AsUUID(); | 293 | //session_id = rm["session_id"].AsUUID(); |
292 | state = rm["state"].AsInteger(); | 294 | state = rm["state"].AsInteger(); |
295 | lastattach = rm["last_attach_point"].AsInteger(); | ||
293 | try | 296 | try |
294 | { | 297 | { |
295 | ray_end = ((OSDArray)rm["ray_end"]).AsVector3(); | 298 | ray_end = ((OSDArray)rm["ray_end"]).AsVector3(); |
@@ -331,6 +334,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
331 | pbs.ProfileEnd = (ushort)profile_end; | 334 | pbs.ProfileEnd = (ushort)profile_end; |
332 | pbs.Scale = scale; | 335 | pbs.Scale = scale; |
333 | pbs.State = (byte)state; | 336 | pbs.State = (byte)state; |
337 | pbs.LastAttachPoint = (byte)lastattach; | ||
334 | 338 | ||
335 | SceneObjectGroup obj = null; ; | 339 | SceneObjectGroup obj = null; ; |
336 | 340 | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs index 55a503e..769fe28 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs | |||
@@ -277,6 +277,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
277 | pbs.ProfileEnd = (ushort) obj.ProfileEnd; | 277 | pbs.ProfileEnd = (ushort) obj.ProfileEnd; |
278 | pbs.Scale = obj.Scale; | 278 | pbs.Scale = obj.Scale; |
279 | pbs.State = (byte) 0; | 279 | pbs.State = (byte) 0; |
280 | pbs.LastAttachPoint = (byte) 0; | ||
280 | SceneObjectPart prim = new SceneObjectPart(); | 281 | SceneObjectPart prim = new SceneObjectPart(); |
281 | prim.UUID = UUID.Random(); | 282 | prim.UUID = UUID.Random(); |
282 | prim.CreatorID = AgentId; | 283 | prim.CreatorID = AgentId; |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs b/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs index 595d01a..112608b 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs | |||
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices; | |||
29 | // Build Number | 29 | // Build Number |
30 | // Revision | 30 | // Revision |
31 | // | 31 | // |
32 | [assembly: AssemblyVersion("0.7.6.*")] | 32 | [assembly: AssemblyVersion("0.8.0.*")] |
33 | 33 | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs index 79d56c4..5196368 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs | |||
@@ -183,7 +183,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
183 | m_isGod = m_scene.Permissions.IsGod(agentID); | 183 | m_isGod = m_scene.Permissions.IsGod(agentID); |
184 | } | 184 | } |
185 | 185 | ||
186 | public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | 186 | protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) |
187 | { | 187 | { |
188 | StreamReader reader = new StreamReader(request); | 188 | StreamReader reader = new StreamReader(request); |
189 | string message = reader.ReadToEnd(); | 189 | string message = reader.ReadToEnd(); |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs index 7d9f935..e4d8a20 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs | |||
@@ -68,7 +68,6 @@ namespace OpenSim.Region.ClientStack.Linden | |||
68 | /// </summary> | 68 | /// </summary> |
69 | private OSDMap m_features = new OSDMap(); | 69 | private OSDMap m_features = new OSDMap(); |
70 | 70 | ||
71 | private string m_MapImageServerURL = string.Empty; | ||
72 | private string m_SearchURL = string.Empty; | 71 | private string m_SearchURL = string.Empty; |
73 | private bool m_ExportSupported = false; | 72 | private bool m_ExportSupported = false; |
74 | 73 | ||
@@ -78,15 +77,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
78 | { | 77 | { |
79 | IConfig config = source.Configs["SimulatorFeatures"]; | 78 | IConfig config = source.Configs["SimulatorFeatures"]; |
80 | if (config != null) | 79 | if (config != null) |
81 | { | 80 | { |
82 | m_MapImageServerURL = config.GetString("MapImageServerURI", string.Empty); | ||
83 | if (m_MapImageServerURL != string.Empty) | ||
84 | { | ||
85 | m_MapImageServerURL = m_MapImageServerURL.Trim(); | ||
86 | if (!m_MapImageServerURL.EndsWith("/")) | ||
87 | m_MapImageServerURL = m_MapImageServerURL + "/"; | ||
88 | } | ||
89 | |||
90 | m_SearchURL = config.GetString("SearchServerURI", string.Empty); | 81 | m_SearchURL = config.GetString("SearchServerURI", string.Empty); |
91 | 82 | ||
92 | m_ExportSupported = config.GetBoolean("ExportSupported", m_ExportSupported); | 83 | m_ExportSupported = config.GetBoolean("ExportSupported", m_ExportSupported); |
@@ -149,15 +140,16 @@ namespace OpenSim.Region.ClientStack.Linden | |||
149 | m_features["PhysicsShapeTypes"] = typesMap; | 140 | m_features["PhysicsShapeTypes"] = typesMap; |
150 | 141 | ||
151 | // Extra information for viewers that want to use it | 142 | // Extra information for viewers that want to use it |
152 | OSDMap gridServicesMap = new OSDMap(); | 143 | // TODO: Take these out of here into their respective modules, like map-server-url |
153 | if (m_MapImageServerURL != string.Empty) | 144 | OSDMap extrasMap = new OSDMap(); |
154 | gridServicesMap["map-server-url"] = m_MapImageServerURL; | ||
155 | if (m_SearchURL != string.Empty) | 145 | if (m_SearchURL != string.Empty) |
156 | gridServicesMap["search"] = m_SearchURL; | 146 | extrasMap["search-server-url"] = m_SearchURL; |
157 | m_features["GridServices"] = gridServicesMap; | ||
158 | |||
159 | if (m_ExportSupported) | 147 | if (m_ExportSupported) |
160 | m_features["ExportSupported"] = true; | 148 | extrasMap["ExportSupported"] = true; |
149 | |||
150 | if (extrasMap.Count > 0) | ||
151 | m_features["OpenSimExtras"] = extrasMap; | ||
152 | |||
161 | } | 153 | } |
162 | } | 154 | } |
163 | 155 | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs index eca576d..50e9275 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs | |||
@@ -64,11 +64,18 @@ namespace OpenSim.Region.ClientStack.Linden | |||
64 | 64 | ||
65 | private Scene m_scene; | 65 | private Scene m_scene; |
66 | private bool m_persistBakedTextures; | 66 | private bool m_persistBakedTextures; |
67 | private string m_URL; | ||
67 | 68 | ||
68 | private IBakedTextureModule m_BakedTextureModule; | 69 | private IBakedTextureModule m_BakedTextureModule; |
69 | 70 | ||
70 | public void Initialise(IConfigSource source) | 71 | public void Initialise(IConfigSource source) |
71 | { | 72 | { |
73 | IConfig config = source.Configs["ClientStack.LindenCaps"]; | ||
74 | if (config == null) | ||
75 | return; | ||
76 | |||
77 | m_URL = config.GetString("Cap_UploadBakedTexture", string.Empty); | ||
78 | |||
72 | IConfig appearanceConfig = source.Configs["Appearance"]; | 79 | IConfig appearanceConfig = source.Configs["Appearance"]; |
73 | if (appearanceConfig != null) | 80 | if (appearanceConfig != null) |
74 | m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures); | 81 | m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures); |
@@ -89,9 +96,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
89 | s.EventManager.OnRemovePresence -= DeRegisterPresence; | 96 | s.EventManager.OnRemovePresence -= DeRegisterPresence; |
90 | m_BakedTextureModule = null; | 97 | m_BakedTextureModule = null; |
91 | m_scene = null; | 98 | m_scene = null; |
92 | } | 99 | } |
93 | |||
94 | |||
95 | 100 | ||
96 | public void RegionLoaded(Scene s) | 101 | public void RegionLoaded(Scene s) |
97 | { | 102 | { |
@@ -103,44 +108,58 @@ namespace OpenSim.Region.ClientStack.Linden | |||
103 | 108 | ||
104 | private void DeRegisterPresence(UUID agentId) | 109 | private void DeRegisterPresence(UUID agentId) |
105 | { | 110 | { |
106 | ScenePresence presence = null; | 111 | // ScenePresence presence = null; |
107 | if (m_scene.TryGetScenePresence(agentId, out presence)) | 112 | // if (m_scene.TryGetScenePresence(agentId, out presence)) |
108 | { | 113 | { |
109 | presence.ControllingClient.OnSetAppearance -= CaptureAppearanceSettings; | 114 | // presence.ControllingClient.OnSetAppearance -= CaptureAppearanceSettings; |
110 | } | 115 | } |
111 | 116 | ||
112 | } | 117 | } |
113 | 118 | ||
114 | private void RegisterNewPresence(ScenePresence presence) | 119 | private void RegisterNewPresence(ScenePresence presence) |
115 | { | 120 | { |
116 | presence.ControllingClient.OnSetAppearance += CaptureAppearanceSettings; | 121 | // presence.ControllingClient.OnSetAppearance += CaptureAppearanceSettings; |
117 | |||
118 | } | 122 | } |
119 | 123 | ||
120 | private void CaptureAppearanceSettings(IClientAPI remoteClient, Primitive.TextureEntry textureEntry, byte[] visualParams, Vector3 avSize, WearableCacheItem[] cacheItems) | 124 | /* not in use. work done in AvatarFactoryModule ValidateBakedTextureCache() and UpdateBakedTextureCache() |
121 | { | 125 | private void CaptureAppearanceSettings(IClientAPI remoteClient, Primitive.TextureEntry textureEntry, byte[] visualParams, Vector3 avSize, WearableCacheItem[] cacheItems) |
122 | int maxCacheitemsLoop = cacheItems.Length; | ||
123 | if (maxCacheitemsLoop > AvatarWearable.MAX_WEARABLES) | ||
124 | { | ||
125 | maxCacheitemsLoop = AvatarWearable.MAX_WEARABLES; | ||
126 | m_log.WarnFormat("[CACHEDBAKES]: Too Many Cache items Provided {0}, the max is {1}. Truncating!", cacheItems.Length, AvatarWearable.MAX_WEARABLES); | ||
127 | } | ||
128 | |||
129 | m_BakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>(); | ||
130 | if (cacheItems.Length > 0) | ||
131 | { | ||
132 | m_log.Debug("[Cacheitems]: " + cacheItems.Length); | ||
133 | for (int iter = 0; iter < maxCacheitemsLoop; iter++) | ||
134 | { | ||
135 | m_log.Debug("[Cacheitems] {" + iter + "/" + cacheItems[iter].TextureIndex + "}: c-" + cacheItems[iter].CacheId + ", t-" + | ||
136 | cacheItems[iter].TextureID); | ||
137 | } | ||
138 | |||
139 | ScenePresence p = null; | ||
140 | if (m_scene.TryGetScenePresence(remoteClient.AgentId, out p)) | ||
141 | { | 126 | { |
127 | // if cacheItems.Length > 0 viewer is giving us current textures information. | ||
128 | // baked ones should had been uploaded and in assets cache as local itens | ||
129 | |||
130 | |||
131 | if (cacheItems.Length == 0) | ||
132 | return; // no textures information, nothing to do | ||
133 | |||
134 | ScenePresence p = null; | ||
135 | if (!m_scene.TryGetScenePresence(remoteClient.AgentId, out p)) | ||
136 | return; // what are we doing if there is no presence to cache for? | ||
137 | |||
138 | if (p.IsDeleted) | ||
139 | return; // does this really work? | ||
140 | |||
141 | int maxCacheitemsLoop = cacheItems.Length; | ||
142 | if (maxCacheitemsLoop > 20) | ||
143 | { | ||
144 | maxCacheitemsLoop = AvatarWearable.MAX_WEARABLES; | ||
145 | m_log.WarnFormat("[CACHEDBAKES]: Too Many Cache items Provided {0}, the max is {1}. Truncating!", cacheItems.Length, AvatarWearable.MAX_WEARABLES); | ||
146 | } | ||
147 | |||
148 | m_BakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>(); | ||
149 | |||
150 | |||
151 | // some nice debug | ||
152 | m_log.Debug("[Cacheitems]: " + cacheItems.Length); | ||
153 | for (int iter = 0; iter < maxCacheitemsLoop; iter++) | ||
154 | { | ||
155 | m_log.Debug("[Cacheitems] {" + iter + "/" + cacheItems[iter].TextureIndex + "}: c-" + cacheItems[iter].CacheId + ", t-" + | ||
156 | cacheItems[iter].TextureID); | ||
157 | } | ||
158 | |||
159 | // p.Appearance.WearableCacheItems is in memory primary cashID to textures mapper | ||
142 | 160 | ||
143 | WearableCacheItem[] existingitems = p.Appearance.WearableCacheItems; | 161 | WearableCacheItem[] existingitems = p.Appearance.WearableCacheItems; |
162 | |||
144 | if (existingitems == null) | 163 | if (existingitems == null) |
145 | { | 164 | { |
146 | if (m_BakedTextureModule != null) | 165 | if (m_BakedTextureModule != null) |
@@ -154,38 +173,22 @@ namespace OpenSim.Region.ClientStack.Linden | |||
154 | p.Appearance.WearableCacheItems = savedcache; | 173 | p.Appearance.WearableCacheItems = savedcache; |
155 | p.Appearance.WearableCacheItemsDirty = false; | 174 | p.Appearance.WearableCacheItemsDirty = false; |
156 | } | 175 | } |
157 | |||
158 | } | ||
159 | /* | ||
160 | * The following Catch types DO NOT WORK with m_BakedTextureModule.Get | ||
161 | * it jumps to the General Packet Exception Handler if you don't catch Exception! | ||
162 | * | ||
163 | catch (System.Net.Sockets.SocketException) | ||
164 | { | ||
165 | cacheItems = null; | ||
166 | } | ||
167 | catch (WebException) | ||
168 | { | ||
169 | cacheItems = null; | ||
170 | } | 176 | } |
171 | catch (InvalidOperationException) | 177 | |
172 | { | ||
173 | cacheItems = null; | ||
174 | } */ | ||
175 | catch (Exception) | 178 | catch (Exception) |
176 | { | 179 | { |
177 | // The service logs a sufficient error message. | 180 | // The service logs a sufficient error message. |
178 | } | 181 | } |
179 | 182 | ||
180 | 183 | ||
181 | if (savedcache != null) | 184 | if (savedcache != null) |
182 | existingitems = savedcache; | 185 | existingitems = savedcache; |
183 | } | 186 | } |
184 | } | 187 | } |
188 | |||
185 | // Existing items null means it's a fully new appearance | 189 | // Existing items null means it's a fully new appearance |
186 | if (existingitems == null) | 190 | if (existingitems == null) |
187 | { | 191 | { |
188 | |||
189 | for (int i = 0; i < maxCacheitemsLoop; i++) | 192 | for (int i = 0; i < maxCacheitemsLoop; i++) |
190 | { | 193 | { |
191 | if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex) | 194 | if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex) |
@@ -198,7 +201,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
198 | AppearanceManager.DEFAULT_AVATAR_TEXTURE; | 201 | AppearanceManager.DEFAULT_AVATAR_TEXTURE; |
199 | continue; | 202 | continue; |
200 | } | 203 | } |
201 | cacheItems[i].TextureID =face.TextureID; | 204 | cacheItems[i].TextureID = face.TextureID; |
202 | if (m_scene.AssetService != null) | 205 | if (m_scene.AssetService != null) |
203 | cacheItems[i].TextureAsset = | 206 | cacheItems[i].TextureAsset = |
204 | m_scene.AssetService.GetCached(cacheItems[i].TextureID.ToString()); | 207 | m_scene.AssetService.GetCached(cacheItems[i].TextureID.ToString()); |
@@ -207,15 +210,10 @@ namespace OpenSim.Region.ClientStack.Linden | |||
207 | { | 210 | { |
208 | m_log.WarnFormat("[CACHEDBAKES]: Invalid Texture Index Provided, Texture doesn't exist or hasn't been uploaded yet {0}, the max is {1}. Skipping!", cacheItems[i].TextureIndex, textureEntry.FaceTextures.Length); | 211 | m_log.WarnFormat("[CACHEDBAKES]: Invalid Texture Index Provided, Texture doesn't exist or hasn't been uploaded yet {0}, the max is {1}. Skipping!", cacheItems[i].TextureIndex, textureEntry.FaceTextures.Length); |
209 | } | 212 | } |
210 | |||
211 | |||
212 | } | 213 | } |
213 | } | 214 | } |
214 | else | 215 | else |
215 | 216 | { | |
216 | |||
217 | { | ||
218 | // for each uploaded baked texture | ||
219 | for (int i = 0; i < maxCacheitemsLoop; i++) | 217 | for (int i = 0; i < maxCacheitemsLoop; i++) |
220 | { | 218 | { |
221 | if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex) | 219 | if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex) |
@@ -246,23 +244,24 @@ namespace OpenSim.Region.ClientStack.Linden | |||
246 | } | 244 | } |
247 | } | 245 | } |
248 | } | 246 | } |
249 | |||
250 | |||
251 | |||
252 | p.Appearance.WearableCacheItems = cacheItems; | 247 | p.Appearance.WearableCacheItems = cacheItems; |
253 | |||
254 | |||
255 | 248 | ||
256 | if (m_BakedTextureModule != null) | 249 | if (m_BakedTextureModule != null) |
257 | { | 250 | { |
258 | m_BakedTextureModule.Store(remoteClient.AgentId, cacheItems); | 251 | m_BakedTextureModule.Store(remoteClient.AgentId, cacheItems); |
259 | p.Appearance.WearableCacheItemsDirty = true; | 252 | p.Appearance.WearableCacheItemsDirty = true; |
260 | 253 | ||
261 | } | 254 | } |
262 | } | 255 | else |
263 | } | 256 | p.Appearance.WearableCacheItemsDirty = false; |
264 | } | ||
265 | 257 | ||
258 | for (int iter = 0; iter < maxCacheitemsLoop; iter++) | ||
259 | { | ||
260 | m_log.Debug("[CacheitemsLeaving] {" + iter + "/" + cacheItems[iter].TextureIndex + "}: c-" + cacheItems[iter].CacheId + ", t-" + | ||
261 | cacheItems[iter].TextureID); | ||
262 | } | ||
263 | } | ||
264 | */ | ||
266 | public void PostInitialise() | 265 | public void PostInitialise() |
267 | { | 266 | { |
268 | } | 267 | } |
@@ -280,23 +279,28 @@ namespace OpenSim.Region.ClientStack.Linden | |||
280 | 279 | ||
281 | public void RegisterCaps(UUID agentID, Caps caps) | 280 | public void RegisterCaps(UUID agentID, Caps caps) |
282 | { | 281 | { |
283 | UploadBakedTextureHandler avatarhandler = new UploadBakedTextureHandler( | 282 | // UUID capID = UUID.Random(); |
284 | caps, m_scene.AssetService, m_persistBakedTextures); | ||
285 | |||
286 | |||
287 | |||
288 | caps.RegisterHandler( | ||
289 | "UploadBakedTexture", | ||
290 | new RestStreamHandler( | ||
291 | "POST", | ||
292 | "/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath, | ||
293 | avatarhandler.UploadBakedTexture, | ||
294 | "UploadBakedTexture", | ||
295 | agentID.ToString())); | ||
296 | 283 | ||
297 | 284 | //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture)); | |
298 | 285 | if (m_URL == "localhost") | |
286 | { | ||
287 | UploadBakedTextureHandler avatarhandler = new UploadBakedTextureHandler( | ||
288 | caps, m_scene.AssetService, m_persistBakedTextures); | ||
299 | 289 | ||
290 | caps.RegisterHandler( | ||
291 | "UploadBakedTexture", | ||
292 | new RestStreamHandler( | ||
293 | "POST", | ||
294 | "/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath, | ||
295 | avatarhandler.UploadBakedTexture, | ||
296 | "UploadBakedTexture", | ||
297 | agentID.ToString())); | ||
298 | |||
299 | } | ||
300 | else | ||
301 | { | ||
302 | caps.RegisterHandler("UploadBakedTexture", m_URL); | ||
303 | } | ||
300 | } | 304 | } |
301 | } | 305 | } |
302 | } \ No newline at end of file | 306 | } |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs index 707cc93..6fc35cd 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs | |||
@@ -71,9 +71,13 @@ namespace OpenSim.Region.ClientStack.Linden | |||
71 | private IInventoryService m_InventoryService; | 71 | private IInventoryService m_InventoryService; |
72 | private ILibraryService m_LibraryService; | 72 | private ILibraryService m_LibraryService; |
73 | 73 | ||
74 | private bool m_Enabled; | ||
75 | |||
76 | private string m_fetchInventoryDescendents2Url; | ||
77 | private string m_webFetchInventoryDescendentsUrl; | ||
78 | |||
74 | private static WebFetchInvDescHandler m_webFetchHandler; | 79 | private static WebFetchInvDescHandler m_webFetchHandler; |
75 | 80 | ||
76 | private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>(); | ||
77 | private static Thread[] m_workerThreads = null; | 81 | private static Thread[] m_workerThreads = null; |
78 | 82 | ||
79 | private static DoubleQueue<aPollRequest> m_queue = | 83 | private static DoubleQueue<aPollRequest> m_queue = |
@@ -83,22 +87,45 @@ namespace OpenSim.Region.ClientStack.Linden | |||
83 | 87 | ||
84 | public void Initialise(IConfigSource source) | 88 | public void Initialise(IConfigSource source) |
85 | { | 89 | { |
90 | IConfig config = source.Configs["ClientStack.LindenCaps"]; | ||
91 | if (config == null) | ||
92 | return; | ||
93 | |||
94 | m_fetchInventoryDescendents2Url = config.GetString("Cap_FetchInventoryDescendents2", string.Empty); | ||
95 | m_webFetchInventoryDescendentsUrl = config.GetString("Cap_WebFetchInventoryDescendents", string.Empty); | ||
96 | |||
97 | if (m_fetchInventoryDescendents2Url != string.Empty || m_webFetchInventoryDescendentsUrl != string.Empty) | ||
98 | { | ||
99 | m_Enabled = true; | ||
100 | } | ||
86 | } | 101 | } |
87 | 102 | ||
88 | public void AddRegion(Scene s) | 103 | public void AddRegion(Scene s) |
89 | { | 104 | { |
105 | if (!m_Enabled) | ||
106 | return; | ||
107 | |||
90 | m_scene = s; | 108 | m_scene = s; |
91 | } | 109 | } |
92 | 110 | ||
93 | public void RemoveRegion(Scene s) | 111 | public void RemoveRegion(Scene s) |
94 | { | 112 | { |
113 | if (!m_Enabled) | ||
114 | return; | ||
115 | |||
95 | m_scene.EventManager.OnRegisterCaps -= RegisterCaps; | 116 | m_scene.EventManager.OnRegisterCaps -= RegisterCaps; |
96 | m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps; | 117 | |
118 | foreach (Thread t in m_workerThreads) | ||
119 | Watchdog.AbortThread(t.ManagedThreadId); | ||
120 | |||
97 | m_scene = null; | 121 | m_scene = null; |
98 | } | 122 | } |
99 | 123 | ||
100 | public void RegionLoaded(Scene s) | 124 | public void RegionLoaded(Scene s) |
101 | { | 125 | { |
126 | if (!m_Enabled) | ||
127 | return; | ||
128 | |||
102 | m_InventoryService = m_scene.InventoryService; | 129 | m_InventoryService = m_scene.InventoryService; |
103 | m_LibraryService = m_scene.LibraryService; | 130 | m_LibraryService = m_scene.LibraryService; |
104 | 131 | ||
@@ -106,7 +133,6 @@ namespace OpenSim.Region.ClientStack.Linden | |||
106 | m_webFetchHandler = new WebFetchInvDescHandler(m_InventoryService, m_LibraryService); | 133 | m_webFetchHandler = new WebFetchInvDescHandler(m_InventoryService, m_LibraryService); |
107 | 134 | ||
108 | m_scene.EventManager.OnRegisterCaps += RegisterCaps; | 135 | m_scene.EventManager.OnRegisterCaps += RegisterCaps; |
109 | m_scene.EventManager.OnDeregisterCaps += DeregisterCaps; | ||
110 | 136 | ||
111 | if (m_workerThreads == null) | 137 | if (m_workerThreads == null) |
112 | { | 138 | { |
@@ -140,12 +166,6 @@ namespace OpenSim.Region.ClientStack.Linden | |||
140 | 166 | ||
141 | #endregion | 167 | #endregion |
142 | 168 | ||
143 | ~WebFetchInvDescModule() | ||
144 | { | ||
145 | foreach (Thread t in m_workerThreads) | ||
146 | Watchdog.AbortThread(t.ManagedThreadId); | ||
147 | } | ||
148 | |||
149 | private class PollServiceInventoryEventArgs : PollServiceEventArgs | 169 | private class PollServiceInventoryEventArgs : PollServiceEventArgs |
150 | { | 170 | { |
151 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 171 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
@@ -155,8 +175,8 @@ namespace OpenSim.Region.ClientStack.Linden | |||
155 | 175 | ||
156 | private Scene m_scene; | 176 | private Scene m_scene; |
157 | 177 | ||
158 | public PollServiceInventoryEventArgs(Scene scene, UUID pId) : | 178 | public PollServiceInventoryEventArgs(Scene scene, string url, UUID pId) : |
159 | base(null, null, null, null, pId, int.MaxValue) | 179 | base(null, url, null, null, null, pId, int.MaxValue) |
160 | { | 180 | { |
161 | m_scene = scene; | 181 | m_scene = scene; |
162 | 182 | ||
@@ -278,53 +298,72 @@ namespace OpenSim.Region.ClientStack.Linden | |||
278 | requestinfo.request["body"].ToString(), String.Empty, String.Empty, null, null); | 298 | requestinfo.request["body"].ToString(), String.Empty, String.Empty, null, null); |
279 | 299 | ||
280 | lock (responses) | 300 | lock (responses) |
281 | responses[requestID] = response; | 301 | responses[requestID] = response; |
282 | } | 302 | } |
283 | } | 303 | } |
284 | 304 | ||
285 | private void RegisterCaps(UUID agentID, Caps caps) | 305 | private void RegisterCaps(UUID agentID, Caps caps) |
286 | { | 306 | { |
287 | string capUrl = "/CAPS/" + UUID.Random() + "/"; | 307 | RegisterFetchDescendentsCap(agentID, caps, "FetchInventoryDescendents2", m_fetchInventoryDescendents2Url); |
288 | |||
289 | // Register this as a poll service | ||
290 | PollServiceInventoryEventArgs args = new PollServiceInventoryEventArgs(m_scene, agentID); | ||
291 | |||
292 | args.Type = PollServiceEventArgs.EventType.Inventory; | ||
293 | MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args); | ||
294 | |||
295 | string hostName = m_scene.RegionInfo.ExternalHostName; | ||
296 | uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port; | ||
297 | string protocol = "http"; | ||
298 | |||
299 | if (MainServer.Instance.UseSSL) | ||
300 | { | ||
301 | hostName = MainServer.Instance.SSLCommonName; | ||
302 | port = MainServer.Instance.SSLPort; | ||
303 | protocol = "https"; | ||
304 | } | ||
305 | caps.RegisterHandler("FetchInventoryDescendents2", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl)); | ||
306 | |||
307 | m_capsDict[agentID] = capUrl; | ||
308 | } | 308 | } |
309 | 309 | ||
310 | private void DeregisterCaps(UUID agentID, Caps caps) | 310 | private void RegisterFetchDescendentsCap(UUID agentID, Caps caps, string capName, string url) |
311 | { | 311 | { |
312 | string capUrl; | 312 | string capUrl; |
313 | 313 | ||
314 | if (m_capsDict.TryGetValue(agentID, out capUrl)) | 314 | // disable the cap clause |
315 | if (url == "") | ||
316 | { | ||
317 | return; | ||
318 | } | ||
319 | // handled by the simulator | ||
320 | else if (url == "localhost") | ||
321 | { | ||
322 | capUrl = "/CAPS/" + UUID.Random() + "/"; | ||
323 | |||
324 | // Register this as a poll service | ||
325 | PollServiceInventoryEventArgs args = new PollServiceInventoryEventArgs(m_scene, capUrl, agentID); | ||
326 | args.Type = PollServiceEventArgs.EventType.Inventory; | ||
327 | |||
328 | caps.RegisterPollHandler(capName, args); | ||
329 | } | ||
330 | // external handler | ||
331 | else | ||
315 | { | 332 | { |
316 | MainServer.Instance.RemoveHTTPHandler("", capUrl); | 333 | capUrl = url; |
317 | m_capsDict.Remove(agentID); | 334 | IExternalCapsModule handler = m_scene.RequestModuleInterface<IExternalCapsModule>(); |
335 | if (handler != null) | ||
336 | handler.RegisterExternalUserCapsHandler(agentID,caps,capName,capUrl); | ||
337 | else | ||
338 | caps.RegisterHandler(capName, capUrl); | ||
318 | } | 339 | } |
340 | |||
341 | // m_log.DebugFormat( | ||
342 | // "[FETCH INVENTORY DESCENDENTS2 MODULE]: Registered capability {0} at {1} in region {2} for {3}", | ||
343 | // capName, capUrl, m_scene.RegionInfo.RegionName, agentID); | ||
319 | } | 344 | } |
320 | 345 | ||
346 | // private void DeregisterCaps(UUID agentID, Caps caps) | ||
347 | // { | ||
348 | // string capUrl; | ||
349 | // | ||
350 | // if (m_capsDict.TryGetValue(agentID, out capUrl)) | ||
351 | // { | ||
352 | // MainServer.Instance.RemoveHTTPHandler("", capUrl); | ||
353 | // m_capsDict.Remove(agentID); | ||
354 | // } | ||
355 | // } | ||
356 | |||
321 | private void DoInventoryRequests() | 357 | private void DoInventoryRequests() |
322 | { | 358 | { |
323 | while (true) | 359 | while (true) |
324 | { | 360 | { |
361 | Watchdog.UpdateThread(); | ||
362 | |||
325 | aPollRequest poolreq = m_queue.Dequeue(); | 363 | aPollRequest poolreq = m_queue.Dequeue(); |
326 | 364 | ||
327 | poolreq.thepoll.Process(poolreq); | 365 | if (poolreq != null && poolreq.thepoll != null) |
366 | poolreq.thepoll.Process(poolreq); | ||
328 | } | 367 | } |
329 | } | 368 | } |
330 | } | 369 | } |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs index 3995620..15d6f7f 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs | |||
@@ -424,12 +424,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
424 | // foreign user is visiting, we need to try again after the first fail to the local | 424 | // foreign user is visiting, we need to try again after the first fail to the local |
425 | // asset service. | 425 | // asset service. |
426 | string assetServerURL = string.Empty; | 426 | string assetServerURL = string.Empty; |
427 | if (InventoryAccessModule.IsForeignUser(AgentID, out assetServerURL)) | 427 | if (InventoryAccessModule.IsForeignUser(AgentID, out assetServerURL) && !string.IsNullOrEmpty(assetServerURL)) |
428 | { | 428 | { |
429 | if (!assetServerURL.EndsWith("/") && !assetServerURL.EndsWith("=")) | 429 | if (!assetServerURL.EndsWith("/") && !assetServerURL.EndsWith("=")) |
430 | assetServerURL = assetServerURL + "/"; | 430 | assetServerURL = assetServerURL + "/"; |
431 | 431 | ||
432 | m_log.DebugFormat("[J2KIMAGE]: texture {0} not found in local asset storage. Trying user's storage.", assetServerURL + id); | 432 | // m_log.DebugFormat("[J2KIMAGE]: texture {0} not found in local asset storage. Trying user's storage.", assetServerURL + id); |
433 | AssetService.Get(assetServerURL + id, InventoryAccessModule, AssetReceived); | 433 | AssetService.Get(assetServerURL + id, InventoryAccessModule, AssetReceived); |
434 | return; | 434 | return; |
435 | } | 435 | } |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 5ee1596..06f1301 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | |||
@@ -84,6 +84,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
84 | public event ModifyTerrain OnModifyTerrain; | 84 | public event ModifyTerrain OnModifyTerrain; |
85 | public event Action<IClientAPI> OnRegionHandShakeReply; | 85 | public event Action<IClientAPI> OnRegionHandShakeReply; |
86 | public event GenericCall1 OnRequestWearables; | 86 | public event GenericCall1 OnRequestWearables; |
87 | public event CachedTextureRequest OnCachedTextureRequest; | ||
87 | public event SetAppearance OnSetAppearance; | 88 | public event SetAppearance OnSetAppearance; |
88 | public event AvatarNowWearing OnAvatarNowWearing; | 89 | public event AvatarNowWearing OnAvatarNowWearing; |
89 | public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv; | 90 | public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv; |
@@ -95,6 +96,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
95 | public event Action<IClientAPI, bool> OnCompleteMovementToRegion; | 96 | public event Action<IClientAPI, bool> OnCompleteMovementToRegion; |
96 | public event UpdateAgent OnPreAgentUpdate; | 97 | public event UpdateAgent OnPreAgentUpdate; |
97 | public event UpdateAgent OnAgentUpdate; | 98 | public event UpdateAgent OnAgentUpdate; |
99 | public event UpdateAgent OnAgentCameraUpdate; | ||
98 | public event AgentRequestSit OnAgentRequestSit; | 100 | public event AgentRequestSit OnAgentRequestSit; |
99 | public event AgentSit OnAgentSit; | 101 | public event AgentSit OnAgentSit; |
100 | public event AvatarPickerRequest OnAvatarPickerRequest; | 102 | public event AvatarPickerRequest OnAvatarPickerRequest; |
@@ -335,6 +337,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
335 | private bool m_VelocityInterpolate = false; | 337 | private bool m_VelocityInterpolate = false; |
336 | private const uint MaxTransferBytesPerPacket = 600; | 338 | private const uint MaxTransferBytesPerPacket = 600; |
337 | 339 | ||
340 | private volatile bool m_justEditedTerrain = false; | ||
338 | 341 | ||
339 | /// <value> | 342 | /// <value> |
340 | /// List used in construction of data blocks for an object update packet. This is to stop us having to | 343 | /// List used in construction of data blocks for an object update packet. This is to stop us having to |
@@ -355,7 +358,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
355 | // protected HashSet<uint> m_attachmentsSent; | 358 | // protected HashSet<uint> m_attachmentsSent; |
356 | 359 | ||
357 | private bool m_deliverPackets = true; | 360 | private bool m_deliverPackets = true; |
358 | private int m_animationSequenceNumber = 1; | 361 | |
359 | private bool m_SendLogoutPacketWhenClosing = true; | 362 | private bool m_SendLogoutPacketWhenClosing = true; |
360 | 363 | ||
361 | /// <summary> | 364 | /// <summary> |
@@ -367,7 +370,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
367 | /// This does mean that agent updates must be processed synchronously, at least for each client, and called methods | 370 | /// This does mean that agent updates must be processed synchronously, at least for each client, and called methods |
368 | /// cannot retain a reference to it outside of that method. | 371 | /// cannot retain a reference to it outside of that method. |
369 | /// </remarks> | 372 | /// </remarks> |
370 | private AgentUpdateArgs m_lastAgentUpdateArgs; | 373 | private AgentUpdateArgs m_thisAgentUpdateArgs = new AgentUpdateArgs(); |
371 | 374 | ||
372 | protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>(); | 375 | protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>(); |
373 | protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers | 376 | protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers |
@@ -416,6 +419,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
416 | public ulong ActiveGroupPowers { get { return m_activeGroupPowers; } } | 419 | public ulong ActiveGroupPowers { get { return m_activeGroupPowers; } } |
417 | public bool IsGroupMember(UUID groupID) { return m_groupPowers.ContainsKey(groupID); } | 420 | public bool IsGroupMember(UUID groupID) { return m_groupPowers.ContainsKey(groupID); } |
418 | 421 | ||
422 | public int PingTimeMS | ||
423 | { | ||
424 | get | ||
425 | { | ||
426 | if (UDPClient != null) | ||
427 | return UDPClient.PingTimeMS; | ||
428 | return 0; | ||
429 | } | ||
430 | } | ||
431 | |||
419 | /// <summary> | 432 | /// <summary> |
420 | /// Entity update queues | 433 | /// Entity update queues |
421 | /// </summary> | 434 | /// </summary> |
@@ -437,7 +450,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
437 | public string Name { get { return FirstName + " " + LastName; } } | 450 | public string Name { get { return FirstName + " " + LastName; } } |
438 | 451 | ||
439 | public uint CircuitCode { get { return m_circuitCode; } } | 452 | public uint CircuitCode { get { return m_circuitCode; } } |
440 | public int NextAnimationSequenceNumber { get { return m_animationSequenceNumber++; } } | 453 | public int NextAnimationSequenceNumber |
454 | { | ||
455 | get { return m_udpServer.NextAnimationSequenceNumber; } | ||
456 | } | ||
441 | 457 | ||
442 | /// <summary> | 458 | /// <summary> |
443 | /// As well as it's function in IClientAPI, in LLClientView we are locking on this property in order to | 459 | /// As well as it's function in IClientAPI, in LLClientView we are locking on this property in order to |
@@ -458,6 +474,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
458 | set { m_disableFacelights = value; } | 474 | set { m_disableFacelights = value; } |
459 | } | 475 | } |
460 | 476 | ||
477 | |||
461 | public bool SendLogoutPacketWhenClosing { set { m_SendLogoutPacketWhenClosing = value; } } | 478 | public bool SendLogoutPacketWhenClosing { set { m_SendLogoutPacketWhenClosing = value; } } |
462 | 479 | ||
463 | 480 | ||
@@ -504,6 +521,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
504 | m_udpServer = udpServer; | 521 | m_udpServer = udpServer; |
505 | m_udpClient = udpClient; | 522 | m_udpClient = udpClient; |
506 | m_udpClient.OnQueueEmpty += HandleQueueEmpty; | 523 | m_udpClient.OnQueueEmpty += HandleQueueEmpty; |
524 | m_udpClient.HasUpdates += HandleHasUpdates; | ||
507 | m_udpClient.OnPacketStats += PopulateStats; | 525 | m_udpClient.OnPacketStats += PopulateStats; |
508 | 526 | ||
509 | m_prioritizer = new Prioritizer(m_scene); | 527 | m_prioritizer = new Prioritizer(m_scene); |
@@ -533,7 +551,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
533 | // We still perform a force close inside the sync lock since this is intended to attempt close where | 551 | // We still perform a force close inside the sync lock since this is intended to attempt close where |
534 | // there is some unidentified connection problem, not where we have issues due to deadlock | 552 | // there is some unidentified connection problem, not where we have issues due to deadlock |
535 | if (!IsActive && !force) | 553 | if (!IsActive && !force) |
554 | { | ||
555 | m_log.DebugFormat( | ||
556 | "[CLIENT]: Not attempting to close inactive client {0} in {1} since force flag is not set", | ||
557 | Name, m_scene.Name); | ||
558 | |||
536 | return; | 559 | return; |
560 | } | ||
537 | 561 | ||
538 | IsActive = false; | 562 | IsActive = false; |
539 | CloseWithoutChecks(sendStop); | 563 | CloseWithoutChecks(sendStop); |
@@ -709,12 +733,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
709 | //there is a local handler for this packet type | 733 | //there is a local handler for this packet type |
710 | if (pprocessor.Async) | 734 | if (pprocessor.Async) |
711 | { | 735 | { |
736 | ClientInfo cinfo = UDPClient.GetClientInfo(); | ||
737 | if (!cinfo.AsyncRequests.ContainsKey(packet.Type.ToString())) | ||
738 | cinfo.AsyncRequests[packet.Type.ToString()] = 0; | ||
739 | cinfo.AsyncRequests[packet.Type.ToString()]++; | ||
740 | |||
712 | object obj = new AsyncPacketProcess(this, pprocessor.method, packet); | 741 | object obj = new AsyncPacketProcess(this, pprocessor.method, packet); |
713 | Util.FireAndForget(ProcessSpecificPacketAsync, obj); | 742 | Util.FireAndForget(ProcessSpecificPacketAsync, obj); |
714 | result = true; | 743 | result = true; |
715 | } | 744 | } |
716 | else | 745 | else |
717 | { | 746 | { |
747 | ClientInfo cinfo = UDPClient.GetClientInfo(); | ||
748 | if (!cinfo.SyncRequests.ContainsKey(packet.Type.ToString())) | ||
749 | cinfo.SyncRequests[packet.Type.ToString()] = 0; | ||
750 | cinfo.SyncRequests[packet.Type.ToString()]++; | ||
751 | |||
718 | result = pprocessor.method(this, packet); | 752 | result = pprocessor.method(this, packet); |
719 | } | 753 | } |
720 | } | 754 | } |
@@ -729,6 +763,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
729 | } | 763 | } |
730 | if (found) | 764 | if (found) |
731 | { | 765 | { |
766 | ClientInfo cinfo = UDPClient.GetClientInfo(); | ||
767 | if (!cinfo.GenericRequests.ContainsKey(packet.Type.ToString())) | ||
768 | cinfo.GenericRequests[packet.Type.ToString()] = 0; | ||
769 | cinfo.GenericRequests[packet.Type.ToString()]++; | ||
770 | |||
732 | result = method(this, packet); | 771 | result = method(this, packet); |
733 | } | 772 | } |
734 | } | 773 | } |
@@ -758,7 +797,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
758 | 797 | ||
759 | public virtual void Start() | 798 | public virtual void Start() |
760 | { | 799 | { |
761 | m_scene.AddNewClient(this, PresenceType.User); | 800 | m_scene.AddNewAgent(this, PresenceType.User); |
762 | 801 | ||
763 | RefreshGroupMembership(); | 802 | RefreshGroupMembership(); |
764 | } | 803 | } |
@@ -820,14 +859,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
820 | handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType); | 859 | handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType); |
821 | handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes; | 860 | handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes; |
822 | 861 | ||
823 | handshake.RegionInfo4 = new RegionHandshakePacket.RegionInfo4Block[0]; | 862 | handshake.RegionInfo4 = new RegionHandshakePacket.RegionInfo4Block[1]; |
824 | // OutPacket(handshake, ThrottleOutPacketType.Task); | 863 | handshake.RegionInfo4[0] = new RegionHandshakePacket.RegionInfo4Block(); |
825 | // use same as MoveAgentIntoRegion (both should be task ) | 864 | handshake.RegionInfo4[0].RegionFlagsExtended = args.regionFlags; |
865 | handshake.RegionInfo4[0].RegionProtocols = 0; // 1 here would indicate that SSB is supported | ||
866 | |||
826 | OutPacket(handshake, ThrottleOutPacketType.Unknown); | 867 | OutPacket(handshake, ThrottleOutPacketType.Unknown); |
827 | } | 868 | } |
828 | 869 | ||
870 | |||
829 | public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look) | 871 | public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look) |
830 | { | 872 | { |
873 | m_thisAgentUpdateArgs.CameraAtAxis.X = float.MinValue; | ||
874 | m_thisAgentUpdateArgs.ControlFlags = uint.MaxValue; | ||
875 | |||
831 | AgentMovementCompletePacket mov = (AgentMovementCompletePacket)PacketPool.Instance.GetPacket(PacketType.AgentMovementComplete); | 876 | AgentMovementCompletePacket mov = (AgentMovementCompletePacket)PacketPool.Instance.GetPacket(PacketType.AgentMovementComplete); |
832 | mov.SimData.ChannelVersion = m_channelVersion; | 877 | mov.SimData.ChannelVersion = m_channelVersion; |
833 | mov.AgentData.SessionID = m_sessionId; | 878 | mov.AgentData.SessionID = m_sessionId; |
@@ -1210,9 +1255,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1210 | LLHeightFieldMoronize(map); | 1255 | LLHeightFieldMoronize(map); |
1211 | 1256 | ||
1212 | LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); | 1257 | LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); |
1213 | layerpack.Header.Reliable = true; | 1258 | |
1259 | // When a user edits the terrain, so much data is sent, the data queues up fast and presents a sub optimal editing experience. | ||
1260 | // To alleviate this issue, when the user edits the terrain, we start skipping the queues until they're done editing the terrain. | ||
1261 | // We also make them unreliable because it's extremely likely that multiple packets will be sent for a terrain patch area | ||
1262 | // invalidating previous packets for that area. | ||
1214 | 1263 | ||
1215 | OutPacket(layerpack, ThrottleOutPacketType.Task); | 1264 | // It's possible for an editing user to flood themselves with edited packets but the majority of use cases are such that only a |
1265 | // tiny percentage of users will be editing the terrain. Other, non-editing users will see the edits much slower. | ||
1266 | |||
1267 | // One last note on this topic, by the time users are going to be editing the terrain, it's extremely likely that the sim will | ||
1268 | // have rezzed already and therefore this is not likely going to cause any additional issues with lost packets, objects or terrain | ||
1269 | // patches. | ||
1270 | |||
1271 | // m_justEditedTerrain is volatile, so test once and duplicate two affected statements so we only have one cache miss. | ||
1272 | if (m_justEditedTerrain) | ||
1273 | { | ||
1274 | layerpack.Header.Reliable = false; | ||
1275 | OutPacket(layerpack, | ||
1276 | ThrottleOutPacketType.Unknown ); | ||
1277 | } | ||
1278 | else | ||
1279 | { | ||
1280 | layerpack.Header.Reliable = true; | ||
1281 | OutPacket(layerpack, | ||
1282 | ThrottleOutPacketType.Task); | ||
1283 | } | ||
1216 | } | 1284 | } |
1217 | catch (Exception e) | 1285 | catch (Exception e) |
1218 | { | 1286 | { |
@@ -1405,6 +1473,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1405 | 1473 | ||
1406 | mapReply.AgentData.AgentID = AgentId; | 1474 | mapReply.AgentData.AgentID = AgentId; |
1407 | mapReply.Data = new MapBlockReplyPacket.DataBlock[mapBlocks2.Length]; | 1475 | mapReply.Data = new MapBlockReplyPacket.DataBlock[mapBlocks2.Length]; |
1476 | mapReply.Size = new MapBlockReplyPacket.SizeBlock[mapBlocks2.Length]; | ||
1408 | mapReply.AgentData.Flags = flag; | 1477 | mapReply.AgentData.Flags = flag; |
1409 | 1478 | ||
1410 | for (int i = 0; i < mapBlocks2.Length; i++) | 1479 | for (int i = 0; i < mapBlocks2.Length; i++) |
@@ -1419,6 +1488,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1419 | mapReply.Data[i].RegionFlags = mapBlocks2[i].RegionFlags; | 1488 | mapReply.Data[i].RegionFlags = mapBlocks2[i].RegionFlags; |
1420 | mapReply.Data[i].Access = mapBlocks2[i].Access; | 1489 | mapReply.Data[i].Access = mapBlocks2[i].Access; |
1421 | mapReply.Data[i].Agents = mapBlocks2[i].Agents; | 1490 | mapReply.Data[i].Agents = mapBlocks2[i].Agents; |
1491 | |||
1492 | // TODO: hookup varregion sim size here | ||
1493 | mapReply.Size[i] = new MapBlockReplyPacket.SizeBlock(); | ||
1494 | mapReply.Size[i].SizeX = 256; | ||
1495 | mapReply.Size[i].SizeY = 256; | ||
1422 | } | 1496 | } |
1423 | OutPacket(mapReply, ThrottleOutPacketType.Land); | 1497 | OutPacket(mapReply, ThrottleOutPacketType.Land); |
1424 | } | 1498 | } |
@@ -1578,9 +1652,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1578 | pc.PingID.OldestUnacked = 0; | 1652 | pc.PingID.OldestUnacked = 0; |
1579 | 1653 | ||
1580 | OutPacket(pc, ThrottleOutPacketType.Unknown); | 1654 | OutPacket(pc, ThrottleOutPacketType.Unknown); |
1655 | UDPClient.m_lastStartpingTimeMS = Util.EnvironmentTickCount(); | ||
1581 | } | 1656 | } |
1582 | 1657 | ||
1583 | public void SendKillObject(ulong regionHandle, List<uint> localIDs) | 1658 | public void SendKillObject(List<uint> localIDs) |
1584 | { | 1659 | { |
1585 | // foreach (uint id in localIDs) | 1660 | // foreach (uint id in localIDs) |
1586 | // m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle); | 1661 | // m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle); |
@@ -2594,11 +2669,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2594 | { | 2669 | { |
2595 | AvatarSitResponsePacket avatarSitResponse = new AvatarSitResponsePacket(); | 2670 | AvatarSitResponsePacket avatarSitResponse = new AvatarSitResponsePacket(); |
2596 | avatarSitResponse.SitObject.ID = TargetID; | 2671 | avatarSitResponse.SitObject.ID = TargetID; |
2597 | if (CameraAtOffset != Vector3.Zero) | 2672 | avatarSitResponse.SitTransform.CameraAtOffset = CameraAtOffset; |
2598 | { | 2673 | avatarSitResponse.SitTransform.CameraEyeOffset = CameraEyeOffset; |
2599 | avatarSitResponse.SitTransform.CameraAtOffset = CameraAtOffset; | ||
2600 | avatarSitResponse.SitTransform.CameraEyeOffset = CameraEyeOffset; | ||
2601 | } | ||
2602 | avatarSitResponse.SitTransform.ForceMouselook = ForceMouseLook; | 2674 | avatarSitResponse.SitTransform.ForceMouselook = ForceMouseLook; |
2603 | avatarSitResponse.SitTransform.AutoPilot = autopilot; | 2675 | avatarSitResponse.SitTransform.AutoPilot = autopilot; |
2604 | avatarSitResponse.SitTransform.SitPosition = OffsetPos; | 2676 | avatarSitResponse.SitTransform.SitPosition = OffsetPos; |
@@ -3630,6 +3702,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3630 | avp.Sender.IsTrial = false; | 3702 | avp.Sender.IsTrial = false; |
3631 | avp.Sender.ID = agentID; | 3703 | avp.Sender.ID = agentID; |
3632 | avp.AppearanceData = new AvatarAppearancePacket.AppearanceDataBlock[0]; | 3704 | avp.AppearanceData = new AvatarAppearancePacket.AppearanceDataBlock[0]; |
3705 | |||
3706 | // this need be use in future | ||
3707 | // avp.AppearanceData[0].AppearanceVersion = 0; | ||
3708 | // avp.AppearanceData[0].CofVersion = 0; | ||
3709 | |||
3633 | //m_log.DebugFormat("[CLIENT]: Sending appearance for {0} to {1}", agentID.ToString(), AgentId.ToString()); | 3710 | //m_log.DebugFormat("[CLIENT]: Sending appearance for {0} to {1}", agentID.ToString(), AgentId.ToString()); |
3634 | OutPacket(avp, ThrottleOutPacketType.Task); | 3711 | OutPacket(avp, ThrottleOutPacketType.Task); |
3635 | } | 3712 | } |
@@ -3751,8 +3828,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3751 | { | 3828 | { |
3752 | SceneObjectPart e = (SceneObjectPart)entity; | 3829 | SceneObjectPart e = (SceneObjectPart)entity; |
3753 | SceneObjectGroup g = e.ParentGroup; | 3830 | SceneObjectGroup g = e.ParentGroup; |
3754 | if (g.RootPart.Shape.State > 30) // HUD | 3831 | if (g.HasPrivateAttachmentPoint && g.OwnerID != AgentId) |
3755 | if (g.OwnerID != AgentId) | ||
3756 | return; // Don't send updates for other people's HUDs | 3832 | return; // Don't send updates for other people's HUDs |
3757 | } | 3833 | } |
3758 | 3834 | ||
@@ -3762,43 +3838,64 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3762 | m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation)); | 3838 | m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation)); |
3763 | } | 3839 | } |
3764 | 3840 | ||
3765 | /// <summary> | 3841 | /* dont use this |
3766 | /// Requeue an EntityUpdate when it was not acknowledged by the client. | 3842 | udp packet resent must be done at udp level only |
3767 | /// We will update the priority and put it in the correct queue, merging update flags | 3843 | re map from a packet to original updates just doesnt work |
3768 | /// with any other updates that may be queued for the same entity. | ||
3769 | /// The original update time is used for the merged update. | ||
3770 | /// </summary> | ||
3771 | private void ResendPrimUpdate(EntityUpdate update) | ||
3772 | { | ||
3773 | // If the update exists in priority queue, it will be updated. | ||
3774 | // If it does not exist then it will be added with the current (rather than its original) priority | ||
3775 | uint priority = m_prioritizer.GetUpdatePriority(this, update.Entity); | ||
3776 | 3844 | ||
3777 | lock (m_entityUpdates.SyncRoot) | 3845 | /// <summary> |
3778 | m_entityUpdates.Enqueue(priority, update); | 3846 | /// Requeue an EntityUpdate when it was not acknowledged by the client. |
3779 | } | 3847 | /// We will update the priority and put it in the correct queue, merging update flags |
3848 | /// with any other updates that may be queued for the same entity. | ||
3849 | /// The original update time is used for the merged update. | ||
3850 | /// </summary> | ||
3851 | private void ResendPrimUpdate(EntityUpdate update) | ||
3852 | { | ||
3853 | // If the update exists in priority queue, it will be updated. | ||
3854 | // If it does not exist then it will be added with the current (rather than its original) priority | ||
3855 | uint priority = m_prioritizer.GetUpdatePriority(this, update.Entity); | ||
3780 | 3856 | ||
3781 | /// <summary> | 3857 | lock (m_entityUpdates.SyncRoot) |
3782 | /// Requeue a list of EntityUpdates when they were not acknowledged by the client. | 3858 | m_entityUpdates.Enqueue(priority, update); |
3783 | /// We will update the priority and put it in the correct queue, merging update flags | 3859 | } |
3784 | /// with any other updates that may be queued for the same entity. | ||
3785 | /// The original update time is used for the merged update. | ||
3786 | /// </summary> | ||
3787 | private void ResendPrimUpdates(List<EntityUpdate> updates, OutgoingPacket oPacket) | ||
3788 | { | ||
3789 | // m_log.WarnFormat("[CLIENT] resending prim updates {0}, packet sequence number {1}", updates[0].UpdateTime, oPacket.SequenceNumber); | ||
3790 | 3860 | ||
3791 | // Remove the update packet from the list of packets waiting for acknowledgement | ||
3792 | // because we are requeuing the list of updates. They will be resent in new packets | ||
3793 | // with the most recent state and priority. | ||
3794 | m_udpClient.NeedAcks.Remove(oPacket.SequenceNumber); | ||
3795 | 3861 | ||
3796 | // Count this as a resent packet since we are going to requeue all of the updates contained in it | 3862 | /// <summary> |
3797 | Interlocked.Increment(ref m_udpClient.PacketsResent); | 3863 | /// Requeue a list of EntityUpdates when they were not acknowledged by the client. |
3864 | /// We will update the priority and put it in the correct queue, merging update flags | ||
3865 | /// with any other updates that may be queued for the same entity. | ||
3866 | /// The original update time is used for the merged update. | ||
3867 | /// </summary> | ||
3868 | private void ResendPrimUpdates(List<EntityUpdate> updates, OutgoingPacket oPacket) | ||
3869 | { | ||
3870 | // m_log.WarnFormat("[CLIENT] resending prim updates {0}, packet sequence number {1}", updates[0].UpdateTime, oPacket.SequenceNumber); | ||
3871 | |||
3872 | // Remove the update packet from the list of packets waiting for acknowledgement | ||
3873 | // because we are requeuing the list of updates. They will be resent in new packets | ||
3874 | // with the most recent state and priority. | ||
3875 | m_udpClient.NeedAcks.Remove(oPacket.SequenceNumber); | ||
3876 | |||
3877 | // Count this as a resent packet since we are going to requeue all of the updates contained in it | ||
3878 | Interlocked.Increment(ref m_udpClient.PacketsResent); | ||
3879 | |||
3880 | // We're not going to worry about interlock yet since its not currently critical that this total count | ||
3881 | // is 100% correct | ||
3882 | m_udpServer.PacketsResentCount++; | ||
3883 | |||
3884 | foreach (EntityUpdate update in updates) | ||
3885 | ResendPrimUpdate(update); | ||
3886 | } | ||
3887 | */ | ||
3888 | |||
3889 | // OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>(); | ||
3890 | // OpenSim.Framework.Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>> compressedUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>>(); | ||
3891 | // OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>(); | ||
3892 | // OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>(); | ||
3893 | // | ||
3894 | // OpenSim.Framework.Lazy<List<EntityUpdate>> objectUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); | ||
3895 | // OpenSim.Framework.Lazy<List<EntityUpdate>> compressedUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); | ||
3896 | // OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); | ||
3897 | // OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); | ||
3798 | 3898 | ||
3799 | foreach (EntityUpdate update in updates) | ||
3800 | ResendPrimUpdate(update); | ||
3801 | } | ||
3802 | 3899 | ||
3803 | private void ProcessEntityUpdates(int maxUpdates) | 3900 | private void ProcessEntityUpdates(int maxUpdates) |
3804 | { | 3901 | { |
@@ -3812,6 +3909,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3812 | OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); | 3909 | OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); |
3813 | OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); | 3910 | OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); |
3814 | 3911 | ||
3912 | // objectUpdateBlocks.Value.Clear(); | ||
3913 | // compressedUpdateBlocks.Value.Clear(); | ||
3914 | // terseUpdateBlocks.Value.Clear(); | ||
3915 | // terseAgentUpdateBlocks.Value.Clear(); | ||
3916 | // objectUpdates.Value.Clear(); | ||
3917 | // compressedUpdates.Value.Clear(); | ||
3918 | // terseUpdates.Value.Clear(); | ||
3919 | // terseAgentUpdates.Value.Clear(); | ||
3920 | |||
3815 | // Check to see if this is a flush | 3921 | // Check to see if this is a flush |
3816 | if (maxUpdates <= 0) | 3922 | if (maxUpdates <= 0) |
3817 | { | 3923 | { |
@@ -3846,8 +3952,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3846 | 3952 | ||
3847 | if (part.ParentGroup.IsAttachment) | 3953 | if (part.ParentGroup.IsAttachment) |
3848 | { // Someone else's HUD, why are we getting these? | 3954 | { // Someone else's HUD, why are we getting these? |
3849 | if (part.ParentGroup.OwnerID != AgentId && | 3955 | if (part.ParentGroup.OwnerID != AgentId && part.ParentGroup.HasPrivateAttachmentPoint) |
3850 | part.ParentGroup.RootPart.Shape.State > 30) | ||
3851 | continue; | 3956 | continue; |
3852 | ScenePresence sp; | 3957 | ScenePresence sp; |
3853 | // Owner is not in the sim, don't update it to | 3958 | // Owner is not in the sim, don't update it to |
@@ -4098,12 +4203,40 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4098 | for (int i = 0; i < blocks.Count; i++) | 4203 | for (int i = 0; i < blocks.Count; i++) |
4099 | packet.ObjectData[i] = blocks[i]; | 4204 | packet.ObjectData[i] = blocks[i]; |
4100 | 4205 | ||
4101 | OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); }); | 4206 | // OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); }); |
4207 | // use default udp retry | ||
4208 | OutPacket(packet, ThrottleOutPacketType.Task, true); | ||
4102 | } | 4209 | } |
4103 | 4210 | ||
4211 | |||
4212 | |||
4104 | #endregion Packet Sending | 4213 | #endregion Packet Sending |
4214 | |||
4105 | } | 4215 | } |
4106 | 4216 | ||
4217 | // hack.. dont use | ||
4218 | public void SendPartFullUpdate(ISceneEntity ent, uint? parentID) | ||
4219 | { | ||
4220 | if (ent is SceneObjectPart) | ||
4221 | { | ||
4222 | SceneObjectPart part = (SceneObjectPart)ent; | ||
4223 | ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate); | ||
4224 | packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; | ||
4225 | packet.RegionData.TimeDilation = 1; | ||
4226 | packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1]; | ||
4227 | |||
4228 | ObjectUpdatePacket.ObjectDataBlock blk = CreatePrimUpdateBlock(part, this.m_agentId); | ||
4229 | if (parentID.HasValue) | ||
4230 | { | ||
4231 | blk.ParentID = parentID.Value; | ||
4232 | } | ||
4233 | |||
4234 | packet.ObjectData[0] = blk; | ||
4235 | |||
4236 | OutPacket(packet, ThrottleOutPacketType.Task, true); | ||
4237 | } | ||
4238 | } | ||
4239 | |||
4107 | public void ReprioritizeUpdates() | 4240 | public void ReprioritizeUpdates() |
4108 | { | 4241 | { |
4109 | lock (m_entityUpdates.SyncRoot) | 4242 | lock (m_entityUpdates.SyncRoot) |
@@ -4140,8 +4273,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4140 | 4273 | ||
4141 | void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories) | 4274 | void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories) |
4142 | { | 4275 | { |
4276 | // if (!m_udpServer.IsRunningOutbound) | ||
4277 | // return; | ||
4278 | |||
4143 | if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) | 4279 | if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) |
4144 | { | 4280 | { |
4281 | // if (!m_udpServer.IsRunningOutbound) | ||
4282 | // return; | ||
4283 | |||
4145 | if (m_maxUpdates == 0 || m_LastQueueFill == 0) | 4284 | if (m_maxUpdates == 0 || m_LastQueueFill == 0) |
4146 | { | 4285 | { |
4147 | m_maxUpdates = m_udpServer.PrimUpdatesPerCallback; | 4286 | m_maxUpdates = m_udpServer.PrimUpdatesPerCallback; |
@@ -4167,6 +4306,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4167 | ImageManager.ProcessImageQueue(m_udpServer.TextureSendLimit); | 4306 | ImageManager.ProcessImageQueue(m_udpServer.TextureSendLimit); |
4168 | } | 4307 | } |
4169 | 4308 | ||
4309 | internal bool HandleHasUpdates(ThrottleOutPacketTypeFlags categories) | ||
4310 | { | ||
4311 | bool hasUpdates = false; | ||
4312 | |||
4313 | if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) | ||
4314 | { | ||
4315 | if (m_entityUpdates.Count > 0) | ||
4316 | hasUpdates = true; | ||
4317 | else if (m_entityProps.Count > 0) | ||
4318 | hasUpdates = true; | ||
4319 | } | ||
4320 | |||
4321 | if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0) | ||
4322 | { | ||
4323 | if (ImageManager.HasUpdates()) | ||
4324 | hasUpdates = true; | ||
4325 | } | ||
4326 | |||
4327 | return hasUpdates; | ||
4328 | } | ||
4329 | |||
4170 | public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID) | 4330 | public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID) |
4171 | { | 4331 | { |
4172 | AssetUploadCompletePacket newPack = new AssetUploadCompletePacket(); | 4332 | AssetUploadCompletePacket newPack = new AssetUploadCompletePacket(); |
@@ -4312,6 +4472,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4312 | // Count this as a resent packet since we are going to requeue all of the updates contained in it | 4472 | // Count this as a resent packet since we are going to requeue all of the updates contained in it |
4313 | Interlocked.Increment(ref m_udpClient.PacketsResent); | 4473 | Interlocked.Increment(ref m_udpClient.PacketsResent); |
4314 | 4474 | ||
4475 | // We're not going to worry about interlock yet since its not currently critical that this total count | ||
4476 | // is 100% correct | ||
4477 | m_udpServer.PacketsResentCount++; | ||
4478 | |||
4315 | foreach (ObjectPropertyUpdate update in updates) | 4479 | foreach (ObjectPropertyUpdate update in updates) |
4316 | ResendPropertyUpdate(update); | 4480 | ResendPropertyUpdate(update); |
4317 | } | 4481 | } |
@@ -4499,6 +4663,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4499 | SceneObjectPart root = sop.ParentGroup.RootPart; | 4663 | SceneObjectPart root = sop.ParentGroup.RootPart; |
4500 | 4664 | ||
4501 | block.TouchName = Util.StringToBytes256(root.TouchName); | 4665 | block.TouchName = Util.StringToBytes256(root.TouchName); |
4666 | |||
4667 | // SL 3.3.4, at least, appears to read this information as a concatenated byte[] stream of UUIDs but | ||
4668 | // it's not yet clear whether this is actually used. If this is done in the future then a pre-cached | ||
4669 | // copy is really needed since it's less efficient to be constantly recreating this byte array. | ||
4670 | // using (MemoryStream memStream = new MemoryStream()) | ||
4671 | // { | ||
4672 | // using (BinaryWriter binWriter = new BinaryWriter(memStream)) | ||
4673 | // { | ||
4674 | // for (int i = 0; i < sop.GetNumberOfSides(); i++) | ||
4675 | // { | ||
4676 | // Primitive.TextureEntryFace teFace = sop.Shape.Textures.FaceTextures[i]; | ||
4677 | // | ||
4678 | // UUID textureID; | ||
4679 | // | ||
4680 | // if (teFace != null) | ||
4681 | // textureID = teFace.TextureID; | ||
4682 | // else | ||
4683 | // textureID = sop.Shape.Textures.DefaultTexture.TextureID; | ||
4684 | // | ||
4685 | // binWriter.Write(textureID.GetBytes()); | ||
4686 | // } | ||
4687 | // | ||
4688 | // block.TextureID = memStream.ToArray(); | ||
4689 | // } | ||
4690 | // } | ||
4691 | |||
4502 | block.TextureID = new byte[0]; // TextureID ??? | 4692 | block.TextureID = new byte[0]; // TextureID ??? |
4503 | block.SitName = Util.StringToBytes256(root.SitName); | 4693 | block.SitName = Util.StringToBytes256(root.SitName); |
4504 | block.OwnerMask = root.OwnerMask; | 4694 | block.OwnerMask = root.OwnerMask; |
@@ -4839,7 +5029,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4839 | IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>(); | 5029 | IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>(); |
4840 | if (eq != null) | 5030 | if (eq != null) |
4841 | { | 5031 | { |
4842 | eq.ParcelProperties(updateMessage, this.AgentId); | 5032 | OSD message_body = updateMessage.Serialize(); |
5033 | // Add new fields here until OMV has them | ||
5034 | OSDMap bodyMap = (OSDMap)message_body; | ||
5035 | OSDArray parcelDataArray = (OSDArray)bodyMap["ParcelData"]; | ||
5036 | OSDMap parcelData = (OSDMap)parcelDataArray[0]; | ||
5037 | parcelData["SeeAVs"] = OSD.FromBoolean(landData.SeeAVs); | ||
5038 | parcelData["AnyAVSounds"] = OSD.FromBoolean(landData.AnyAVSounds); | ||
5039 | parcelData["GroupAVSounds"] = OSD.FromBoolean(landData.GroupAVSounds); | ||
5040 | OSDMap message = new OSDMap(); | ||
5041 | message.Add("message", OSD.FromString("ParcelProperties")); | ||
5042 | message.Add("body", message_body); | ||
5043 | eq.Enqueue (message, this.AgentId); | ||
5044 | //eq.ParcelProperties(updateMessage, this.AgentId); | ||
4843 | } | 5045 | } |
4844 | else | 5046 | else |
4845 | { | 5047 | { |
@@ -4877,7 +5079,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4877 | 5079 | ||
4878 | public void SendForceClientSelectObjects(List<uint> ObjectIDs) | 5080 | public void SendForceClientSelectObjects(List<uint> ObjectIDs) |
4879 | { | 5081 | { |
4880 | m_log.WarnFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count); | 5082 | // m_log.DebugFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count); |
4881 | 5083 | ||
4882 | bool firstCall = true; | 5084 | bool firstCall = true; |
4883 | const int MAX_OBJECTS_PER_PACKET = 251; | 5085 | const int MAX_OBJECTS_PER_PACKET = 251; |
@@ -4997,33 +5199,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4997 | 5199 | ||
4998 | position = presence.OffsetPosition; | 5200 | position = presence.OffsetPosition; |
4999 | rotation = presence.Rotation; | 5201 | rotation = presence.Rotation; |
5000 | 5202 | angularVelocity = presence.AngularVelocity; | |
5001 | if (presence.ParentID != 0) | 5203 | rotation = presence.Rotation; |
5002 | { | ||
5003 | SceneObjectPart part = m_scene.GetSceneObjectPart(presence.ParentID); | ||
5004 | if (part != null && part != part.ParentGroup.RootPart) | ||
5005 | { | ||
5006 | position = part.OffsetPosition + presence.OffsetPosition * part.RotationOffset; | ||
5007 | rotation = part.RotationOffset * presence.Rotation; | ||
5008 | } | ||
5009 | angularVelocity = Vector3.Zero; | ||
5010 | } | ||
5011 | else | ||
5012 | { | ||
5013 | angularVelocity = presence.AngularVelocity; | ||
5014 | rotation = presence.Rotation; | ||
5015 | } | ||
5016 | 5204 | ||
5017 | attachPoint = 0; | 5205 | attachPoint = 0; |
5206 | // m_log.DebugFormat( | ||
5207 | // "[LLCLIENTVIEW]: Sending terse update to {0} with position {1} in {2}", Name, presence.OffsetPosition, m_scene.Name); | ||
5208 | |||
5209 | // attachPoint = presence.State; // Core: commented | ||
5018 | collisionPlane = presence.CollisionPlane; | 5210 | collisionPlane = presence.CollisionPlane; |
5019 | velocity = presence.Velocity; | 5211 | velocity = presence.Velocity; |
5020 | acceleration = Vector3.Zero; | 5212 | acceleration = Vector3.Zero; |
5021 | 5213 | ||
5022 | // Interestingly, sending this to non-zero will cause the client's avatar to start moving & accelerating | ||
5023 | // in that direction, even though we don't model this on the server. Implementing this in the future | ||
5024 | // may improve movement smoothness. | ||
5025 | // acceleration = new Vector3(1, 0, 0); | ||
5026 | |||
5027 | if (sendTexture) | 5214 | if (sendTexture) |
5028 | textureEntry = presence.Appearance.Texture.GetBytes(); | 5215 | textureEntry = presence.Appearance.Texture.GetBytes(); |
5029 | else | 5216 | else |
@@ -5034,7 +5221,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5034 | SceneObjectPart part = (SceneObjectPart)entity; | 5221 | SceneObjectPart part = (SceneObjectPart)entity; |
5035 | 5222 | ||
5036 | attachPoint = part.ParentGroup.AttachmentPoint; | 5223 | attachPoint = part.ParentGroup.AttachmentPoint; |
5037 | 5224 | attachPoint = ((attachPoint % 16) * 16 + (attachPoint / 16)); | |
5038 | // m_log.DebugFormat( | 5225 | // m_log.DebugFormat( |
5039 | // "[LLCLIENTVIEW]: Sending attachPoint {0} for {1} {2} to {3}", | 5226 | // "[LLCLIENTVIEW]: Sending attachPoint {0} for {1} {2} to {3}", |
5040 | // attachPoint, part.Name, part.LocalId, Name); | 5227 | // attachPoint, part.Name, part.LocalId, Name); |
@@ -5062,7 +5249,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5062 | pos += 4; | 5249 | pos += 4; |
5063 | 5250 | ||
5064 | // Avatar/CollisionPlane | 5251 | // Avatar/CollisionPlane |
5065 | data[pos++] = (byte)((attachPoint % 16) * 16 + (attachPoint / 16)); ; | 5252 | data[pos++] = (byte) attachPoint; |
5066 | if (avatar) | 5253 | if (avatar) |
5067 | { | 5254 | { |
5068 | data[pos++] = 1; | 5255 | data[pos++] = 1; |
@@ -5132,30 +5319,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5132 | Vector3 offsetPosition = data.OffsetPosition; | 5319 | Vector3 offsetPosition = data.OffsetPosition; |
5133 | Quaternion rotation = data.Rotation; | 5320 | Quaternion rotation = data.Rotation; |
5134 | uint parentID = data.ParentID; | 5321 | uint parentID = data.ParentID; |
5135 | 5322 | ||
5136 | if (parentID != 0) | 5323 | // m_log.DebugFormat( |
5137 | { | 5324 | // "[LLCLIENTVIEW]: Sending full update to {0} with position {1} in {2}", Name, data.OffsetPosition, m_scene.Name); |
5138 | SceneObjectPart part = m_scene.GetSceneObjectPart(parentID); | ||
5139 | if (part != null && part != part.ParentGroup.RootPart) | ||
5140 | { | ||
5141 | offsetPosition = part.OffsetPosition + data.OffsetPosition * part.RotationOffset; | ||
5142 | rotation = part.RotationOffset * data.Rotation; | ||
5143 | parentID = part.ParentGroup.RootPart.LocalId; | ||
5144 | } | ||
5145 | } | ||
5146 | 5325 | ||
5147 | byte[] objectData = new byte[76]; | 5326 | byte[] objectData = new byte[76]; |
5148 | 5327 | ||
5149 | data.CollisionPlane.ToBytes(objectData, 0); | ||
5150 | offsetPosition.ToBytes(objectData, 16); | ||
5151 | Vector3 velocity = new Vector3(0, 0, 0); | 5328 | Vector3 velocity = new Vector3(0, 0, 0); |
5152 | Vector3 acceleration = new Vector3(0, 0, 0); | 5329 | Vector3 acceleration = new Vector3(0, 0, 0); |
5330 | rotation.Normalize(); | ||
5331 | Vector3 vrot = new Vector3(rotation.X, rotation.Y, rotation.Z); | ||
5332 | |||
5333 | data.CollisionPlane.ToBytes(objectData, 0); | ||
5334 | offsetPosition.ToBytes(objectData, 16); | ||
5153 | velocity.ToBytes(objectData, 28); | 5335 | velocity.ToBytes(objectData, 28); |
5154 | acceleration.ToBytes(objectData, 40); | 5336 | acceleration.ToBytes(objectData, 40); |
5155 | // data.Velocity.ToBytes(objectData, 28); | 5337 | vrot.ToBytes(objectData, 52); |
5156 | // data.Acceleration.ToBytes(objectData, 40); | 5338 | data.AngularVelocity.ToBytes(objectData, 64); |
5157 | rotation.ToBytes(objectData, 52); | ||
5158 | //data.AngularVelocity.ToBytes(objectData, 64); | ||
5159 | 5339 | ||
5160 | ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); | 5340 | ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); |
5161 | 5341 | ||
@@ -5168,7 +5348,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5168 | update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " + | 5348 | update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " + |
5169 | data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle); | 5349 | data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle); |
5170 | update.ObjectData = objectData; | 5350 | update.ObjectData = objectData; |
5171 | update.ParentID = parentID; | 5351 | |
5352 | SceneObjectPart parentPart = data.ParentPart; | ||
5353 | if (parentPart != null) | ||
5354 | update.ParentID = parentPart.ParentGroup.LocalId; | ||
5355 | else | ||
5356 | update.ParentID = 0; | ||
5357 | |||
5172 | update.PathCurve = 16; | 5358 | update.PathCurve = 16; |
5173 | update.PathScaleX = 100; | 5359 | update.PathScaleX = 100; |
5174 | update.PathScaleY = 100; | 5360 | update.PathScaleY = 100; |
@@ -5205,15 +5391,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5205 | data.RelativePosition.ToBytes(objectData, 0); | 5391 | data.RelativePosition.ToBytes(objectData, 0); |
5206 | data.Velocity.ToBytes(objectData, 12); | 5392 | data.Velocity.ToBytes(objectData, 12); |
5207 | data.Acceleration.ToBytes(objectData, 24); | 5393 | data.Acceleration.ToBytes(objectData, 24); |
5208 | try | 5394 | |
5209 | { | 5395 | Quaternion rotation = data.RotationOffset; |
5210 | data.RotationOffset.ToBytes(objectData, 36); | 5396 | rotation.Normalize(); |
5211 | } | 5397 | Vector3 vrot = new Vector3(rotation.X, rotation.Y, rotation.Z); |
5212 | catch (Exception e) | 5398 | vrot.ToBytes(objectData, 36); |
5213 | { | ||
5214 | m_log.Warn("[LLClientView]: exception converting quaternion to bytes, using Quaternion.Identity. Exception: " + e.ToString()); | ||
5215 | OpenMetaverse.Quaternion.Identity.ToBytes(objectData, 36); | ||
5216 | } | ||
5217 | data.AngularVelocity.ToBytes(objectData, 48); | 5399 | data.AngularVelocity.ToBytes(objectData, 48); |
5218 | 5400 | ||
5219 | ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); | 5401 | ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); |
@@ -5387,7 +5569,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5387 | AddLocalPacketHandler(PacketType.RezObject, HandlerRezObject); | 5569 | AddLocalPacketHandler(PacketType.RezObject, HandlerRezObject); |
5388 | AddLocalPacketHandler(PacketType.DeRezObject, HandlerDeRezObject); | 5570 | AddLocalPacketHandler(PacketType.DeRezObject, HandlerDeRezObject); |
5389 | AddLocalPacketHandler(PacketType.ModifyLand, HandlerModifyLand); | 5571 | AddLocalPacketHandler(PacketType.ModifyLand, HandlerModifyLand); |
5390 | AddLocalPacketHandler(PacketType.RegionHandshakeReply, HandlerRegionHandshakeReply); | 5572 | AddLocalPacketHandler(PacketType.RegionHandshakeReply, HandlerRegionHandshakeReply, false); |
5391 | AddLocalPacketHandler(PacketType.AgentWearablesRequest, HandlerAgentWearablesRequest); | 5573 | AddLocalPacketHandler(PacketType.AgentWearablesRequest, HandlerAgentWearablesRequest); |
5392 | AddLocalPacketHandler(PacketType.AgentSetAppearance, HandlerAgentSetAppearance); | 5574 | AddLocalPacketHandler(PacketType.AgentSetAppearance, HandlerAgentSetAppearance); |
5393 | AddLocalPacketHandler(PacketType.AgentIsNowWearing, HandlerAgentIsNowWearing); | 5575 | AddLocalPacketHandler(PacketType.AgentIsNowWearing, HandlerAgentIsNowWearing); |
@@ -5448,8 +5630,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5448 | AddLocalPacketHandler(PacketType.ScriptAnswerYes, HandleScriptAnswerYes, false); | 5630 | AddLocalPacketHandler(PacketType.ScriptAnswerYes, HandleScriptAnswerYes, false); |
5449 | AddLocalPacketHandler(PacketType.ObjectClickAction, HandleObjectClickAction, false); | 5631 | AddLocalPacketHandler(PacketType.ObjectClickAction, HandleObjectClickAction, false); |
5450 | AddLocalPacketHandler(PacketType.ObjectMaterial, HandleObjectMaterial, false); | 5632 | AddLocalPacketHandler(PacketType.ObjectMaterial, HandleObjectMaterial, false); |
5451 | AddLocalPacketHandler(PacketType.RequestImage, HandleRequestImage); | 5633 | AddLocalPacketHandler(PacketType.RequestImage, HandleRequestImage, false); |
5452 | AddLocalPacketHandler(PacketType.TransferRequest, HandleTransferRequest); | 5634 | AddLocalPacketHandler(PacketType.TransferRequest, HandleTransferRequest, false); |
5453 | AddLocalPacketHandler(PacketType.AssetUploadRequest, HandleAssetUploadRequest); | 5635 | AddLocalPacketHandler(PacketType.AssetUploadRequest, HandleAssetUploadRequest); |
5454 | AddLocalPacketHandler(PacketType.RequestXfer, HandleRequestXfer); | 5636 | AddLocalPacketHandler(PacketType.RequestXfer, HandleRequestXfer); |
5455 | AddLocalPacketHandler(PacketType.SendXferPacket, HandleSendXferPacket); | 5637 | AddLocalPacketHandler(PacketType.SendXferPacket, HandleSendXferPacket); |
@@ -5481,7 +5663,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5481 | AddLocalPacketHandler(PacketType.TeleportCancel, HandleTeleportCancel); | 5663 | AddLocalPacketHandler(PacketType.TeleportCancel, HandleTeleportCancel); |
5482 | AddLocalPacketHandler(PacketType.TeleportLocationRequest, HandleTeleportLocationRequest); | 5664 | AddLocalPacketHandler(PacketType.TeleportLocationRequest, HandleTeleportLocationRequest); |
5483 | AddLocalPacketHandler(PacketType.UUIDNameRequest, HandleUUIDNameRequest, false); | 5665 | AddLocalPacketHandler(PacketType.UUIDNameRequest, HandleUUIDNameRequest, false); |
5484 | AddLocalPacketHandler(PacketType.RegionHandleRequest, HandleRegionHandleRequest); | 5666 | AddLocalPacketHandler(PacketType.RegionHandleRequest, HandleRegionHandleRequest, false); |
5485 | AddLocalPacketHandler(PacketType.ParcelInfoRequest, HandleParcelInfoRequest); | 5667 | AddLocalPacketHandler(PacketType.ParcelInfoRequest, HandleParcelInfoRequest); |
5486 | AddLocalPacketHandler(PacketType.ParcelAccessListRequest, HandleParcelAccessListRequest, false); | 5668 | AddLocalPacketHandler(PacketType.ParcelAccessListRequest, HandleParcelAccessListRequest, false); |
5487 | AddLocalPacketHandler(PacketType.ParcelAccessListUpdate, HandleParcelAccessListUpdate, false); | 5669 | AddLocalPacketHandler(PacketType.ParcelAccessListUpdate, HandleParcelAccessListUpdate, false); |
@@ -5594,82 +5776,146 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5594 | 5776 | ||
5595 | #region Packet Handlers | 5777 | #region Packet Handlers |
5596 | 5778 | ||
5779 | public int TotalAgentUpdates { get; set; } | ||
5780 | |||
5597 | #region Scene/Avatar | 5781 | #region Scene/Avatar |
5598 | 5782 | ||
5599 | private bool HandleAgentUpdate(IClientAPI sener, Packet packet) | 5783 | // Threshold for body rotation to be a significant agent update |
5784 | // use the abs of cos | ||
5785 | private const float QDELTABody = 1.0f - 0.0001f; | ||
5786 | private const float QDELTAHead = 1.0f - 0.0001f; | ||
5787 | // Threshold for camera rotation to be a significant agent update | ||
5788 | private const float VDELTA = 0.01f; | ||
5789 | |||
5790 | /// <summary> | ||
5791 | /// This checks the update significance against the last update made. | ||
5792 | /// </summary> | ||
5793 | /// <remarks>Can only be called by one thread at a time</remarks> | ||
5794 | /// <returns></returns> | ||
5795 | /// <param name='x'></param> | ||
5796 | public bool CheckAgentUpdateSignificance(AgentUpdatePacket.AgentDataBlock x) | ||
5600 | { | 5797 | { |
5601 | if (OnAgentUpdate != null) | 5798 | return CheckAgentMovementUpdateSignificance(x) || CheckAgentCameraUpdateSignificance(x); |
5799 | } | ||
5800 | |||
5801 | /// <summary> | ||
5802 | /// This checks the movement/state update significance against the last update made. | ||
5803 | /// </summary> | ||
5804 | /// <remarks>Can only be called by one thread at a time</remarks> | ||
5805 | /// <returns></returns> | ||
5806 | /// <param name='x'></param> | ||
5807 | private bool CheckAgentMovementUpdateSignificance(AgentUpdatePacket.AgentDataBlock x) | ||
5808 | { | ||
5809 | float qdelta1 = Math.Abs(Quaternion.Dot(x.BodyRotation, m_thisAgentUpdateArgs.BodyRotation)); | ||
5810 | //qdelta2 = Math.Abs(Quaternion.Dot(x.HeadRotation, m_thisAgentUpdateArgs.HeadRotation)); | ||
5811 | |||
5812 | bool movementSignificant = | ||
5813 | (x.ControlFlags != m_thisAgentUpdateArgs.ControlFlags) // significant if control flags changed | ||
5814 | || (x.ControlFlags != (byte)AgentManager.ControlFlags.NONE) // significant if user supplying any movement update commands | ||
5815 | || (x.Flags != m_thisAgentUpdateArgs.Flags) // significant if Flags changed | ||
5816 | || (x.State != m_thisAgentUpdateArgs.State) // significant if Stats changed | ||
5817 | || (qdelta1 < QDELTABody) // significant if body rotation above(below cos) threshold | ||
5818 | // Ignoring head rotation altogether, because it's not being used for anything interesting up the stack | ||
5819 | // || (qdelta2 < QDELTAHead) // significant if head rotation above(below cos) threshold | ||
5820 | || (x.Far != m_thisAgentUpdateArgs.Far) // significant if far distance changed | ||
5821 | ; | ||
5822 | //if (movementSignificant) | ||
5823 | //{ | ||
5824 | //m_log.DebugFormat("[LLCLIENTVIEW]: Bod {0} {1}", | ||
5825 | // qdelta1, qdelta2); | ||
5826 | //m_log.DebugFormat("[LLCLIENTVIEW]: St {0} {1} {2} {3}", | ||
5827 | // x.ControlFlags, x.Flags, x.Far, x.State); | ||
5828 | //} | ||
5829 | return movementSignificant; | ||
5830 | } | ||
5831 | |||
5832 | /// <summary> | ||
5833 | /// This checks the camera update significance against the last update made. | ||
5834 | /// </summary> | ||
5835 | /// <remarks>Can only be called by one thread at a time</remarks> | ||
5836 | /// <returns></returns> | ||
5837 | /// <param name='x'></param> | ||
5838 | private bool CheckAgentCameraUpdateSignificance(AgentUpdatePacket.AgentDataBlock x) | ||
5839 | { | ||
5840 | float vdelta1 = Vector3.Distance(x.CameraAtAxis, m_thisAgentUpdateArgs.CameraAtAxis); | ||
5841 | float vdelta2 = Vector3.Distance(x.CameraCenter, m_thisAgentUpdateArgs.CameraCenter); | ||
5842 | float vdelta3 = Vector3.Distance(x.CameraLeftAxis, m_thisAgentUpdateArgs.CameraLeftAxis); | ||
5843 | float vdelta4 = Vector3.Distance(x.CameraUpAxis, m_thisAgentUpdateArgs.CameraUpAxis); | ||
5844 | |||
5845 | bool cameraSignificant = | ||
5846 | (vdelta1 > VDELTA) || | ||
5847 | (vdelta2 > VDELTA) || | ||
5848 | (vdelta3 > VDELTA) || | ||
5849 | (vdelta4 > VDELTA) | ||
5850 | ; | ||
5851 | |||
5852 | //if (cameraSignificant) | ||
5853 | //{ | ||
5854 | //m_log.DebugFormat("[LLCLIENTVIEW]: Cam1 {0} {1}", | ||
5855 | // x.CameraAtAxis, x.CameraCenter); | ||
5856 | //m_log.DebugFormat("[LLCLIENTVIEW]: Cam2 {0} {1}", | ||
5857 | // x.CameraLeftAxis, x.CameraUpAxis); | ||
5858 | //} | ||
5859 | |||
5860 | return cameraSignificant; | ||
5861 | } | ||
5862 | |||
5863 | private bool HandleAgentUpdate(IClientAPI sender, Packet packet) | ||
5864 | { | ||
5865 | // We got here, which means that something in agent update was significant | ||
5866 | |||
5867 | AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet; | ||
5868 | AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData; | ||
5869 | |||
5870 | if (x.AgentID != AgentId || x.SessionID != SessionId) | ||
5602 | { | 5871 | { |
5603 | AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet; | 5872 | PacketPool.Instance.ReturnPacket(packet); |
5873 | return false; | ||
5874 | } | ||
5604 | 5875 | ||
5605 | #region Packet Session and User Check | 5876 | TotalAgentUpdates++; |
5606 | if (agentUpdate.AgentData.SessionID != SessionId || agentUpdate.AgentData.AgentID != AgentId) | ||
5607 | { | ||
5608 | PacketPool.Instance.ReturnPacket(packet); | ||
5609 | return false; | ||
5610 | } | ||
5611 | #endregion | ||
5612 | 5877 | ||
5613 | bool update = false; | 5878 | bool movement = CheckAgentMovementUpdateSignificance(x); |
5614 | AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData; | 5879 | bool camera = CheckAgentCameraUpdateSignificance(x); |
5615 | |||
5616 | if (m_lastAgentUpdateArgs != null) | ||
5617 | { | ||
5618 | // These should be ordered from most-likely to | ||
5619 | // least likely to change. I've made an initial | ||
5620 | // guess at that. | ||
5621 | update = | ||
5622 | ( | ||
5623 | (x.BodyRotation != m_lastAgentUpdateArgs.BodyRotation) || | ||
5624 | (x.CameraAtAxis != m_lastAgentUpdateArgs.CameraAtAxis) || | ||
5625 | (x.CameraCenter != m_lastAgentUpdateArgs.CameraCenter) || | ||
5626 | (x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) || | ||
5627 | (x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) || | ||
5628 | (x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) || | ||
5629 | (x.ControlFlags != 0) || | ||
5630 | (x.Far != m_lastAgentUpdateArgs.Far) || | ||
5631 | (x.Flags != m_lastAgentUpdateArgs.Flags) || | ||
5632 | (x.State != m_lastAgentUpdateArgs.State) || | ||
5633 | (x.HeadRotation != m_lastAgentUpdateArgs.HeadRotation) || | ||
5634 | (x.SessionID != m_lastAgentUpdateArgs.SessionID) || | ||
5635 | (x.AgentID != m_lastAgentUpdateArgs.AgentID) | ||
5636 | ); | ||
5637 | } | ||
5638 | else | ||
5639 | { | ||
5640 | m_lastAgentUpdateArgs = new AgentUpdateArgs(); | ||
5641 | update = true; | ||
5642 | } | ||
5643 | 5880 | ||
5644 | if (update) | 5881 | // Was there a significant movement/state change? |
5645 | { | 5882 | if (movement) |
5646 | // m_log.DebugFormat("[LLCLIENTVIEW]: Triggered AgentUpdate for {0}", sener.Name); | 5883 | { |
5884 | m_thisAgentUpdateArgs.BodyRotation = x.BodyRotation; | ||
5885 | m_thisAgentUpdateArgs.ControlFlags = x.ControlFlags; | ||
5886 | m_thisAgentUpdateArgs.Far = x.Far; | ||
5887 | m_thisAgentUpdateArgs.Flags = x.Flags; | ||
5888 | m_thisAgentUpdateArgs.HeadRotation = x.HeadRotation; | ||
5889 | // m_thisAgentUpdateArgs.SessionID = x.SessionID; | ||
5890 | m_thisAgentUpdateArgs.State = x.State; | ||
5647 | 5891 | ||
5648 | m_lastAgentUpdateArgs.AgentID = x.AgentID; | 5892 | UpdateAgent handlerAgentUpdate = OnAgentUpdate; |
5649 | m_lastAgentUpdateArgs.BodyRotation = x.BodyRotation; | 5893 | UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate; |
5650 | m_lastAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis; | ||
5651 | m_lastAgentUpdateArgs.CameraCenter = x.CameraCenter; | ||
5652 | m_lastAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis; | ||
5653 | m_lastAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis; | ||
5654 | m_lastAgentUpdateArgs.ControlFlags = x.ControlFlags; | ||
5655 | m_lastAgentUpdateArgs.Far = x.Far; | ||
5656 | m_lastAgentUpdateArgs.Flags = x.Flags; | ||
5657 | m_lastAgentUpdateArgs.HeadRotation = x.HeadRotation; | ||
5658 | m_lastAgentUpdateArgs.SessionID = x.SessionID; | ||
5659 | m_lastAgentUpdateArgs.State = x.State; | ||
5660 | 5894 | ||
5661 | UpdateAgent handlerAgentUpdate = OnAgentUpdate; | 5895 | if (handlerPreAgentUpdate != null) |
5662 | UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate; | 5896 | OnPreAgentUpdate(this, m_thisAgentUpdateArgs); |
5663 | 5897 | ||
5664 | if (handlerPreAgentUpdate != null) | 5898 | if (handlerAgentUpdate != null) |
5665 | OnPreAgentUpdate(this, m_lastAgentUpdateArgs); | 5899 | OnAgentUpdate(this, m_thisAgentUpdateArgs); |
5666 | 5900 | ||
5667 | if (handlerAgentUpdate != null) | 5901 | handlerAgentUpdate = null; |
5668 | OnAgentUpdate(this, m_lastAgentUpdateArgs); | 5902 | handlerPreAgentUpdate = null; |
5903 | } | ||
5669 | 5904 | ||
5670 | handlerAgentUpdate = null; | 5905 | // Was there a significant camera(s) change? |
5671 | handlerPreAgentUpdate = null; | 5906 | if (camera) |
5672 | } | 5907 | { |
5908 | m_thisAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis; | ||
5909 | m_thisAgentUpdateArgs.CameraCenter = x.CameraCenter; | ||
5910 | m_thisAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis; | ||
5911 | m_thisAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis; | ||
5912 | |||
5913 | UpdateAgent handlerAgentCameraUpdate = OnAgentCameraUpdate; | ||
5914 | |||
5915 | if (handlerAgentCameraUpdate != null) | ||
5916 | handlerAgentCameraUpdate(this, m_thisAgentUpdateArgs); | ||
5917 | |||
5918 | handlerAgentCameraUpdate = null; | ||
5673 | } | 5919 | } |
5674 | 5920 | ||
5675 | PacketPool.Instance.ReturnPacket(packet); | 5921 | PacketPool.Instance.ReturnPacket(packet); |
@@ -6260,6 +6506,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6260 | //m_log.Info("[LAND]: LAND:" + modify.ToString()); | 6506 | //m_log.Info("[LAND]: LAND:" + modify.ToString()); |
6261 | if (modify.ParcelData.Length > 0) | 6507 | if (modify.ParcelData.Length > 0) |
6262 | { | 6508 | { |
6509 | // Note: the ModifyTerrain event handler sends out updated packets before the end of this event. Therefore, | ||
6510 | // a simple boolean value should work and perhaps queue up just a few terrain patch packets at the end of the edit. | ||
6511 | m_justEditedTerrain = true; // Prevent terrain packet (Land layer) from being queued, make it unreliable | ||
6263 | if (OnModifyTerrain != null) | 6512 | if (OnModifyTerrain != null) |
6264 | { | 6513 | { |
6265 | for (int i = 0; i < modify.ParcelData.Length; i++) | 6514 | for (int i = 0; i < modify.ParcelData.Length; i++) |
@@ -6275,6 +6524,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6275 | } | 6524 | } |
6276 | } | 6525 | } |
6277 | } | 6526 | } |
6527 | m_justEditedTerrain = false; // Queue terrain packet (Land layer) if necessary, make it reliable again | ||
6278 | } | 6528 | } |
6279 | 6529 | ||
6280 | return true; | 6530 | return true; |
@@ -6343,7 +6593,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6343 | 6593 | ||
6344 | WearableCacheItem[] cacheitems = new WearableCacheItem[appear.WearableData.Length]; | 6594 | WearableCacheItem[] cacheitems = new WearableCacheItem[appear.WearableData.Length]; |
6345 | for (int i=0; i<appear.WearableData.Length;i++) | 6595 | for (int i=0; i<appear.WearableData.Length;i++) |
6346 | cacheitems[i] = new WearableCacheItem(){CacheId = appear.WearableData[i].CacheID,TextureIndex=Convert.ToUInt32(appear.WearableData[i].TextureIndex)}; | 6596 | cacheitems[i] = new WearableCacheItem(){ |
6597 | CacheId = appear.WearableData[i].CacheID, | ||
6598 | TextureIndex=Convert.ToUInt32(appear.WearableData[i].TextureIndex) | ||
6599 | }; | ||
6347 | 6600 | ||
6348 | 6601 | ||
6349 | 6602 | ||
@@ -6549,8 +6802,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6549 | return true; | 6802 | return true; |
6550 | } | 6803 | } |
6551 | 6804 | ||
6552 | private bool HandleCompleteAgentMovement(IClientAPI sender, Packet Pack) | 6805 | private bool HandleCompleteAgentMovement(IClientAPI sender, Packet Pack) |
6553 | { | 6806 | { |
6807 | m_log.DebugFormat("[LLClientView] HandleCompleteAgentMovement"); | ||
6808 | |||
6554 | Action<IClientAPI, bool> handlerCompleteMovementToRegion = OnCompleteMovementToRegion; | 6809 | Action<IClientAPI, bool> handlerCompleteMovementToRegion = OnCompleteMovementToRegion; |
6555 | if (handlerCompleteMovementToRegion != null) | 6810 | if (handlerCompleteMovementToRegion != null) |
6556 | { | 6811 | { |
@@ -6636,6 +6891,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6636 | } | 6891 | } |
6637 | #endregion | 6892 | #endregion |
6638 | 6893 | ||
6894 | if (SceneAgent.IsChildAgent) | ||
6895 | { | ||
6896 | SendCantSitBecauseChildAgentResponse(); | ||
6897 | return true; | ||
6898 | } | ||
6899 | |||
6639 | AgentRequestSit handlerAgentRequestSit = OnAgentRequestSit; | 6900 | AgentRequestSit handlerAgentRequestSit = OnAgentRequestSit; |
6640 | 6901 | ||
6641 | if (handlerAgentRequestSit != null) | 6902 | if (handlerAgentRequestSit != null) |
@@ -6660,6 +6921,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6660 | } | 6921 | } |
6661 | #endregion | 6922 | #endregion |
6662 | 6923 | ||
6924 | if (SceneAgent.IsChildAgent) | ||
6925 | { | ||
6926 | SendCantSitBecauseChildAgentResponse(); | ||
6927 | return true; | ||
6928 | } | ||
6929 | |||
6663 | AgentSit handlerAgentSit = OnAgentSit; | 6930 | AgentSit handlerAgentSit = OnAgentSit; |
6664 | if (handlerAgentSit != null) | 6931 | if (handlerAgentSit != null) |
6665 | { | 6932 | { |
@@ -6669,6 +6936,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6669 | return true; | 6936 | return true; |
6670 | } | 6937 | } |
6671 | 6938 | ||
6939 | /// <summary> | ||
6940 | /// Used when a child agent gets a sit response which should not be fulfilled. | ||
6941 | /// </summary> | ||
6942 | private void SendCantSitBecauseChildAgentResponse() | ||
6943 | { | ||
6944 | SendAlertMessage("Try moving closer. Can't sit on object because it is not in the same region as you."); | ||
6945 | } | ||
6946 | |||
6672 | private bool HandleSoundTrigger(IClientAPI sender, Packet Pack) | 6947 | private bool HandleSoundTrigger(IClientAPI sender, Packet Pack) |
6673 | { | 6948 | { |
6674 | SoundTriggerPacket soundTriggerPacket = (SoundTriggerPacket)Pack; | 6949 | SoundTriggerPacket soundTriggerPacket = (SoundTriggerPacket)Pack; |
@@ -7879,129 +8154,145 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
7879 | //m_log.Debug("ClientView.ProcessPackets.cs:ProcessInPacket() - Got transfer request"); | 8154 | //m_log.Debug("ClientView.ProcessPackets.cs:ProcessInPacket() - Got transfer request"); |
7880 | 8155 | ||
7881 | TransferRequestPacket transfer = (TransferRequestPacket)Pack; | 8156 | TransferRequestPacket transfer = (TransferRequestPacket)Pack; |
7882 | //m_log.Debug("Transfer Request: " + transfer.ToString()); | ||
7883 | // Validate inventory transfers | ||
7884 | // Has to be done here, because AssetCache can't do it | ||
7885 | // | ||
7886 | UUID taskID = UUID.Zero; | 8157 | UUID taskID = UUID.Zero; |
7887 | if (transfer.TransferInfo.SourceType == (int)SourceType.SimInventoryItem) | 8158 | if (transfer.TransferInfo.SourceType == (int)SourceType.SimInventoryItem) |
7888 | { | 8159 | { |
7889 | taskID = new UUID(transfer.TransferInfo.Params, 48); | ||
7890 | UUID itemID = new UUID(transfer.TransferInfo.Params, 64); | ||
7891 | UUID requestID = new UUID(transfer.TransferInfo.Params, 80); | ||
7892 | |||
7893 | // m_log.DebugFormat( | ||
7894 | // "[CLIENT]: Got request for asset {0} from item {1} in prim {2} by {3}", | ||
7895 | // requestID, itemID, taskID, Name); | ||
7896 | |||
7897 | if (!(((Scene)m_scene).Permissions.BypassPermissions())) | 8160 | if (!(((Scene)m_scene).Permissions.BypassPermissions())) |
7898 | { | 8161 | { |
7899 | if (taskID != UUID.Zero) // Prim | 8162 | // We're spawning a thread because the permissions check can block this thread |
8163 | Util.FireAndForget(delegate | ||
7900 | { | 8164 | { |
7901 | SceneObjectPart part = ((Scene)m_scene).GetSceneObjectPart(taskID); | 8165 | // This requests the asset if needed |
8166 | HandleSimInventoryTransferRequestWithPermsCheck(sender, transfer); | ||
8167 | }); | ||
8168 | return true; | ||
8169 | } | ||
8170 | } | ||
8171 | else if (transfer.TransferInfo.SourceType == (int)SourceType.SimEstate) | ||
8172 | { | ||
8173 | //TransferRequestPacket does not include covenant uuid? | ||
8174 | //get scene covenant uuid | ||
8175 | taskID = m_scene.RegionInfo.RegionSettings.Covenant; | ||
8176 | } | ||
7902 | 8177 | ||
7903 | if (part == null) | 8178 | // This is non-blocking |
7904 | { | 8179 | MakeAssetRequest(transfer, taskID); |
7905 | m_log.WarnFormat( | ||
7906 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but prim does not exist", | ||
7907 | Name, requestID, itemID, taskID); | ||
7908 | return true; | ||
7909 | } | ||
7910 | 8180 | ||
7911 | TaskInventoryItem tii = part.Inventory.GetInventoryItem(itemID); | 8181 | return true; |
7912 | if (tii == null) | 8182 | } |
7913 | { | ||
7914 | m_log.WarnFormat( | ||
7915 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item does not exist", | ||
7916 | Name, requestID, itemID, taskID); | ||
7917 | return true; | ||
7918 | } | ||
7919 | 8183 | ||
7920 | if (tii.Type == (int)AssetType.LSLText) | 8184 | private void HandleSimInventoryTransferRequestWithPermsCheck(IClientAPI sender, TransferRequestPacket transfer) |
7921 | { | 8185 | { |
7922 | if (!((Scene)m_scene).Permissions.CanEditScript(itemID, taskID, AgentId)) | 8186 | UUID taskID = new UUID(transfer.TransferInfo.Params, 48); |
7923 | return true; | 8187 | UUID itemID = new UUID(transfer.TransferInfo.Params, 64); |
7924 | } | 8188 | UUID requestID = new UUID(transfer.TransferInfo.Params, 80); |
7925 | else if (tii.Type == (int)AssetType.Notecard) | ||
7926 | { | ||
7927 | if (!((Scene)m_scene).Permissions.CanEditNotecard(itemID, taskID, AgentId)) | ||
7928 | return true; | ||
7929 | } | ||
7930 | else | ||
7931 | { | ||
7932 | // TODO: Change this code to allow items other than notecards and scripts to be successfully | ||
7933 | // shared with group. In fact, this whole block of permissions checking should move to an IPermissionsModule | ||
7934 | if (part.OwnerID != AgentId) | ||
7935 | { | ||
7936 | m_log.WarnFormat( | ||
7937 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the prim is owned by {4}", | ||
7938 | Name, requestID, itemID, taskID, part.OwnerID); | ||
7939 | return true; | ||
7940 | } | ||
7941 | 8189 | ||
7942 | if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0) | 8190 | //m_log.DebugFormat( |
7943 | { | 8191 | // "[CLIENT]: Got request for asset {0} from item {1} in prim {2} by {3}", |
7944 | m_log.WarnFormat( | 8192 | // requestID, itemID, taskID, Name); |
7945 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but modify permissions are not set", | ||
7946 | Name, requestID, itemID, taskID); | ||
7947 | return true; | ||
7948 | } | ||
7949 | 8193 | ||
7950 | if (tii.OwnerID != AgentId) | 8194 | //m_log.Debug("Transfer Request: " + transfer.ToString()); |
7951 | { | 8195 | // Validate inventory transfers |
7952 | m_log.WarnFormat( | 8196 | // Has to be done here, because AssetCache can't do it |
7953 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the item is owned by {4}", | 8197 | // |
7954 | Name, requestID, itemID, taskID, tii.OwnerID); | 8198 | if (taskID != UUID.Zero) // Prim |
7955 | return true; | 8199 | { |
7956 | } | 8200 | SceneObjectPart part = ((Scene)m_scene).GetSceneObjectPart(taskID); |
7957 | 8201 | ||
7958 | if (( | 8202 | if (part == null) |
7959 | tii.CurrentPermissions & ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) | 8203 | { |
7960 | != ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) | 8204 | m_log.WarnFormat( |
7961 | { | 8205 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but prim does not exist", |
7962 | m_log.WarnFormat( | 8206 | Name, requestID, itemID, taskID); |
7963 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item permissions are not modify/copy/transfer", | 8207 | return; |
7964 | Name, requestID, itemID, taskID); | 8208 | } |
7965 | return true; | ||
7966 | } | ||
7967 | 8209 | ||
7968 | if (tii.AssetID != requestID) | 8210 | TaskInventoryItem tii = part.Inventory.GetInventoryItem(itemID); |
7969 | { | 8211 | if (tii == null) |
7970 | m_log.WarnFormat( | 8212 | { |
7971 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but this does not match item's asset {4}", | 8213 | m_log.WarnFormat( |
7972 | Name, requestID, itemID, taskID, tii.AssetID); | 8214 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item does not exist", |
7973 | return true; | 8215 | Name, requestID, itemID, taskID); |
7974 | } | 8216 | return; |
7975 | } | 8217 | } |
8218 | |||
8219 | if (tii.Type == (int)AssetType.LSLText) | ||
8220 | { | ||
8221 | if (!((Scene)m_scene).Permissions.CanEditScript(itemID, taskID, AgentId)) | ||
8222 | return; | ||
8223 | } | ||
8224 | else if (tii.Type == (int)AssetType.Notecard) | ||
8225 | { | ||
8226 | if (!((Scene)m_scene).Permissions.CanEditNotecard(itemID, taskID, AgentId)) | ||
8227 | return; | ||
8228 | } | ||
8229 | else | ||
8230 | { | ||
8231 | // TODO: Change this code to allow items other than notecards and scripts to be successfully | ||
8232 | // shared with group. In fact, this whole block of permissions checking should move to an IPermissionsModule | ||
8233 | if (part.OwnerID != AgentId) | ||
8234 | { | ||
8235 | m_log.WarnFormat( | ||
8236 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the prim is owned by {4}", | ||
8237 | Name, requestID, itemID, taskID, part.OwnerID); | ||
8238 | return; | ||
7976 | } | 8239 | } |
7977 | else // Agent | 8240 | |
8241 | if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0) | ||
7978 | { | 8242 | { |
7979 | IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>(); | 8243 | m_log.WarnFormat( |
7980 | if (invAccess != null) | 8244 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but modify permissions are not set", |
7981 | { | 8245 | Name, requestID, itemID, taskID); |
7982 | if (!invAccess.CanGetAgentInventoryItem(this, itemID, requestID)) | 8246 | return; |
7983 | return false; | 8247 | } |
7984 | } | 8248 | |
7985 | else | 8249 | if (tii.OwnerID != AgentId) |
7986 | { | 8250 | { |
7987 | return false; | 8251 | m_log.WarnFormat( |
7988 | } | 8252 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the item is owned by {4}", |
8253 | Name, requestID, itemID, taskID, tii.OwnerID); | ||
8254 | return; | ||
8255 | } | ||
8256 | |||
8257 | if (( | ||
8258 | tii.CurrentPermissions & ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) | ||
8259 | != ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) | ||
8260 | { | ||
8261 | m_log.WarnFormat( | ||
8262 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item permissions are not modify/copy/transfer", | ||
8263 | Name, requestID, itemID, taskID); | ||
8264 | return; | ||
8265 | } | ||
8266 | |||
8267 | if (tii.AssetID != requestID) | ||
8268 | { | ||
8269 | m_log.WarnFormat( | ||
8270 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but this does not match item's asset {4}", | ||
8271 | Name, requestID, itemID, taskID, tii.AssetID); | ||
8272 | return; | ||
7989 | } | 8273 | } |
7990 | } | 8274 | } |
7991 | } | 8275 | } |
7992 | else | 8276 | else // Agent |
7993 | if (transfer.TransferInfo.SourceType == (int)SourceType.SimEstate) | 8277 | { |
8278 | IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>(); | ||
8279 | if (invAccess != null) | ||
7994 | { | 8280 | { |
7995 | //TransferRequestPacket does not include covenant uuid? | 8281 | if (!invAccess.CanGetAgentInventoryItem(this, itemID, requestID)) |
7996 | //get scene covenant uuid | 8282 | return; |
7997 | taskID = m_scene.RegionInfo.RegionSettings.Covenant; | ||
7998 | } | 8283 | } |
8284 | else | ||
8285 | { | ||
8286 | return; | ||
8287 | } | ||
8288 | } | ||
7999 | 8289 | ||
8290 | // Permissions out of the way, let's request the asset | ||
8000 | MakeAssetRequest(transfer, taskID); | 8291 | MakeAssetRequest(transfer, taskID); |
8001 | 8292 | ||
8002 | return true; | ||
8003 | } | 8293 | } |
8004 | 8294 | ||
8295 | |||
8005 | private bool HandleAssetUploadRequest(IClientAPI sender, Packet Pack) | 8296 | private bool HandleAssetUploadRequest(IClientAPI sender, Packet Pack) |
8006 | { | 8297 | { |
8007 | AssetUploadRequestPacket request = (AssetUploadRequestPacket)Pack; | 8298 | AssetUploadRequestPacket request = (AssetUploadRequestPacket)Pack; |
@@ -11732,8 +12023,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11732 | } | 12023 | } |
11733 | 12024 | ||
11734 | /// <summary> | 12025 | /// <summary> |
11735 | /// Send a response back to a client when it asks the asset server (via the region server) if it has | ||
11736 | /// its appearance texture cached. | ||
11737 | /// </summary> | 12026 | /// </summary> |
11738 | /// <remarks> | 12027 | /// <remarks> |
11739 | /// At the moment, we always reply that there is no cached texture. | 12028 | /// At the moment, we always reply that there is no cached texture. |
@@ -11741,6 +12030,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11741 | /// <param name="simclient"></param> | 12030 | /// <param name="simclient"></param> |
11742 | /// <param name="packet"></param> | 12031 | /// <param name="packet"></param> |
11743 | /// <returns></returns> | 12032 | /// <returns></returns> |
12033 | // TODO: Convert old handler to use new method | ||
12034 | /*protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet) | ||
12035 | { | ||
12036 | AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet; | ||
12037 | |||
12038 | if (cachedtex.AgentData.SessionID != SessionId) | ||
12039 | return false; | ||
12040 | |||
12041 | |||
12042 | List<CachedTextureRequestArg> requestArgs = new List<CachedTextureRequestArg>(); | ||
12043 | |||
12044 | for (int i = 0; i < cachedtex.WearableData.Length; i++) | ||
12045 | { | ||
12046 | CachedTextureRequestArg arg = new CachedTextureRequestArg(); | ||
12047 | arg.BakedTextureIndex = cachedtex.WearableData[i].TextureIndex; | ||
12048 | arg.WearableHashID = cachedtex.WearableData[i].ID; | ||
12049 | |||
12050 | requestArgs.Add(arg); | ||
12051 | } | ||
12052 | |||
12053 | CachedTextureRequest handlerCachedTextureRequest = OnCachedTextureRequest; | ||
12054 | if (handlerCachedTextureRequest != null) | ||
12055 | { | ||
12056 | handlerCachedTextureRequest(simclient,cachedtex.AgentData.SerialNum,requestArgs); | ||
12057 | } | ||
12058 | |||
12059 | return true; | ||
12060 | }*/ | ||
12061 | |||
11744 | protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet) | 12062 | protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet) |
11745 | { | 12063 | { |
11746 | //m_log.Debug("texture cached: " + packet.ToString()); | 12064 | //m_log.Debug("texture cached: " + packet.ToString()); |
@@ -11749,156 +12067,105 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11749 | 12067 | ||
11750 | if (cachedtex.AgentData.SessionID != SessionId) | 12068 | if (cachedtex.AgentData.SessionID != SessionId) |
11751 | return false; | 12069 | return false; |
11752 | |||
11753 | 12070 | ||
11754 | // TODO: don't create new blocks if recycling an old packet | 12071 | // TODO: don't create new blocks if recycling an old packet |
11755 | cachedresp.AgentData.AgentID = AgentId; | 12072 | cachedresp.AgentData.AgentID = AgentId; |
11756 | cachedresp.AgentData.SessionID = m_sessionId; | 12073 | cachedresp.AgentData.SessionID = m_sessionId; |
11757 | cachedresp.AgentData.SerialNum = m_cachedTextureSerial; | 12074 | cachedresp.AgentData.SerialNum = cachedtex.AgentData.SerialNum; |
11758 | m_cachedTextureSerial++; | ||
11759 | cachedresp.WearableData = | 12075 | cachedresp.WearableData = |
11760 | new AgentCachedTextureResponsePacket.WearableDataBlock[cachedtex.WearableData.Length]; | 12076 | new AgentCachedTextureResponsePacket.WearableDataBlock[cachedtex.WearableData.Length]; |
11761 | 12077 | ||
11762 | //IAvatarFactoryModule fac = m_scene.RequestModuleInterface<IAvatarFactoryModule>(); | ||
11763 | // var item = fac.GetBakedTextureFaces(AgentId); | ||
11764 | //WearableCacheItem[] items = fac.GetCachedItems(AgentId); | ||
11765 | |||
11766 | IAssetService cache = m_scene.AssetService; | ||
11767 | IBakedTextureModule bakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>(); | ||
11768 | //bakedTextureModule = null; | ||
11769 | int maxWearablesLoop = cachedtex.WearableData.Length; | 12078 | int maxWearablesLoop = cachedtex.WearableData.Length; |
11770 | if (maxWearablesLoop > AvatarWearable.MAX_WEARABLES) | 12079 | if (maxWearablesLoop > AvatarWearable.MAX_WEARABLES) |
11771 | maxWearablesLoop = AvatarWearable.MAX_WEARABLES; | 12080 | maxWearablesLoop = AvatarWearable.MAX_WEARABLES; |
11772 | 12081 | ||
11773 | if (bakedTextureModule != null && cache != null) | 12082 | int cacheHits = 0; |
11774 | { | ||
11775 | // We need to make sure the asset stored in the bake is available on this server also by it's assetid before we map it to a Cacheid | ||
11776 | 12083 | ||
11777 | WearableCacheItem[] cacheItems = null; | 12084 | // We need to make sure the asset stored in the bake is available on this server also by it's assetid before we map it to a Cacheid |
11778 | ScenePresence p = m_scene.GetScenePresence(AgentId); | ||
11779 | if (p.Appearance != null) | ||
11780 | if (p.Appearance.WearableCacheItems == null || p.Appearance.WearableCacheItemsDirty) | ||
11781 | { | ||
11782 | try | ||
11783 | { | ||
11784 | cacheItems = bakedTextureModule.Get(AgentId); | ||
11785 | p.Appearance.WearableCacheItems = cacheItems; | ||
11786 | p.Appearance.WearableCacheItemsDirty = false; | ||
11787 | } | ||
11788 | 12085 | ||
11789 | /* | 12086 | WearableCacheItem[] cacheItems = null; |
11790 | * The following Catch types DO NOT WORK, it jumps to the General Packet Exception Handler if you don't catch Exception! | ||
11791 | * | ||
11792 | catch (System.Net.Sockets.SocketException) | ||
11793 | { | ||
11794 | cacheItems = null; | ||
11795 | } | ||
11796 | catch (WebException) | ||
11797 | { | ||
11798 | cacheItems = null; | ||
11799 | } | ||
11800 | catch (InvalidOperationException) | ||
11801 | { | ||
11802 | cacheItems = null; | ||
11803 | } */ | ||
11804 | catch (Exception) | ||
11805 | { | ||
11806 | cacheItems = null; | ||
11807 | } | ||
11808 | |||
11809 | } | ||
11810 | else if (p.Appearance.WearableCacheItems != null) | ||
11811 | { | ||
11812 | cacheItems = p.Appearance.WearableCacheItems; | ||
11813 | } | ||
11814 | 12087 | ||
11815 | if (cache != null && cacheItems != null) | 12088 | ScenePresence p = m_scene.GetScenePresence(AgentId); |
11816 | { | ||
11817 | foreach (WearableCacheItem item in cacheItems) | ||
11818 | { | ||
11819 | |||
11820 | if (cache.GetCached(item.TextureID.ToString()) == null) | ||
11821 | { | ||
11822 | item.TextureAsset.Temporary = true; | ||
11823 | cache.Store(item.TextureAsset); | ||
11824 | } | ||
11825 | 12089 | ||
12090 | if (p != null && p.Appearance != null) | ||
12091 | { | ||
12092 | cacheItems = p.Appearance.WearableCacheItems; | ||
12093 | } | ||
11826 | 12094 | ||
11827 | } | 12095 | if (cacheItems != null) |
11828 | } | 12096 | { |
11829 | 12097 | for (int i = 0; i < maxWearablesLoop; i++) | |
11830 | if (cacheItems != null) | ||
11831 | { | 12098 | { |
11832 | 12099 | int idx = cachedtex.WearableData[i].TextureIndex; | |
11833 | for (int i = 0; i < maxWearablesLoop; i++) | ||
11834 | { | ||
11835 | WearableCacheItem item = | ||
11836 | WearableCacheItem.SearchTextureIndex(cachedtex.WearableData[i].TextureIndex,cacheItems); | ||
11837 | 12100 | ||
11838 | cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); | 12101 | cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); |
11839 | cachedresp.WearableData[i].TextureIndex= cachedtex.WearableData[i].TextureIndex; | 12102 | cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex; |
11840 | cachedresp.WearableData[i].HostName = new byte[0]; | 12103 | cachedresp.WearableData[i].HostName = new byte[0]; |
11841 | if (item != null && cachedtex.WearableData[i].ID == item.CacheId) | 12104 | if (cachedtex.WearableData[i].ID == cacheItems[idx].CacheId) |
11842 | { | 12105 | { |
11843 | 12106 | cachedresp.WearableData[i].TextureID = cacheItems[idx].TextureID; | |
11844 | cachedresp.WearableData[i].TextureID = item.TextureID; | 12107 | cacheHits++; |
11845 | } | ||
11846 | else | ||
11847 | { | ||
11848 | cachedresp.WearableData[i].TextureID = UUID.Zero; | ||
11849 | } | ||
11850 | } | 12108 | } |
11851 | } | 12109 | else |
11852 | else | ||
11853 | { | ||
11854 | for (int i = 0; i < maxWearablesLoop; i++) | ||
11855 | { | 12110 | { |
11856 | cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); | ||
11857 | cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex; | ||
11858 | cachedresp.WearableData[i].TextureID = UUID.Zero; | 12111 | cachedresp.WearableData[i].TextureID = UUID.Zero; |
11859 | //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46"); | ||
11860 | cachedresp.WearableData[i].HostName = new byte[0]; | ||
11861 | } | 12112 | } |
11862 | } | 12113 | } |
11863 | } | 12114 | } |
11864 | else | 12115 | else |
11865 | { | 12116 | { |
11866 | if (cache == null) | 12117 | for (int i = 0; i < maxWearablesLoop; i++) |
11867 | { | 12118 | { |
11868 | for (int i = 0; i < maxWearablesLoop; i++) | 12119 | cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); |
11869 | { | 12120 | cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex; |
11870 | cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); | 12121 | cachedresp.WearableData[i].TextureID = UUID.Zero; |
11871 | cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex; | 12122 | //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46"); |
11872 | cachedresp.WearableData[i].TextureID = UUID.Zero; | 12123 | cachedresp.WearableData[i].HostName = new byte[0]; |
11873 | //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46"); | ||
11874 | cachedresp.WearableData[i].HostName = new byte[0]; | ||
11875 | } | ||
11876 | } | 12124 | } |
11877 | else | 12125 | } |
11878 | { | ||
11879 | for (int i = 0; i < maxWearablesLoop; i++) | ||
11880 | { | ||
11881 | cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); | ||
11882 | cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex; | ||
11883 | |||
11884 | 12126 | ||
12127 | m_log.DebugFormat("texture cached: hits {0}", cacheHits); | ||
11885 | 12128 | ||
11886 | if (cache.GetCached(cachedresp.WearableData[i].TextureID.ToString()) == null) | ||
11887 | cachedresp.WearableData[i].TextureID = UUID.Zero; | ||
11888 | //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46"); | ||
11889 | else | ||
11890 | cachedresp.WearableData[i].TextureID = UUID.Zero; | ||
11891 | // UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46"); | ||
11892 | cachedresp.WearableData[i].HostName = new byte[0]; | ||
11893 | } | ||
11894 | } | ||
11895 | } | ||
11896 | cachedresp.Header.Zerocoded = true; | 12129 | cachedresp.Header.Zerocoded = true; |
11897 | OutPacket(cachedresp, ThrottleOutPacketType.Task); | 12130 | OutPacket(cachedresp, ThrottleOutPacketType.Task); |
11898 | 12131 | ||
11899 | return true; | 12132 | return true; |
11900 | } | 12133 | } |
11901 | 12134 | ||
12135 | /// <summary> | ||
12136 | /// Send a response back to a client when it asks the asset server (via the region server) if it has | ||
12137 | /// its appearance texture cached. | ||
12138 | /// </summary> | ||
12139 | /// <param name="avatar"></param> | ||
12140 | /// <param name="serial"></param> | ||
12141 | /// <param name="cachedTextures"></param> | ||
12142 | /// <returns></returns> | ||
12143 | public void SendCachedTextureResponse(ISceneEntity avatar, int serial, List<CachedTextureResponseArg> cachedTextures) | ||
12144 | { | ||
12145 | ScenePresence presence = avatar as ScenePresence; | ||
12146 | if (presence == null) | ||
12147 | return; | ||
12148 | |||
12149 | AgentCachedTextureResponsePacket cachedresp = (AgentCachedTextureResponsePacket)PacketPool.Instance.GetPacket(PacketType.AgentCachedTextureResponse); | ||
12150 | |||
12151 | // TODO: don't create new blocks if recycling an old packet | ||
12152 | cachedresp.AgentData.AgentID = m_agentId; | ||
12153 | cachedresp.AgentData.SessionID = m_sessionId; | ||
12154 | cachedresp.AgentData.SerialNum = serial; | ||
12155 | cachedresp.WearableData = new AgentCachedTextureResponsePacket.WearableDataBlock[cachedTextures.Count]; | ||
12156 | |||
12157 | for (int i = 0; i < cachedTextures.Count; i++) | ||
12158 | { | ||
12159 | cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); | ||
12160 | cachedresp.WearableData[i].TextureIndex = (byte)cachedTextures[i].BakedTextureIndex; | ||
12161 | cachedresp.WearableData[i].TextureID = cachedTextures[i].BakedTextureID; | ||
12162 | cachedresp.WearableData[i].HostName = new byte[0]; | ||
12163 | } | ||
12164 | |||
12165 | cachedresp.Header.Zerocoded = true; | ||
12166 | OutPacket(cachedresp, ThrottleOutPacketType.Task); | ||
12167 | } | ||
12168 | |||
11902 | protected bool HandleMultipleObjUpdate(IClientAPI simClient, Packet packet) | 12169 | protected bool HandleMultipleObjUpdate(IClientAPI simClient, Packet packet) |
11903 | { | 12170 | { |
11904 | MultipleObjectUpdatePacket multipleupdate = (MultipleObjectUpdatePacket)packet; | 12171 | MultipleObjectUpdatePacket multipleupdate = (MultipleObjectUpdatePacket)packet; |
@@ -11924,8 +12191,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11924 | if (part == null) | 12191 | if (part == null) |
11925 | { | 12192 | { |
11926 | // It's a ghost! tell the client to delete it from view. | 12193 | // It's a ghost! tell the client to delete it from view. |
11927 | simClient.SendKillObject(Scene.RegionInfo.RegionHandle, | 12194 | simClient.SendKillObject(new List<uint> { localId }); |
11928 | new List<uint> { localId }); | ||
11929 | } | 12195 | } |
11930 | else | 12196 | else |
11931 | { | 12197 | { |
@@ -12299,6 +12565,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
12299 | 12565 | ||
12300 | shape.PCode = addPacket.ObjectData.PCode; | 12566 | shape.PCode = addPacket.ObjectData.PCode; |
12301 | shape.State = addPacket.ObjectData.State; | 12567 | shape.State = addPacket.ObjectData.State; |
12568 | shape.LastAttachPoint = addPacket.ObjectData.State; | ||
12302 | shape.PathBegin = addPacket.ObjectData.PathBegin; | 12569 | shape.PathBegin = addPacket.ObjectData.PathBegin; |
12303 | shape.PathEnd = addPacket.ObjectData.PathEnd; | 12570 | shape.PathEnd = addPacket.ObjectData.PathEnd; |
12304 | shape.PathScaleX = addPacket.ObjectData.PathScaleX; | 12571 | shape.PathScaleX = addPacket.ObjectData.PathScaleX; |
@@ -12329,7 +12596,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
12329 | ClientInfo info = m_udpClient.GetClientInfo(); | 12596 | ClientInfo info = m_udpClient.GetClientInfo(); |
12330 | 12597 | ||
12331 | info.proxyEP = null; | 12598 | info.proxyEP = null; |
12332 | info.agentcircuit = RequestClientInfo(); | 12599 | if (info.agentcircuit == null) |
12600 | info.agentcircuit = RequestClientInfo(); | ||
12333 | 12601 | ||
12334 | return info; | 12602 | return info; |
12335 | } | 12603 | } |
@@ -12712,11 +12980,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
12712 | OutPacket(dialog, ThrottleOutPacketType.Task); | 12980 | OutPacket(dialog, ThrottleOutPacketType.Task); |
12713 | } | 12981 | } |
12714 | 12982 | ||
12715 | public void StopFlying(ISceneEntity p) | 12983 | public void SendAgentTerseUpdate(ISceneEntity p) |
12716 | { | 12984 | { |
12717 | if (p is ScenePresence) | 12985 | if (p is ScenePresence) |
12718 | { | 12986 | { |
12719 | ScenePresence presence = p as ScenePresence; | 12987 | // m_log.DebugFormat( |
12988 | // "[LLCLIENTVIEW]: Immediately sending terse agent update for {0} to {1} in {2}", | ||
12989 | // p.Name, Name, Scene.Name); | ||
12990 | |||
12720 | // It turns out to get the agent to stop flying, you have to feed it stop flying velocities | 12991 | // It turns out to get the agent to stop flying, you have to feed it stop flying velocities |
12721 | // There's no explicit message to send the client to tell it to stop flying.. it relies on the | 12992 | // There's no explicit message to send the client to tell it to stop flying.. it relies on the |
12722 | // velocity, collision plane and avatar height | 12993 | // velocity, collision plane and avatar height |
@@ -12724,34 +12995,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
12724 | // Add 1/6 the avatar's height to it's position so it doesn't shoot into the air | 12995 | // Add 1/6 the avatar's height to it's position so it doesn't shoot into the air |
12725 | // when the avatar stands up | 12996 | // when the avatar stands up |
12726 | 12997 | ||
12727 | Vector3 pos = presence.AbsolutePosition; | ||
12728 | |||
12729 | if (presence.Appearance.AvatarHeight != 127.0f) | ||
12730 | pos += new Vector3(0f, 0f, (presence.Appearance.AvatarHeight/6f)); | ||
12731 | else | ||
12732 | pos += new Vector3(0f, 0f, (1.56f/6f)); | ||
12733 | |||
12734 | presence.AbsolutePosition = pos; | ||
12735 | |||
12736 | // attach a suitable collision plane regardless of the actual situation to force the LLClient to land. | ||
12737 | // Collision plane below the avatar's position a 6th of the avatar's height is suitable. | ||
12738 | // Mind you, that this method doesn't get called if the avatar's velocity magnitude is greater then a | ||
12739 | // certain amount.. because the LLClient wouldn't land in that situation anyway. | ||
12740 | |||
12741 | // why are we still testing for this really old height value default??? | ||
12742 | if (presence.Appearance.AvatarHeight != 127.0f) | ||
12743 | presence.CollisionPlane = new Vector4(0, 0, 0, pos.Z - presence.Appearance.AvatarHeight/6f); | ||
12744 | else | ||
12745 | presence.CollisionPlane = new Vector4(0, 0, 0, pos.Z - (1.56f/6f)); | ||
12746 | |||
12747 | |||
12748 | ImprovedTerseObjectUpdatePacket.ObjectDataBlock block = | 12998 | ImprovedTerseObjectUpdatePacket.ObjectDataBlock block = |
12749 | CreateImprovedTerseBlock(p, false); | 12999 | CreateImprovedTerseBlock(p, false); |
12750 | 13000 | ||
12751 | const float TIME_DILATION = 1.0f; | 13001 | const float TIME_DILATION = 1.0f; |
12752 | ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f); | 13002 | ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f); |
12753 | 13003 | ||
12754 | |||
12755 | ImprovedTerseObjectUpdatePacket packet | 13004 | ImprovedTerseObjectUpdatePacket packet |
12756 | = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket( | 13005 | = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket( |
12757 | PacketType.ImprovedTerseObjectUpdate); | 13006 | PacketType.ImprovedTerseObjectUpdate); |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs index 073c357..41dd4d1 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs | |||
@@ -206,6 +206,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
206 | } | 206 | } |
207 | } | 207 | } |
208 | 208 | ||
209 | public bool HasUpdates() | ||
210 | { | ||
211 | J2KImage image = GetHighestPriorityImage(); | ||
212 | |||
213 | return image != null && image.IsDecoded; | ||
214 | } | ||
215 | |||
209 | public bool ProcessImageQueue(int packetsToSend) | 216 | public bool ProcessImageQueue(int packetsToSend) |
210 | { | 217 | { |
211 | int packetsSent = 0; | 218 | int packetsSent = 0; |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs index e52ac37..fe31bd9 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs | |||
@@ -31,6 +31,7 @@ using System.Net; | |||
31 | using System.Threading; | 31 | using System.Threading; |
32 | using log4net; | 32 | using log4net; |
33 | using OpenSim.Framework; | 33 | using OpenSim.Framework; |
34 | using OpenSim.Framework.Monitoring; | ||
34 | using OpenMetaverse; | 35 | using OpenMetaverse; |
35 | using OpenMetaverse.Packets; | 36 | using OpenMetaverse.Packets; |
36 | 37 | ||
@@ -81,6 +82,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
81 | /// hooked to put more data on the empty queue</summary> | 82 | /// hooked to put more data on the empty queue</summary> |
82 | public event QueueEmpty OnQueueEmpty; | 83 | public event QueueEmpty OnQueueEmpty; |
83 | 84 | ||
85 | public event Func<ThrottleOutPacketTypeFlags, bool> HasUpdates; | ||
86 | |||
84 | /// <summary>AgentID for this client</summary> | 87 | /// <summary>AgentID for this client</summary> |
85 | public readonly UUID AgentID; | 88 | public readonly UUID AgentID; |
86 | /// <summary>The remote address of the connected client</summary> | 89 | /// <summary>The remote address of the connected client</summary> |
@@ -160,6 +163,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
160 | private int m_maxRTO = 60000; | 163 | private int m_maxRTO = 60000; |
161 | public bool m_deliverPackets = true; | 164 | public bool m_deliverPackets = true; |
162 | 165 | ||
166 | public int m_lastStartpingTimeMS; | ||
167 | public int m_pingMS; | ||
168 | |||
169 | public int PingTimeMS | ||
170 | { | ||
171 | get | ||
172 | { | ||
173 | if (m_pingMS < 10) | ||
174 | return 10; | ||
175 | if(m_pingMS > 2000) | ||
176 | return 2000; | ||
177 | return m_pingMS; | ||
178 | } | ||
179 | } | ||
180 | |||
181 | /// <summary> | ||
182 | /// This is the percentage of the udp texture queue to add to the task queue since | ||
183 | /// textures are now generally handled through http. | ||
184 | /// </summary> | ||
185 | private double m_cannibalrate = 0.0; | ||
186 | |||
187 | private ClientInfo m_info = new ClientInfo(); | ||
188 | |||
163 | /// <summary> | 189 | /// <summary> |
164 | /// Default constructor | 190 | /// Default constructor |
165 | /// </summary> | 191 | /// </summary> |
@@ -197,6 +223,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
197 | // Create an array of token buckets for this clients different throttle categories | 223 | // Create an array of token buckets for this clients different throttle categories |
198 | m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; | 224 | m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; |
199 | 225 | ||
226 | m_cannibalrate = rates.CannibalizeTextureRate; | ||
227 | |||
200 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) | 228 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) |
201 | { | 229 | { |
202 | ThrottleOutPacketType type = (ThrottleOutPacketType)i; | 230 | ThrottleOutPacketType type = (ThrottleOutPacketType)i; |
@@ -212,6 +240,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
212 | 240 | ||
213 | // Initialize this to a sane value to prevent early disconnects | 241 | // Initialize this to a sane value to prevent early disconnects |
214 | TickLastPacketReceived = Environment.TickCount & Int32.MaxValue; | 242 | TickLastPacketReceived = Environment.TickCount & Int32.MaxValue; |
243 | m_pingMS = (int)(3.0 * server.TickCountResolution); // so filter doesnt start at 0; | ||
215 | } | 244 | } |
216 | 245 | ||
217 | /// <summary> | 246 | /// <summary> |
@@ -241,20 +270,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
241 | // TODO: This data structure is wrong in so many ways. Locking and copying the entire lists | 270 | // TODO: This data structure is wrong in so many ways. Locking and copying the entire lists |
242 | // of pending and needed ACKs for every client every time some method wants information about | 271 | // of pending and needed ACKs for every client every time some method wants information about |
243 | // this connection is a recipe for poor performance | 272 | // this connection is a recipe for poor performance |
244 | ClientInfo info = new ClientInfo(); | 273 | |
245 | info.pendingAcks = new Dictionary<uint, uint>(); | 274 | m_info.resendThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate; |
246 | info.needAck = new Dictionary<uint, byte[]>(); | 275 | m_info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; |
247 | 276 | m_info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; | |
248 | info.resendThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate; | 277 | m_info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; |
249 | info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; | 278 | m_info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; |
250 | info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; | 279 | m_info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; |
251 | info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; | 280 | m_info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; |
252 | info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; | 281 | m_info.totalThrottle = (int)m_throttleCategory.DripRate; |
253 | info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; | 282 | |
254 | info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; | 283 | return m_info; |
255 | info.totalThrottle = (int)m_throttleCategory.DripRate; | ||
256 | |||
257 | return info; | ||
258 | } | 284 | } |
259 | 285 | ||
260 | /// <summary> | 286 | /// <summary> |
@@ -348,6 +374,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
348 | texture = Math.Max(texture, LLUDPServer.MTU); | 374 | texture = Math.Max(texture, LLUDPServer.MTU); |
349 | asset = Math.Max(asset, LLUDPServer.MTU); | 375 | asset = Math.Max(asset, LLUDPServer.MTU); |
350 | 376 | ||
377 | // Since most textures are now delivered through http, make it possible | ||
378 | // to cannibalize some of the bw from the texture throttle to use for | ||
379 | // the task queue (e.g. object updates) | ||
380 | task = task + (int)(m_cannibalrate * texture); | ||
381 | texture = (int)((1 - m_cannibalrate) * texture); | ||
382 | |||
351 | //int total = resend + land + wind + cloud + task + texture + asset; | 383 | //int total = resend + land + wind + cloud + task + texture + asset; |
352 | //m_log.DebugFormat("[LLUDPCLIENT]: {0} is setting throttles. Resend={1}, Land={2}, Wind={3}, Cloud={4}, Task={5}, Texture={6}, Asset={7}, Total={8}", | 384 | //m_log.DebugFormat("[LLUDPCLIENT]: {0} is setting throttles. Resend={1}, Land={2}, Wind={3}, Cloud={4}, Task={5}, Texture={6}, Asset={7}, Total={8}", |
353 | // AgentID, resend, land, wind, cloud, task, texture, asset, total); | 385 | // AgentID, resend, land, wind, cloud, task, texture, asset, total); |
@@ -646,15 +678,38 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
646 | /// <param name="categories">Throttle categories to fire the callback for</param> | 678 | /// <param name="categories">Throttle categories to fire the callback for</param> |
647 | private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories) | 679 | private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories) |
648 | { | 680 | { |
649 | if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty) | 681 | // if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty) |
682 | if (!m_isQueueEmptyRunning && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty) | ||
650 | { | 683 | { |
684 | m_isQueueEmptyRunning = true; | ||
685 | |||
686 | int start = Environment.TickCount & Int32.MaxValue; | ||
687 | const int MIN_CALLBACK_MS = 30; | ||
688 | |||
689 | m_nextOnQueueEmpty = start + MIN_CALLBACK_MS; | ||
690 | if (m_nextOnQueueEmpty == 0) | ||
691 | m_nextOnQueueEmpty = 1; | ||
692 | |||
651 | // Use a value of 0 to signal that FireQueueEmpty is running | 693 | // Use a value of 0 to signal that FireQueueEmpty is running |
652 | m_nextOnQueueEmpty = 0; | 694 | // m_nextOnQueueEmpty = 0; |
653 | // Asynchronously run the callback | 695 | |
654 | Util.FireAndForget(FireQueueEmpty, categories); | 696 | m_categories = categories; |
697 | |||
698 | if (HasUpdates(m_categories)) | ||
699 | { | ||
700 | // Asynchronously run the callback | ||
701 | Util.FireAndForget(FireQueueEmpty, categories); | ||
702 | } | ||
703 | else | ||
704 | { | ||
705 | m_isQueueEmptyRunning = false; | ||
706 | } | ||
655 | } | 707 | } |
656 | } | 708 | } |
657 | 709 | ||
710 | private bool m_isQueueEmptyRunning; | ||
711 | private ThrottleOutPacketTypeFlags m_categories = 0; | ||
712 | |||
658 | /// <summary> | 713 | /// <summary> |
659 | /// Fires the OnQueueEmpty callback and sets the minimum time that it | 714 | /// Fires the OnQueueEmpty callback and sets the minimum time that it |
660 | /// can be called again | 715 | /// can be called again |
@@ -664,22 +719,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
664 | /// signature</param> | 719 | /// signature</param> |
665 | private void FireQueueEmpty(object o) | 720 | private void FireQueueEmpty(object o) |
666 | { | 721 | { |
667 | const int MIN_CALLBACK_MS = 30; | 722 | // int start = Environment.TickCount & Int32.MaxValue; |
723 | // const int MIN_CALLBACK_MS = 30; | ||
668 | 724 | ||
669 | ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o; | 725 | // if (m_udpServer.IsRunningOutbound) |
670 | QueueEmpty callback = OnQueueEmpty; | 726 | // { |
671 | 727 | ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o; | |
672 | int start = Environment.TickCount & Int32.MaxValue; | 728 | QueueEmpty callback = OnQueueEmpty; |
673 | 729 | ||
674 | if (callback != null) | 730 | if (callback != null) |
675 | { | 731 | { |
676 | try { callback(categories); } | 732 | // if (m_udpServer.IsRunningOutbound) |
677 | catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); } | 733 | // { |
678 | } | 734 | try { callback(categories); } |
735 | catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); } | ||
736 | // } | ||
737 | } | ||
738 | // } | ||
739 | |||
740 | // m_nextOnQueueEmpty = start + MIN_CALLBACK_MS; | ||
741 | // if (m_nextOnQueueEmpty == 0) | ||
742 | // m_nextOnQueueEmpty = 1; | ||
743 | |||
744 | // } | ||
679 | 745 | ||
680 | m_nextOnQueueEmpty = start + MIN_CALLBACK_MS; | 746 | m_isQueueEmptyRunning = false; |
681 | if (m_nextOnQueueEmpty == 0) | ||
682 | m_nextOnQueueEmpty = 1; | ||
683 | } | 747 | } |
684 | internal void ForceThrottleSetting(int throttle, int setting) | 748 | internal void ForceThrottleSetting(int throttle, int setting) |
685 | { | 749 | { |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 4154ef2..3b0312d 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | |||
@@ -34,6 +34,7 @@ using System.Net.Sockets; | |||
34 | using System.Reflection; | 34 | using System.Reflection; |
35 | using System.Threading; | 35 | using System.Threading; |
36 | using log4net; | 36 | using log4net; |
37 | using NDesk.Options; | ||
37 | using Nini.Config; | 38 | using Nini.Config; |
38 | using OpenMetaverse.Packets; | 39 | using OpenMetaverse.Packets; |
39 | using OpenSim.Framework; | 40 | using OpenSim.Framework; |
@@ -62,20 +63,41 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
62 | m_udpServer = new LLUDPServer(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager); | 63 | m_udpServer = new LLUDPServer(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager); |
63 | } | 64 | } |
64 | 65 | ||
65 | public void NetworkStop() | ||
66 | { | ||
67 | m_udpServer.Stop(); | ||
68 | } | ||
69 | |||
70 | public void AddScene(IScene scene) | 66 | public void AddScene(IScene scene) |
71 | { | 67 | { |
72 | m_udpServer.AddScene(scene); | 68 | m_udpServer.AddScene(scene); |
73 | 69 | ||
74 | StatsManager.RegisterStat( | 70 | StatsManager.RegisterStat( |
75 | new Stat( | 71 | new Stat( |
72 | "ClientLogoutsDueToNoReceives", | ||
73 | "Number of times a client has been logged out because no packets were received before the timeout.", | ||
74 | "", | ||
75 | "", | ||
76 | "clientstack", | ||
77 | scene.Name, | ||
78 | StatType.Pull, | ||
79 | MeasuresOfInterest.None, | ||
80 | stat => stat.Value = m_udpServer.ClientLogoutsDueToNoReceives, | ||
81 | StatVerbosity.Debug)); | ||
82 | |||
83 | StatsManager.RegisterStat( | ||
84 | new Stat( | ||
85 | "IncomingUDPReceivesCount", | ||
86 | "Number of UDP receives performed", | ||
87 | "", | ||
88 | "", | ||
89 | "clientstack", | ||
90 | scene.Name, | ||
91 | StatType.Pull, | ||
92 | MeasuresOfInterest.AverageChangeOverTime, | ||
93 | stat => stat.Value = m_udpServer.UdpReceives, | ||
94 | StatVerbosity.Debug)); | ||
95 | |||
96 | StatsManager.RegisterStat( | ||
97 | new Stat( | ||
76 | "IncomingPacketsProcessedCount", | 98 | "IncomingPacketsProcessedCount", |
77 | "Number of inbound UDP packets processed", | 99 | "Number of inbound LL protocol packets processed", |
78 | "Number of inbound UDP packets processed", | 100 | "", |
79 | "", | 101 | "", |
80 | "clientstack", | 102 | "clientstack", |
81 | scene.Name, | 103 | scene.Name, |
@@ -83,6 +105,86 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
83 | MeasuresOfInterest.AverageChangeOverTime, | 105 | MeasuresOfInterest.AverageChangeOverTime, |
84 | stat => stat.Value = m_udpServer.IncomingPacketsProcessed, | 106 | stat => stat.Value = m_udpServer.IncomingPacketsProcessed, |
85 | StatVerbosity.Debug)); | 107 | StatVerbosity.Debug)); |
108 | |||
109 | StatsManager.RegisterStat( | ||
110 | new Stat( | ||
111 | "IncomingPacketsMalformedCount", | ||
112 | "Number of inbound UDP packets that could not be recognized as LL protocol packets.", | ||
113 | "", | ||
114 | "", | ||
115 | "clientstack", | ||
116 | scene.Name, | ||
117 | StatType.Pull, | ||
118 | MeasuresOfInterest.AverageChangeOverTime, | ||
119 | stat => stat.Value = m_udpServer.IncomingMalformedPacketCount, | ||
120 | StatVerbosity.Info)); | ||
121 | |||
122 | StatsManager.RegisterStat( | ||
123 | new Stat( | ||
124 | "IncomingPacketsOrphanedCount", | ||
125 | "Number of inbound packets that were not initial connections packets and could not be associated with a viewer.", | ||
126 | "", | ||
127 | "", | ||
128 | "clientstack", | ||
129 | scene.Name, | ||
130 | StatType.Pull, | ||
131 | MeasuresOfInterest.AverageChangeOverTime, | ||
132 | stat => stat.Value = m_udpServer.IncomingOrphanedPacketCount, | ||
133 | StatVerbosity.Info)); | ||
134 | |||
135 | StatsManager.RegisterStat( | ||
136 | new Stat( | ||
137 | "IncomingPacketsResentCount", | ||
138 | "Number of inbound packets that clients indicate are resends.", | ||
139 | "", | ||
140 | "", | ||
141 | "clientstack", | ||
142 | scene.Name, | ||
143 | StatType.Pull, | ||
144 | MeasuresOfInterest.AverageChangeOverTime, | ||
145 | stat => stat.Value = m_udpServer.IncomingPacketsResentCount, | ||
146 | StatVerbosity.Debug)); | ||
147 | |||
148 | StatsManager.RegisterStat( | ||
149 | new Stat( | ||
150 | "OutgoingUDPSendsCount", | ||
151 | "Number of UDP sends performed", | ||
152 | "", | ||
153 | "", | ||
154 | "clientstack", | ||
155 | scene.Name, | ||
156 | StatType.Pull, | ||
157 | MeasuresOfInterest.AverageChangeOverTime, | ||
158 | stat => stat.Value = m_udpServer.UdpSends, | ||
159 | StatVerbosity.Debug)); | ||
160 | |||
161 | StatsManager.RegisterStat( | ||
162 | new Stat( | ||
163 | "OutgoingPacketsResentCount", | ||
164 | "Number of packets resent because a client did not acknowledge receipt", | ||
165 | "", | ||
166 | "", | ||
167 | "clientstack", | ||
168 | scene.Name, | ||
169 | StatType.Pull, | ||
170 | MeasuresOfInterest.AverageChangeOverTime, | ||
171 | stat => stat.Value = m_udpServer.PacketsResentCount, | ||
172 | StatVerbosity.Debug)); | ||
173 | |||
174 | StatsManager.RegisterStat( | ||
175 | new Stat( | ||
176 | "AverageUDPProcessTime", | ||
177 | "Average number of milliseconds taken to process each incoming UDP packet in a sample.", | ||
178 | "This is for initial receive processing which is separate from the later client LL packet processing stage.", | ||
179 | "ms", | ||
180 | "clientstack", | ||
181 | scene.Name, | ||
182 | StatType.Pull, | ||
183 | MeasuresOfInterest.None, | ||
184 | stat => stat.Value = m_udpServer.AverageReceiveTicksForLastSamplePeriod / TimeSpan.TicksPerMillisecond, | ||
185 | // stat => | ||
186 | // stat.Value = Math.Round(m_udpServer.AverageReceiveTicksForLastSamplePeriod / TimeSpan.TicksPerMillisecond, 7), | ||
187 | StatVerbosity.Debug)); | ||
86 | } | 188 | } |
87 | 189 | ||
88 | public bool HandlesRegion(Location x) | 190 | public bool HandlesRegion(Location x) |
@@ -107,10 +209,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
107 | /// </summary> | 209 | /// </summary> |
108 | public class LLUDPServer : OpenSimUDPBase | 210 | public class LLUDPServer : OpenSimUDPBase |
109 | { | 211 | { |
212 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
213 | |||
110 | /// <summary>Maximum transmission unit, or UDP packet size, for the LLUDP protocol</summary> | 214 | /// <summary>Maximum transmission unit, or UDP packet size, for the LLUDP protocol</summary> |
111 | public const int MTU = 1400; | 215 | public const int MTU = 1400; |
112 | 216 | ||
113 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 217 | /// <summary>Number of forced client logouts due to no receipt of packets before timeout.</summary> |
218 | public int ClientLogoutsDueToNoReceives { get; private set; } | ||
219 | |||
220 | /// <summary> | ||
221 | /// Default packet debug level given to new clients | ||
222 | /// </summary> | ||
223 | public int DefaultClientPacketDebugLevel { get; set; } | ||
114 | 224 | ||
115 | /// <summary>The measured resolution of Environment.TickCount</summary> | 225 | /// <summary>The measured resolution of Environment.TickCount</summary> |
116 | public readonly float TickCountResolution; | 226 | public readonly float TickCountResolution; |
@@ -183,7 +293,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
183 | /// <summary>Flag to signal when clients should send pings</summary> | 293 | /// <summary>Flag to signal when clients should send pings</summary> |
184 | protected bool m_sendPing; | 294 | protected bool m_sendPing; |
185 | 295 | ||
296 | private int m_animationSequenceNumber; | ||
297 | |||
298 | public int NextAnimationSequenceNumber | ||
299 | { | ||
300 | get | ||
301 | { | ||
302 | m_animationSequenceNumber++; | ||
303 | if (m_animationSequenceNumber > 2147482624) | ||
304 | m_animationSequenceNumber = 1; | ||
305 | return m_animationSequenceNumber; | ||
306 | } | ||
307 | } | ||
308 | |||
309 | |||
310 | |||
186 | private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>(); | 311 | private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>(); |
312 | |||
313 | /// <summary> | ||
314 | /// Event used to signal when queued packets are available for sending. | ||
315 | /// </summary> | ||
316 | /// <remarks> | ||
317 | /// This allows the outbound loop to only operate when there is data to send rather than continuously polling. | ||
318 | /// Some data is sent immediately and not queued. That data would not trigger this event. | ||
319 | /// WRONG use. May be usefull in future revision | ||
320 | /// </remarks> | ||
321 | // private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false); | ||
322 | |||
187 | private Pool<IncomingPacket> m_incomingPacketPool; | 323 | private Pool<IncomingPacket> m_incomingPacketPool; |
188 | 324 | ||
189 | /// <summary> | 325 | /// <summary> |
@@ -204,7 +340,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
204 | 340 | ||
205 | public Socket Server { get { return null; } } | 341 | public Socket Server { get { return null; } } |
206 | 342 | ||
207 | private int m_malformedCount = 0; // Guard against a spamming attack | 343 | /// <summary> |
344 | /// Record how many packets have been resent | ||
345 | /// </summary> | ||
346 | internal int PacketsResentCount { get; set; } | ||
347 | |||
348 | /// <summary> | ||
349 | /// Record how many packets have been sent | ||
350 | /// </summary> | ||
351 | internal int PacketsSentCount { get; set; } | ||
352 | |||
353 | /// <summary> | ||
354 | /// Record how many incoming packets are indicated as resends by clients. | ||
355 | /// </summary> | ||
356 | internal int IncomingPacketsResentCount { get; set; } | ||
357 | |||
358 | /// <summary> | ||
359 | /// Record how many inbound packets could not be recognized as LLUDP packets. | ||
360 | /// </summary> | ||
361 | public int IncomingMalformedPacketCount { get; private set; } | ||
362 | |||
363 | /// <summary> | ||
364 | /// Record how many inbound packets could not be associated with a simulator circuit. | ||
365 | /// </summary> | ||
366 | public int IncomingOrphanedPacketCount { get; private set; } | ||
208 | 367 | ||
209 | /// <summary> | 368 | /// <summary> |
210 | /// Record current outgoing client for monitoring purposes. | 369 | /// Record current outgoing client for monitoring purposes. |
@@ -225,16 +384,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
225 | 384 | ||
226 | // Measure the resolution of Environment.TickCount | 385 | // Measure the resolution of Environment.TickCount |
227 | TickCountResolution = 0f; | 386 | TickCountResolution = 0f; |
228 | for (int i = 0; i < 5; i++) | 387 | for (int i = 0; i < 10; i++) |
229 | { | 388 | { |
230 | int start = Environment.TickCount; | 389 | int start = Environment.TickCount; |
231 | int now = start; | 390 | int now = start; |
232 | while (now == start) | 391 | while (now == start) |
233 | now = Environment.TickCount; | 392 | now = Environment.TickCount; |
234 | TickCountResolution += (float)(now - start) * 0.2f; | 393 | TickCountResolution += (float)(now - start) * 0.1f; |
235 | } | 394 | } |
236 | m_log.Info("[LLUDPSERVER]: Average Environment.TickCount resolution: " + TickCountResolution + "ms"); | ||
237 | TickCountResolution = (float)Math.Ceiling(TickCountResolution); | 395 | TickCountResolution = (float)Math.Ceiling(TickCountResolution); |
396 | m_log.Info("[LLUDPSERVER]: Average Environment.TickCount resolution: " + TickCountResolution + "ms"); | ||
238 | 397 | ||
239 | #endregion Environment.TickCount Measurement | 398 | #endregion Environment.TickCount Measurement |
240 | 399 | ||
@@ -242,6 +401,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
242 | int sceneThrottleBps = 0; | 401 | int sceneThrottleBps = 0; |
243 | bool usePools = false; | 402 | bool usePools = false; |
244 | 403 | ||
404 | |||
405 | |||
245 | IConfig config = configSource.Configs["ClientStack.LindenUDP"]; | 406 | IConfig config = configSource.Configs["ClientStack.LindenUDP"]; |
246 | if (config != null) | 407 | if (config != null) |
247 | { | 408 | { |
@@ -291,6 +452,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
291 | m_throttle = new TokenBucket(null, sceneThrottleBps); | 452 | m_throttle = new TokenBucket(null, sceneThrottleBps); |
292 | ThrottleRates = new ThrottleRates(configSource); | 453 | ThrottleRates = new ThrottleRates(configSource); |
293 | 454 | ||
455 | Random rnd = new Random(Util.EnvironmentTickCount()); | ||
456 | m_animationSequenceNumber = rnd.Next(11474826); | ||
457 | |||
294 | if (usePools) | 458 | if (usePools) |
295 | EnablePools(); | 459 | EnablePools(); |
296 | } | 460 | } |
@@ -461,6 +625,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
461 | m_scene = (Scene)scene; | 625 | m_scene = (Scene)scene; |
462 | m_location = new Location(m_scene.RegionInfo.RegionHandle); | 626 | m_location = new Location(m_scene.RegionInfo.RegionHandle); |
463 | 627 | ||
628 | StatsManager.RegisterStat( | ||
629 | new Stat( | ||
630 | "InboxPacketsCount", | ||
631 | "Number of LL protocol packets waiting for the second stage of processing after initial receive.", | ||
632 | "Number of LL protocol packets waiting for the second stage of processing after initial receive.", | ||
633 | "", | ||
634 | "clientstack", | ||
635 | scene.Name, | ||
636 | StatType.Pull, | ||
637 | MeasuresOfInterest.AverageChangeOverTime, | ||
638 | stat => stat.Value = packetInbox.Count, | ||
639 | StatVerbosity.Debug)); | ||
640 | |||
464 | // XXX: These stats are also pool stats but we register them separately since they are currently not | 641 | // XXX: These stats are also pool stats but we register them separately since they are currently not |
465 | // turned on and off by EnablePools()/DisablePools() | 642 | // turned on and off by EnablePools()/DisablePools() |
466 | StatsManager.RegisterStat( | 643 | StatsManager.RegisterStat( |
@@ -521,6 +698,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
521 | EnablePoolStats(); | 698 | EnablePoolStats(); |
522 | 699 | ||
523 | MainConsole.Instance.Commands.AddCommand( | 700 | MainConsole.Instance.Commands.AddCommand( |
701 | "Debug", false, "debug lludp packet", | ||
702 | "debug lludp packet [--default] <level> [<avatar-first-name> <avatar-last-name>]", | ||
703 | "Turn on packet debugging", | ||
704 | "If level > 255 then all incoming and outgoing packets are logged.\n" | ||
705 | + "If level <= 255 then incoming AgentUpdate and outgoing SimStats and SimulatorViewerTimeMessage packets are not logged.\n" | ||
706 | + "If level <= 200 then incoming RequestImage and outgoing ImagePacket, ImageData, LayerData and CoarseLocationUpdate packets are not logged.\n" | ||
707 | + "If level <= 100 then incoming ViewerEffect and AgentAnimation and outgoing ViewerEffect and AvatarAnimation packets are not logged.\n" | ||
708 | + "If level <= 50 then outgoing ImprovedTerseObjectUpdate packets are not logged.\n" | ||
709 | + "If level <= 0 then no packets are logged.\n" | ||
710 | + "If --default is specified then the level becomes the default logging level for all subsequent agents.\n" | ||
711 | + "In this case, you cannot also specify an avatar name.\n" | ||
712 | + "If an avatar name is given then only packets from that avatar are logged.", | ||
713 | HandlePacketCommand); | ||
714 | |||
715 | MainConsole.Instance.Commands.AddCommand( | ||
524 | "Debug", | 716 | "Debug", |
525 | false, | 717 | false, |
526 | "debug lludp start", | 718 | "debug lludp start", |
@@ -559,10 +751,79 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
559 | "debug lludp status", | 751 | "debug lludp status", |
560 | "Return status of LLUDP packet processing.", | 752 | "Return status of LLUDP packet processing.", |
561 | HandleStatusCommand); | 753 | HandleStatusCommand); |
754 | /* disabled | ||
755 | MainConsole.Instance.Commands.AddCommand( | ||
756 | "Debug", | ||
757 | false, | ||
758 | "debug lludp toggle agentupdate", | ||
759 | "debug lludp toggle agentupdate", | ||
760 | "Toggle whether agentupdate packets are processed or simply discarded.", | ||
761 | HandleAgentUpdateCommand); | ||
762 | */ | ||
763 | } | ||
764 | |||
765 | private void HandlePacketCommand(string module, string[] args) | ||
766 | { | ||
767 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) | ||
768 | return; | ||
769 | |||
770 | bool setAsDefaultLevel = false; | ||
771 | OptionSet optionSet = new OptionSet().Add("default", o => setAsDefaultLevel = o != null); | ||
772 | List<string> filteredArgs = optionSet.Parse(args); | ||
773 | |||
774 | string name = null; | ||
775 | |||
776 | if (filteredArgs.Count == 6) | ||
777 | { | ||
778 | if (!setAsDefaultLevel) | ||
779 | { | ||
780 | name = string.Format("{0} {1}", filteredArgs[4], filteredArgs[5]); | ||
781 | } | ||
782 | else | ||
783 | { | ||
784 | MainConsole.Instance.OutputFormat("ERROR: Cannot specify a user name when setting default logging level"); | ||
785 | return; | ||
786 | } | ||
787 | } | ||
788 | |||
789 | if (filteredArgs.Count > 3) | ||
790 | { | ||
791 | int newDebug; | ||
792 | if (int.TryParse(filteredArgs[3], out newDebug)) | ||
793 | { | ||
794 | if (setAsDefaultLevel) | ||
795 | { | ||
796 | DefaultClientPacketDebugLevel = newDebug; | ||
797 | MainConsole.Instance.OutputFormat( | ||
798 | "Debug packet debug for new clients set to {0} in {1}", DefaultClientPacketDebugLevel, m_scene.Name); | ||
799 | } | ||
800 | else | ||
801 | { | ||
802 | m_scene.ForEachScenePresence(sp => | ||
803 | { | ||
804 | if (name == null || sp.Name == name) | ||
805 | { | ||
806 | MainConsole.Instance.OutputFormat( | ||
807 | "Packet debug for {0} ({1}) set to {2} in {3}", | ||
808 | sp.Name, sp.IsChildAgent ? "child" : "root", newDebug, m_scene.Name); | ||
809 | |||
810 | sp.ControllingClient.DebugPacketLevel = newDebug; | ||
811 | } | ||
812 | }); | ||
813 | } | ||
814 | } | ||
815 | else | ||
816 | { | ||
817 | MainConsole.Instance.Output("Usage: debug lludp packet [--default] 0..255 [<first-name> <last-name>]"); | ||
818 | } | ||
819 | } | ||
562 | } | 820 | } |
563 | 821 | ||
564 | private void HandleStartCommand(string module, string[] args) | 822 | private void HandleStartCommand(string module, string[] args) |
565 | { | 823 | { |
824 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) | ||
825 | return; | ||
826 | |||
566 | if (args.Length != 4) | 827 | if (args.Length != 4) |
567 | { | 828 | { |
568 | MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>"); | 829 | MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>"); |
@@ -580,6 +841,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
580 | 841 | ||
581 | private void HandleStopCommand(string module, string[] args) | 842 | private void HandleStopCommand(string module, string[] args) |
582 | { | 843 | { |
844 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) | ||
845 | return; | ||
846 | |||
583 | if (args.Length != 4) | 847 | if (args.Length != 4) |
584 | { | 848 | { |
585 | MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>"); | 849 | MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>"); |
@@ -597,6 +861,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
597 | 861 | ||
598 | private void HandlePoolCommand(string module, string[] args) | 862 | private void HandlePoolCommand(string module, string[] args) |
599 | { | 863 | { |
864 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) | ||
865 | return; | ||
866 | |||
600 | if (args.Length != 4) | 867 | if (args.Length != 4) |
601 | { | 868 | { |
602 | MainConsole.Instance.Output("Usage: debug lludp pool <on|off>"); | 869 | MainConsole.Instance.Output("Usage: debug lludp pool <on|off>"); |
@@ -627,8 +894,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
627 | } | 894 | } |
628 | } | 895 | } |
629 | 896 | ||
897 | bool m_discardAgentUpdates; | ||
898 | |||
899 | private void HandleAgentUpdateCommand(string module, string[] args) | ||
900 | { | ||
901 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) | ||
902 | return; | ||
903 | |||
904 | m_discardAgentUpdates = !m_discardAgentUpdates; | ||
905 | |||
906 | MainConsole.Instance.OutputFormat( | ||
907 | "Discard AgentUpdates now {0} for {1}", m_discardAgentUpdates, m_scene.Name); | ||
908 | } | ||
909 | |||
630 | private void HandleStatusCommand(string module, string[] args) | 910 | private void HandleStatusCommand(string module, string[] args) |
631 | { | 911 | { |
912 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) | ||
913 | return; | ||
914 | |||
632 | MainConsole.Instance.OutputFormat( | 915 | MainConsole.Instance.OutputFormat( |
633 | "IN LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningInbound ? "enabled" : "disabled"); | 916 | "IN LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningInbound ? "enabled" : "disabled"); |
634 | 917 | ||
@@ -636,6 +919,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
636 | "OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled"); | 919 | "OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled"); |
637 | 920 | ||
638 | MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_scene.Name, UsePools ? "on" : "off"); | 921 | MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_scene.Name, UsePools ? "on" : "off"); |
922 | |||
923 | MainConsole.Instance.OutputFormat( | ||
924 | "Packet debug level for new clients is {0}", DefaultClientPacketDebugLevel); | ||
639 | } | 925 | } |
640 | 926 | ||
641 | public bool HandlesRegion(Location x) | 927 | public bool HandlesRegion(Location x) |
@@ -643,44 +929,44 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
643 | return x == m_location; | 929 | return x == m_location; |
644 | } | 930 | } |
645 | 931 | ||
646 | public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting) | 932 | // public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting) |
647 | { | 933 | // { |
648 | // CoarseLocationUpdate and AvatarGroupsReply packets cannot be split in an automated way | 934 | // // CoarseLocationUpdate and AvatarGroupsReply packets cannot be split in an automated way |
649 | if ((packet.Type == PacketType.CoarseLocationUpdate || packet.Type == PacketType.AvatarGroupsReply) && allowSplitting) | 935 | // if ((packet.Type == PacketType.CoarseLocationUpdate || packet.Type == PacketType.AvatarGroupsReply) && allowSplitting) |
650 | allowSplitting = false; | 936 | // allowSplitting = false; |
651 | 937 | // | |
652 | if (allowSplitting && packet.HasVariableBlocks) | 938 | // if (allowSplitting && packet.HasVariableBlocks) |
653 | { | 939 | // { |
654 | byte[][] datas = packet.ToBytesMultiple(); | 940 | // byte[][] datas = packet.ToBytesMultiple(); |
655 | int packetCount = datas.Length; | 941 | // int packetCount = datas.Length; |
656 | 942 | // | |
657 | if (packetCount < 1) | 943 | // if (packetCount < 1) |
658 | m_log.Error("[LLUDPSERVER]: Failed to split " + packet.Type + " with estimated length " + packet.Length); | 944 | // m_log.Error("[LLUDPSERVER]: Failed to split " + packet.Type + " with estimated length " + packet.Length); |
659 | 945 | // | |
660 | for (int i = 0; i < packetCount; i++) | 946 | // for (int i = 0; i < packetCount; i++) |
661 | { | 947 | // { |
662 | byte[] data = datas[i]; | 948 | // byte[] data = datas[i]; |
663 | m_scene.ForEachClient( | 949 | // m_scene.ForEachClient( |
664 | delegate(IClientAPI client) | 950 | // delegate(IClientAPI client) |
665 | { | 951 | // { |
666 | if (client is LLClientView) | 952 | // if (client is LLClientView) |
667 | SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null); | 953 | // SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null); |
668 | } | 954 | // } |
669 | ); | 955 | // ); |
670 | } | 956 | // } |
671 | } | 957 | // } |
672 | else | 958 | // else |
673 | { | 959 | // { |
674 | byte[] data = packet.ToBytes(); | 960 | // byte[] data = packet.ToBytes(); |
675 | m_scene.ForEachClient( | 961 | // m_scene.ForEachClient( |
676 | delegate(IClientAPI client) | 962 | // delegate(IClientAPI client) |
677 | { | 963 | // { |
678 | if (client is LLClientView) | 964 | // if (client is LLClientView) |
679 | SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null); | 965 | // SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null); |
680 | } | 966 | // } |
681 | ); | 967 | // ); |
682 | } | 968 | // } |
683 | } | 969 | // } |
684 | 970 | ||
685 | /// <summary> | 971 | /// <summary> |
686 | /// Start the process of sending a packet to the client. | 972 | /// Start the process of sending a packet to the client. |
@@ -700,6 +986,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
700 | if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting) | 986 | if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting) |
701 | allowSplitting = false; | 987 | allowSplitting = false; |
702 | 988 | ||
989 | bool packetQueued = false; | ||
990 | |||
703 | if (allowSplitting && packet.HasVariableBlocks) | 991 | if (allowSplitting && packet.HasVariableBlocks) |
704 | { | 992 | { |
705 | byte[][] datas = packet.ToBytesMultiple(); | 993 | byte[][] datas = packet.ToBytesMultiple(); |
@@ -711,16 +999,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
711 | for (int i = 0; i < packetCount; i++) | 999 | for (int i = 0; i < packetCount; i++) |
712 | { | 1000 | { |
713 | byte[] data = datas[i]; | 1001 | byte[] data = datas[i]; |
714 | SendPacketData(udpClient, data, packet.Type, category, method); | 1002 | |
1003 | if (!SendPacketData(udpClient, data, packet.Type, category, method)) | ||
1004 | packetQueued = true; | ||
715 | } | 1005 | } |
716 | } | 1006 | } |
717 | else | 1007 | else |
718 | { | 1008 | { |
719 | byte[] data = packet.ToBytes(); | 1009 | byte[] data = packet.ToBytes(); |
720 | SendPacketData(udpClient, data, packet.Type, category, method); | 1010 | packetQueued = SendPacketData(udpClient, data, packet.Type, category, method); |
721 | } | 1011 | } |
722 | 1012 | ||
723 | PacketPool.Instance.ReturnPacket(packet); | 1013 | PacketPool.Instance.ReturnPacket(packet); |
1014 | |||
1015 | /// WRONG use. May be usefull in future revision | ||
1016 | // if (packetQueued) | ||
1017 | // m_dataPresentEvent.Set(); | ||
724 | } | 1018 | } |
725 | 1019 | ||
726 | /// <summary> | 1020 | /// <summary> |
@@ -734,7 +1028,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
734 | /// The method to call if the packet is not acked by the client. If null, then a standard | 1028 | /// The method to call if the packet is not acked by the client. If null, then a standard |
735 | /// resend of the packet is done. | 1029 | /// resend of the packet is done. |
736 | /// </param> | 1030 | /// </param> |
737 | public void SendPacketData( | 1031 | /// <returns>true if the data was sent immediately, false if it was queued for sending</returns> |
1032 | public bool SendPacketData( | ||
738 | LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category, UnackedPacketMethod method) | 1033 | LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category, UnackedPacketMethod method) |
739 | { | 1034 | { |
740 | int dataLength = data.Length; | 1035 | int dataLength = data.Length; |
@@ -807,7 +1102,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
807 | // packet so that it isn't sent before a queued update packet. | 1102 | // packet so that it isn't sent before a queued update packet. |
808 | bool requestQueue = type == PacketType.KillObject; | 1103 | bool requestQueue = type == PacketType.KillObject; |
809 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue, highPriority)) | 1104 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue, highPriority)) |
1105 | { | ||
810 | SendPacketFinal(outgoingPacket); | 1106 | SendPacketFinal(outgoingPacket); |
1107 | return true; | ||
1108 | } | ||
1109 | |||
1110 | return false; | ||
811 | 1111 | ||
812 | #endregion Queue or Send | 1112 | #endregion Queue or Send |
813 | } | 1113 | } |
@@ -848,6 +1148,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
848 | pc.PingID.OldestUnacked = 0; | 1148 | pc.PingID.OldestUnacked = 0; |
849 | 1149 | ||
850 | SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false, null); | 1150 | SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false, null); |
1151 | udpClient.m_lastStartpingTimeMS = Util.EnvironmentTickCount(); | ||
851 | } | 1152 | } |
852 | 1153 | ||
853 | public void CompletePing(LLUDPClient udpClient, byte pingID) | 1154 | public void CompletePing(LLUDPClient udpClient, byte pingID) |
@@ -883,7 +1184,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
883 | // Fire this out on a different thread so that we don't hold up outgoing packet processing for | 1184 | // Fire this out on a different thread so that we don't hold up outgoing packet processing for |
884 | // everybody else if this is being called due to an ack timeout. | 1185 | // everybody else if this is being called due to an ack timeout. |
885 | // This is the same as processing as the async process of a logout request. | 1186 | // This is the same as processing as the async process of a logout request. |
886 | Util.FireAndForget(o => DeactivateClientDueToTimeout(client)); | 1187 | Util.FireAndForget(o => DeactivateClientDueToTimeout(client, timeoutTicks)); |
887 | 1188 | ||
888 | return; | 1189 | return; |
889 | } | 1190 | } |
@@ -988,6 +1289,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
988 | else | 1289 | else |
989 | { | 1290 | { |
990 | Interlocked.Increment(ref udpClient.PacketsResent); | 1291 | Interlocked.Increment(ref udpClient.PacketsResent); |
1292 | |||
1293 | // We're not going to worry about interlock yet since its not currently critical that this total count | ||
1294 | // is 100% correct | ||
1295 | PacketsResentCount++; | ||
991 | } | 1296 | } |
992 | 1297 | ||
993 | #endregion Sequence Number Assignment | 1298 | #endregion Sequence Number Assignment |
@@ -995,6 +1300,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
995 | // Stats tracking | 1300 | // Stats tracking |
996 | Interlocked.Increment(ref udpClient.PacketsSent); | 1301 | Interlocked.Increment(ref udpClient.PacketsSent); |
997 | 1302 | ||
1303 | // We're not going to worry about interlock yet since its not currently critical that this total count | ||
1304 | // is 100% correct | ||
1305 | PacketsSentCount++; | ||
1306 | |||
998 | // Put the UDP payload on the wire | 1307 | // Put the UDP payload on the wire |
999 | AsyncBeginSend(buffer); | 1308 | AsyncBeginSend(buffer); |
1000 | 1309 | ||
@@ -1002,6 +1311,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1002 | outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue; | 1311 | outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue; |
1003 | } | 1312 | } |
1004 | 1313 | ||
1314 | private void RecordMalformedInboundPacket(IPEndPoint endPoint) | ||
1315 | { | ||
1316 | // if (m_malformedCount < 100) | ||
1317 | // m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString()); | ||
1318 | |||
1319 | IncomingMalformedPacketCount++; | ||
1320 | |||
1321 | if ((IncomingMalformedPacketCount % 10000) == 0) | ||
1322 | m_log.WarnFormat( | ||
1323 | "[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack. Last was from {1}", | ||
1324 | IncomingMalformedPacketCount, endPoint); | ||
1325 | } | ||
1326 | |||
1005 | public override void PacketReceived(UDPPacketBuffer buffer) | 1327 | public override void PacketReceived(UDPPacketBuffer buffer) |
1006 | { | 1328 | { |
1007 | // Debugging/Profiling | 1329 | // Debugging/Profiling |
@@ -1023,6 +1345,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1023 | // "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}", | 1345 | // "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}", |
1024 | // buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); | 1346 | // buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); |
1025 | 1347 | ||
1348 | RecordMalformedInboundPacket(endPoint); | ||
1349 | |||
1026 | return; // Drop undersized packet | 1350 | return; // Drop undersized packet |
1027 | } | 1351 | } |
1028 | 1352 | ||
@@ -1041,6 +1365,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1041 | // "[LLUDPSERVER]: Dropping packet with malformed header received from {0} in {1}", | 1365 | // "[LLUDPSERVER]: Dropping packet with malformed header received from {0} in {1}", |
1042 | // buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); | 1366 | // buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); |
1043 | 1367 | ||
1368 | RecordMalformedInboundPacket(endPoint); | ||
1369 | |||
1044 | return; // Malformed header | 1370 | return; // Malformed header |
1045 | } | 1371 | } |
1046 | 1372 | ||
@@ -1056,34 +1382,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1056 | // Only allocate a buffer for zerodecoding if the packet is zerocoded | 1382 | // Only allocate a buffer for zerodecoding if the packet is zerocoded |
1057 | ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null); | 1383 | ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null); |
1058 | } | 1384 | } |
1059 | catch (MalformedDataException) | ||
1060 | { | ||
1061 | } | ||
1062 | catch (IndexOutOfRangeException) | ||
1063 | { | ||
1064 | // m_log.WarnFormat( | ||
1065 | // "[LLUDPSERVER]: Dropping short packet received from {0} in {1}", | ||
1066 | // buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); | ||
1067 | |||
1068 | return; // Drop short packet | ||
1069 | } | ||
1070 | catch (Exception e) | 1385 | catch (Exception e) |
1071 | { | 1386 | { |
1072 | if (m_malformedCount < 100) | 1387 | if (IncomingMalformedPacketCount < 100) |
1073 | m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString()); | 1388 | m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString()); |
1074 | |||
1075 | m_malformedCount++; | ||
1076 | |||
1077 | if ((m_malformedCount % 100000) == 0) | ||
1078 | m_log.DebugFormat("[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack.", m_malformedCount); | ||
1079 | } | 1389 | } |
1080 | 1390 | ||
1081 | // Fail-safe check | 1391 | // Fail-safe check |
1082 | if (packet == null) | 1392 | if (packet == null) |
1083 | { | 1393 | { |
1084 | m_log.ErrorFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}:", | 1394 | if (IncomingMalformedPacketCount < 100) |
1085 | buffer.DataLength, buffer.RemoteEndPoint); | 1395 | { |
1086 | m_log.Error(Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)); | 1396 | m_log.WarnFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}, data {2}:", |
1397 | buffer.DataLength, buffer.RemoteEndPoint, Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)); | ||
1398 | } | ||
1399 | |||
1400 | RecordMalformedInboundPacket(endPoint); | ||
1401 | |||
1087 | return; | 1402 | return; |
1088 | } | 1403 | } |
1089 | 1404 | ||
@@ -1127,12 +1442,36 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1127 | queue.Enqueue(buffer); | 1442 | queue.Enqueue(buffer); |
1128 | return; | 1443 | return; |
1129 | } | 1444 | } |
1445 | |||
1446 | /* | ||
1447 | else if (packet.Type == PacketType.CompleteAgentMovement) | ||
1448 | { | ||
1449 | // Send ack straight away to let the viewer know that we got it. | ||
1450 | SendAckImmediate(endPoint, packet.Header.Sequence); | ||
1451 | |||
1452 | // We need to copy the endpoint so that it doesn't get changed when another thread reuses the | ||
1453 | // buffer. | ||
1454 | object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; | ||
1455 | |||
1456 | Util.FireAndForget(HandleCompleteMovementIntoRegion, array); | ||
1457 | |||
1458 | return; | ||
1459 | } | ||
1460 | */ | ||
1130 | } | 1461 | } |
1131 | 1462 | ||
1132 | // Determine which agent this packet came from | 1463 | // Determine which agent this packet came from |
1133 | if (client == null || !(client is LLClientView)) | 1464 | if (client == null || !(client is LLClientView)) |
1134 | { | 1465 | { |
1135 | //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); | 1466 | //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); |
1467 | |||
1468 | IncomingOrphanedPacketCount++; | ||
1469 | |||
1470 | if ((IncomingOrphanedPacketCount % 10000) == 0) | ||
1471 | m_log.WarnFormat( | ||
1472 | "[LLUDPSERVER]: Received {0} orphaned packets so far. Last was from {1}", | ||
1473 | IncomingOrphanedPacketCount, endPoint); | ||
1474 | |||
1136 | return; | 1475 | return; |
1137 | } | 1476 | } |
1138 | 1477 | ||
@@ -1211,6 +1550,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1211 | 1550 | ||
1212 | #region Incoming Packet Accounting | 1551 | #region Incoming Packet Accounting |
1213 | 1552 | ||
1553 | // We're not going to worry about interlock yet since its not currently critical that this total count | ||
1554 | // is 100% correct | ||
1555 | if (packet.Header.Resent) | ||
1556 | IncomingPacketsResentCount++; | ||
1557 | |||
1214 | // Check the archive of received reliable packet IDs to see whether we already received this packet | 1558 | // Check the archive of received reliable packet IDs to see whether we already received this packet |
1215 | if (packet.Header.Reliable && !udpClient.PacketArchive.TryEnqueue(packet.Header.Sequence)) | 1559 | if (packet.Header.Reliable && !udpClient.PacketArchive.TryEnqueue(packet.Header.Sequence)) |
1216 | { | 1560 | { |
@@ -1233,6 +1577,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1233 | LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length); | 1577 | LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length); |
1234 | #endregion BinaryStats | 1578 | #endregion BinaryStats |
1235 | 1579 | ||
1580 | // AgentUpdate mess removed from here | ||
1581 | |||
1236 | #region Ping Check Handling | 1582 | #region Ping Check Handling |
1237 | 1583 | ||
1238 | if (packet.Type == PacketType.StartPingCheck) | 1584 | if (packet.Type == PacketType.StartPingCheck) |
@@ -1242,7 +1588,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1242 | // We don't need to do anything else with ping checks | 1588 | // We don't need to do anything else with ping checks |
1243 | StartPingCheckPacket startPing = (StartPingCheckPacket)packet; | 1589 | StartPingCheckPacket startPing = (StartPingCheckPacket)packet; |
1244 | CompletePing(udpClient, startPing.PingID.PingID); | 1590 | CompletePing(udpClient, startPing.PingID.PingID); |
1245 | 1591 | ||
1246 | if ((Environment.TickCount - m_elapsedMSSinceLastStatReport) >= 3000) | 1592 | if ((Environment.TickCount - m_elapsedMSSinceLastStatReport) >= 3000) |
1247 | { | 1593 | { |
1248 | udpClient.SendPacketStats(); | 1594 | udpClient.SendPacketStats(); |
@@ -1252,7 +1598,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1252 | } | 1598 | } |
1253 | else if (packet.Type == PacketType.CompletePingCheck) | 1599 | else if (packet.Type == PacketType.CompletePingCheck) |
1254 | { | 1600 | { |
1255 | // We don't currently track client ping times | 1601 | int t = Util.EnvironmentTickCountSubtract(udpClient.m_lastStartpingTimeMS); |
1602 | int c = udpClient.m_pingMS; | ||
1603 | c = 800 * c + 200 * t; | ||
1604 | c /= 1000; | ||
1605 | udpClient.m_pingMS = c; | ||
1256 | return; | 1606 | return; |
1257 | } | 1607 | } |
1258 | 1608 | ||
@@ -1272,11 +1622,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1272 | incomingPacket = new IncomingPacket((LLClientView)client, packet); | 1622 | incomingPacket = new IncomingPacket((LLClientView)client, packet); |
1273 | } | 1623 | } |
1274 | 1624 | ||
1275 | if (incomingPacket.Packet.Type == PacketType.AgentUpdate || | 1625 | // if (incomingPacket.Packet.Type == PacketType.AgentUpdate || |
1276 | incomingPacket.Packet.Type == PacketType.ChatFromViewer) | 1626 | // incomingPacket.Packet.Type == PacketType.ChatFromViewer) |
1627 | if (incomingPacket.Packet.Type == PacketType.ChatFromViewer) | ||
1277 | packetInbox.EnqueueHigh(incomingPacket); | 1628 | packetInbox.EnqueueHigh(incomingPacket); |
1278 | else | 1629 | else |
1279 | packetInbox.EnqueueLow(incomingPacket); | 1630 | packetInbox.EnqueueLow(incomingPacket); |
1631 | |||
1280 | } | 1632 | } |
1281 | 1633 | ||
1282 | #region BinaryStats | 1634 | #region BinaryStats |
@@ -1393,7 +1745,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1393 | 1745 | ||
1394 | try | 1746 | try |
1395 | { | 1747 | { |
1396 | // DateTime startTime = DateTime.Now; | 1748 | // DateTime startTime = DateTime.Now; |
1397 | object[] array = (object[])o; | 1749 | object[] array = (object[])o; |
1398 | endPoint = (IPEndPoint)array[0]; | 1750 | endPoint = (IPEndPoint)array[0]; |
1399 | UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1]; | 1751 | UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1]; |
@@ -1413,20 +1765,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1413 | uccp.CircuitCode.SessionID, | 1765 | uccp.CircuitCode.SessionID, |
1414 | endPoint, | 1766 | endPoint, |
1415 | sessionInfo); | 1767 | sessionInfo); |
1416 | |||
1417 | // Send ack straight away to let the viewer know that the connection is active. | ||
1418 | // The client will be null if it already exists (e.g. if on a region crossing the client sends a use | ||
1419 | // circuit code to the existing child agent. This is not particularly obvious. | ||
1420 | SendAckImmediate(endPoint, uccp.Header.Sequence); | ||
1421 | |||
1422 | // We only want to send initial data to new clients, not ones which are being converted from child to root. | ||
1423 | if (client != null) | ||
1424 | client.SceneAgent.SendInitialDataToMe(); | ||
1425 | 1768 | ||
1426 | // Now we know we can handle more data | 1769 | // Now we know we can handle more data |
1427 | Thread.Sleep(200); | 1770 | Thread.Sleep(200); |
1428 | 1771 | ||
1429 | // Obtain the queue and remove it from the cache | 1772 | // Obtain the pending queue and remove it from the cache |
1430 | Queue<UDPPacketBuffer> queue = null; | 1773 | Queue<UDPPacketBuffer> queue = null; |
1431 | 1774 | ||
1432 | lock (m_pendingCache) | 1775 | lock (m_pendingCache) |
@@ -1435,6 +1778,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1435 | { | 1778 | { |
1436 | m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present"); | 1779 | m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present"); |
1437 | return; | 1780 | return; |
1781 | |||
1438 | } | 1782 | } |
1439 | m_pendingCache.Remove(endPoint); | 1783 | m_pendingCache.Remove(endPoint); |
1440 | } | 1784 | } |
@@ -1442,12 +1786,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1442 | m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count); | 1786 | m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count); |
1443 | 1787 | ||
1444 | // Reinject queued packets | 1788 | // Reinject queued packets |
1445 | while(queue.Count > 0) | 1789 | while (queue.Count > 0) |
1446 | { | 1790 | { |
1447 | UDPPacketBuffer buf = queue.Dequeue(); | 1791 | UDPPacketBuffer buf = queue.Dequeue(); |
1448 | PacketReceived(buf); | 1792 | PacketReceived(buf); |
1449 | } | 1793 | } |
1794 | |||
1450 | queue = null; | 1795 | queue = null; |
1796 | |||
1797 | // Send ack straight away to let the viewer know that the connection is active. | ||
1798 | // The client will be null if it already exists (e.g. if on a region crossing the client sends a use | ||
1799 | // circuit code to the existing child agent. This is not particularly obvious. | ||
1800 | SendAckImmediate(endPoint, uccp.Header.Sequence); | ||
1801 | |||
1802 | // We only want to send initial data to new clients, not ones which are being converted from child to root. | ||
1803 | if (client != null) | ||
1804 | { | ||
1805 | AgentCircuitData aCircuit = m_scene.AuthenticateHandler.GetAgentCircuitData(uccp.CircuitCode.Code); | ||
1806 | bool tp = (aCircuit.teleportFlags > 0); | ||
1807 | // Let's delay this for TP agents, otherwise the viewer doesn't know where to get resources from | ||
1808 | if (!tp) | ||
1809 | client.SceneAgent.SendInitialDataToMe(); | ||
1810 | } | ||
1451 | } | 1811 | } |
1452 | else | 1812 | else |
1453 | { | 1813 | { |
@@ -1457,8 +1817,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1457 | uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint); | 1817 | uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint); |
1458 | lock (m_pendingCache) | 1818 | lock (m_pendingCache) |
1459 | m_pendingCache.Remove(endPoint); | 1819 | m_pendingCache.Remove(endPoint); |
1460 | } | 1820 | } |
1461 | |||
1462 | // m_log.DebugFormat( | 1821 | // m_log.DebugFormat( |
1463 | // "[LLUDPSERVER]: Handling UseCircuitCode request from {0} took {1}ms", | 1822 | // "[LLUDPSERVER]: Handling UseCircuitCode request from {0} took {1}ms", |
1464 | // buffer.RemoteEndPoint, (DateTime.Now - startTime).Milliseconds); | 1823 | // buffer.RemoteEndPoint, (DateTime.Now - startTime).Milliseconds); |
@@ -1475,6 +1834,117 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1475 | e.StackTrace); | 1834 | e.StackTrace); |
1476 | } | 1835 | } |
1477 | } | 1836 | } |
1837 | /* | ||
1838 | private void HandleCompleteMovementIntoRegion(object o) | ||
1839 | { | ||
1840 | IPEndPoint endPoint = null; | ||
1841 | IClientAPI client = null; | ||
1842 | |||
1843 | try | ||
1844 | { | ||
1845 | object[] array = (object[])o; | ||
1846 | endPoint = (IPEndPoint)array[0]; | ||
1847 | CompleteAgentMovementPacket packet = (CompleteAgentMovementPacket)array[1]; | ||
1848 | |||
1849 | m_log.DebugFormat( | ||
1850 | "[LLUDPSERVER]: Handling CompleteAgentMovement request from {0} in {1}", endPoint, m_scene.Name); | ||
1851 | |||
1852 | // Determine which agent this packet came from | ||
1853 | // We need to wait here because in when using the OpenSimulator V2 teleport protocol to travel to a destination | ||
1854 | // simulator with no existing child presence, the viewer (at least LL 3.3.4) will send UseCircuitCode | ||
1855 | // and then CompleteAgentMovement immediately without waiting for an ack. As we are now handling these | ||
1856 | // packets asynchronously, we need to account for this thread proceeding more quickly than the | ||
1857 | // UseCircuitCode thread. | ||
1858 | int count = 40; | ||
1859 | while (count-- > 0) | ||
1860 | { | ||
1861 | if (m_scene.TryGetClient(endPoint, out client)) | ||
1862 | { | ||
1863 | if (!client.IsActive) | ||
1864 | { | ||
1865 | // This check exists to catch a condition where the client has been closed by another thread | ||
1866 | // but has not yet been removed from the client manager (and possibly a new connection has | ||
1867 | // not yet been established). | ||
1868 | m_log.DebugFormat( | ||
1869 | "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client is not active yet. Waiting.", | ||
1870 | endPoint, client.Name, m_scene.Name); | ||
1871 | } | ||
1872 | else if (client.SceneAgent == null) | ||
1873 | { | ||
1874 | // This check exists to catch a condition where the new client has been added to the client | ||
1875 | // manager but the SceneAgent has not yet been set in Scene.AddNewAgent(). If we are too | ||
1876 | // eager, then the new ScenePresence may not have registered a listener for this messsage | ||
1877 | // before we try to process it. | ||
1878 | // XXX: A better long term fix may be to add the SceneAgent before the client is added to | ||
1879 | // the client manager | ||
1880 | m_log.DebugFormat( | ||
1881 | "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client SceneAgent not set yet. Waiting.", | ||
1882 | endPoint, client.Name, m_scene.Name); | ||
1883 | } | ||
1884 | else | ||
1885 | { | ||
1886 | break; | ||
1887 | } | ||
1888 | } | ||
1889 | else | ||
1890 | { | ||
1891 | m_log.DebugFormat( | ||
1892 | "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} in {1} but no client exists yet. Waiting.", | ||
1893 | endPoint, m_scene.Name); | ||
1894 | } | ||
1895 | |||
1896 | Thread.Sleep(200); | ||
1897 | } | ||
1898 | |||
1899 | if (client == null) | ||
1900 | { | ||
1901 | m_log.DebugFormat( | ||
1902 | "[LLUDPSERVER]: No client found for CompleteAgentMovement from {0} in {1} after wait. Dropping.", | ||
1903 | endPoint, m_scene.Name); | ||
1904 | |||
1905 | return; | ||
1906 | } | ||
1907 | else if (!client.IsActive || client.SceneAgent == null) | ||
1908 | { | ||
1909 | // This check exists to catch a condition where the client has been closed by another thread | ||
1910 | // but has not yet been removed from the client manager. | ||
1911 | // The packet could be simply ignored but it is useful to know if this condition occurred for other debugging | ||
1912 | // purposes. | ||
1913 | m_log.DebugFormat( | ||
1914 | "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client is not active after wait. Dropping.", | ||
1915 | endPoint, client.Name, m_scene.Name); | ||
1916 | |||
1917 | return; | ||
1918 | } | ||
1919 | |||
1920 | IncomingPacket incomingPacket1; | ||
1921 | |||
1922 | // Inbox insertion | ||
1923 | if (UsePools) | ||
1924 | { | ||
1925 | incomingPacket1 = m_incomingPacketPool.GetObject(); | ||
1926 | incomingPacket1.Client = (LLClientView)client; | ||
1927 | incomingPacket1.Packet = packet; | ||
1928 | } | ||
1929 | else | ||
1930 | { | ||
1931 | incomingPacket1 = new IncomingPacket((LLClientView)client, packet); | ||
1932 | } | ||
1933 | |||
1934 | packetInbox.Enqueue(incomingPacket1); | ||
1935 | } | ||
1936 | catch (Exception e) | ||
1937 | { | ||
1938 | m_log.ErrorFormat( | ||
1939 | "[LLUDPSERVER]: CompleteAgentMovement handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}", | ||
1940 | endPoint != null ? endPoint.ToString() : "n/a", | ||
1941 | client != null ? client.Name : "unknown", | ||
1942 | client != null ? client.AgentId.ToString() : "unknown", | ||
1943 | e.Message, | ||
1944 | e.StackTrace); | ||
1945 | } | ||
1946 | } | ||
1947 | */ | ||
1478 | 1948 | ||
1479 | /// <summary> | 1949 | /// <summary> |
1480 | /// Send an ack immediately to the given endpoint. | 1950 | /// Send an ack immediately to the given endpoint. |
@@ -1544,6 +2014,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1544 | 2014 | ||
1545 | client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); | 2015 | client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); |
1546 | client.OnLogout += LogoutHandler; | 2016 | client.OnLogout += LogoutHandler; |
2017 | client.DebugPacketLevel = DefaultClientPacketDebugLevel; | ||
1547 | 2018 | ||
1548 | ((LLClientView)client).DisableFacelights = m_disableFacelights; | 2019 | ((LLClientView)client).DisableFacelights = m_disableFacelights; |
1549 | 2020 | ||
@@ -1562,21 +2033,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1562 | /// regular client pings. | 2033 | /// regular client pings. |
1563 | /// </remarks> | 2034 | /// </remarks> |
1564 | /// <param name='client'></param> | 2035 | /// <param name='client'></param> |
1565 | private void DeactivateClientDueToTimeout(LLClientView client) | 2036 | /// <param name='timeoutTicks'></param> |
2037 | private void DeactivateClientDueToTimeout(LLClientView client, int timeoutTicks) | ||
1566 | { | 2038 | { |
1567 | lock (client.CloseSyncLock) | 2039 | lock (client.CloseSyncLock) |
1568 | { | 2040 | { |
2041 | ClientLogoutsDueToNoReceives++; | ||
2042 | |||
1569 | m_log.WarnFormat( | 2043 | m_log.WarnFormat( |
1570 | "[LLUDPSERVER]: Ack timeout, disconnecting {0} agent for {1} in {2}", | 2044 | "[LLUDPSERVER]: No packets received from {0} agent of {1} for {2}ms in {3}. Disconnecting.", |
1571 | client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, m_scene.RegionInfo.RegionName); | 2045 | client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, timeoutTicks, m_scene.Name); |
1572 | |||
1573 | StatsManager.SimExtraStats.AddAbnormalClientThreadTermination(); | ||
1574 | 2046 | ||
1575 | if (!client.SceneAgent.IsChildAgent) | 2047 | if (!client.SceneAgent.IsChildAgent) |
1576 | client.Kick("Simulator logged you out due to connection timeout"); | 2048 | client.Kick("Simulator logged you out due to connection timeout."); |
1577 | |||
1578 | client.CloseWithoutChecks(true); | ||
1579 | } | 2049 | } |
2050 | |||
2051 | m_scene.CloseAgent(client.AgentId, true); | ||
1580 | } | 2052 | } |
1581 | 2053 | ||
1582 | private void IncomingPacketHandler() | 2054 | private void IncomingPacketHandler() |
@@ -1592,6 +2064,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1592 | { | 2064 | { |
1593 | IncomingPacket incomingPacket = null; | 2065 | IncomingPacket incomingPacket = null; |
1594 | 2066 | ||
2067 | /* | ||
1595 | // HACK: This is a test to try and rate limit packet handling on Mono. | 2068 | // HACK: This is a test to try and rate limit packet handling on Mono. |
1596 | // If it works, a more elegant solution can be devised | 2069 | // If it works, a more elegant solution can be devised |
1597 | if (Util.FireAndForgetCount() < 2) | 2070 | if (Util.FireAndForgetCount() < 2) |
@@ -1599,6 +2072,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1599 | //m_log.Debug("[LLUDPSERVER]: Incoming packet handler is sleeping"); | 2072 | //m_log.Debug("[LLUDPSERVER]: Incoming packet handler is sleeping"); |
1600 | Thread.Sleep(30); | 2073 | Thread.Sleep(30); |
1601 | } | 2074 | } |
2075 | */ | ||
1602 | 2076 | ||
1603 | if (packetInbox.Dequeue(100, ref incomingPacket)) | 2077 | if (packetInbox.Dequeue(100, ref incomingPacket)) |
1604 | { | 2078 | { |
@@ -1608,7 +2082,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1608 | m_incomingPacketPool.ReturnObject(incomingPacket); | 2082 | m_incomingPacketPool.ReturnObject(incomingPacket); |
1609 | } | 2083 | } |
1610 | } | 2084 | } |
1611 | catch (Exception ex) | 2085 | catch(Exception ex) |
1612 | { | 2086 | { |
1613 | m_log.Error("[LLUDPSERVER]: Error in the incoming packet handler loop: " + ex.Message, ex); | 2087 | m_log.Error("[LLUDPSERVER]: Error in the incoming packet handler loop: " + ex.Message, ex); |
1614 | } | 2088 | } |
@@ -1694,9 +2168,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1694 | 2168 | ||
1695 | // If nothing was sent, sleep for the minimum amount of time before a | 2169 | // If nothing was sent, sleep for the minimum amount of time before a |
1696 | // token bucket could get more tokens | 2170 | // token bucket could get more tokens |
2171 | |||
1697 | if (!m_packetSent) | 2172 | if (!m_packetSent) |
1698 | Thread.Sleep((int)TickCountResolution); | 2173 | Thread.Sleep((int)TickCountResolution); |
1699 | 2174 | ||
2175 | // .... wrong core code removed | ||
2176 | |||
2177 | |||
1700 | Watchdog.UpdateThread(); | 2178 | Watchdog.UpdateThread(); |
1701 | } | 2179 | } |
1702 | catch (Exception ex) | 2180 | catch (Exception ex) |
@@ -1912,7 +2390,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1912 | if (!client.IsLoggingOut) | 2390 | if (!client.IsLoggingOut) |
1913 | { | 2391 | { |
1914 | client.IsLoggingOut = true; | 2392 | client.IsLoggingOut = true; |
1915 | client.Close(false, false); | 2393 | m_scene.CloseAgent(client.AgentId, false); |
1916 | } | 2394 | } |
1917 | } | 2395 | } |
1918 | } | 2396 | } |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs index 7035e38..881e768 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs | |||
@@ -78,6 +78,36 @@ namespace OpenMetaverse | |||
78 | public bool IsRunningOutbound { get; private set; } | 78 | public bool IsRunningOutbound { get; private set; } |
79 | 79 | ||
80 | /// <summary> | 80 | /// <summary> |
81 | /// Number of UDP receives. | ||
82 | /// </summary> | ||
83 | public int UdpReceives { get; private set; } | ||
84 | |||
85 | /// <summary> | ||
86 | /// Number of UDP sends | ||
87 | /// </summary> | ||
88 | public int UdpSends { get; private set; } | ||
89 | |||
90 | /// <summary> | ||
91 | /// Number of receives over which to establish a receive time average. | ||
92 | /// </summary> | ||
93 | private readonly static int s_receiveTimeSamples = 500; | ||
94 | |||
95 | /// <summary> | ||
96 | /// Current number of samples taken to establish a receive time average. | ||
97 | /// </summary> | ||
98 | private int m_currentReceiveTimeSamples; | ||
99 | |||
100 | /// <summary> | ||
101 | /// Cumulative receive time for the sample so far. | ||
102 | /// </summary> | ||
103 | private int m_receiveTicksInCurrentSamplePeriod; | ||
104 | |||
105 | /// <summary> | ||
106 | /// The average time taken for each require receive in the last sample. | ||
107 | /// </summary> | ||
108 | public float AverageReceiveTicksForLastSamplePeriod { get; private set; } | ||
109 | |||
110 | /// <summary> | ||
81 | /// Default constructor | 111 | /// Default constructor |
82 | /// </summary> | 112 | /// </summary> |
83 | /// <param name="bindAddress">Local IP address to bind the server to</param> | 113 | /// <param name="bindAddress">Local IP address to bind the server to</param> |
@@ -111,6 +141,8 @@ namespace OpenMetaverse | |||
111 | 141 | ||
112 | if (!IsRunningInbound) | 142 | if (!IsRunningInbound) |
113 | { | 143 | { |
144 | m_log.DebugFormat("[UDPBASE]: Starting inbound UDP loop"); | ||
145 | |||
114 | const int SIO_UDP_CONNRESET = -1744830452; | 146 | const int SIO_UDP_CONNRESET = -1744830452; |
115 | 147 | ||
116 | IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort); | 148 | IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort); |
@@ -151,6 +183,8 @@ namespace OpenMetaverse | |||
151 | /// </summary> | 183 | /// </summary> |
152 | public void StartOutbound() | 184 | public void StartOutbound() |
153 | { | 185 | { |
186 | m_log.DebugFormat("[UDPBASE]: Starting outbound UDP loop"); | ||
187 | |||
154 | IsRunningOutbound = true; | 188 | IsRunningOutbound = true; |
155 | } | 189 | } |
156 | 190 | ||
@@ -158,10 +192,8 @@ namespace OpenMetaverse | |||
158 | { | 192 | { |
159 | if (IsRunningInbound) | 193 | if (IsRunningInbound) |
160 | { | 194 | { |
161 | // wait indefinitely for a writer lock. Once this is called, the .NET runtime | 195 | m_log.DebugFormat("[UDPBASE]: Stopping inbound UDP loop"); |
162 | // will deny any more reader locks, in effect blocking all other send/receive | 196 | |
163 | // threads. Once we have the lock, we set IsRunningInbound = false to inform the other | ||
164 | // threads that the socket is closed. | ||
165 | IsRunningInbound = false; | 197 | IsRunningInbound = false; |
166 | m_udpSocket.Close(); | 198 | m_udpSocket.Close(); |
167 | } | 199 | } |
@@ -169,6 +201,8 @@ namespace OpenMetaverse | |||
169 | 201 | ||
170 | public void StopOutbound() | 202 | public void StopOutbound() |
171 | { | 203 | { |
204 | m_log.DebugFormat("[UDPBASE]: Stopping outbound UDP loop"); | ||
205 | |||
172 | IsRunningOutbound = false; | 206 | IsRunningOutbound = false; |
173 | } | 207 | } |
174 | 208 | ||
@@ -257,7 +291,16 @@ namespace OpenMetaverse | |||
257 | m_log.Warn("[UDPBASE]: Salvaged the UDP listener on port " + m_udpPort); | 291 | m_log.Warn("[UDPBASE]: Salvaged the UDP listener on port " + m_udpPort); |
258 | } | 292 | } |
259 | } | 293 | } |
260 | catch (ObjectDisposedException) { } | 294 | catch (ObjectDisposedException e) |
295 | { | ||
296 | m_log.Error( | ||
297 | string.Format("[UDPBASE]: Error processing UDP begin receive {0}. Exception ", UdpReceives), e); | ||
298 | } | ||
299 | catch (Exception e) | ||
300 | { | ||
301 | m_log.Error( | ||
302 | string.Format("[UDPBASE]: Error processing UDP begin receive {0}. Exception ", UdpReceives), e); | ||
303 | } | ||
261 | } | 304 | } |
262 | } | 305 | } |
263 | 306 | ||
@@ -267,17 +310,21 @@ namespace OpenMetaverse | |||
267 | // to AsyncBeginReceive | 310 | // to AsyncBeginReceive |
268 | if (IsRunningInbound) | 311 | if (IsRunningInbound) |
269 | { | 312 | { |
313 | UdpReceives++; | ||
314 | |||
270 | // Asynchronous mode will start another receive before the | 315 | // Asynchronous mode will start another receive before the |
271 | // callback for this packet is even fired. Very parallel :-) | 316 | // callback for this packet is even fired. Very parallel :-) |
272 | if (m_asyncPacketHandling) | 317 | if (m_asyncPacketHandling) |
273 | AsyncBeginReceive(); | 318 | AsyncBeginReceive(); |
274 | 319 | ||
275 | // get the buffer that was created in AsyncBeginReceive | ||
276 | // this is the received data | ||
277 | UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState; | ||
278 | |||
279 | try | 320 | try |
280 | { | 321 | { |
322 | // get the buffer that was created in AsyncBeginReceive | ||
323 | // this is the received data | ||
324 | UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState; | ||
325 | |||
326 | int startTick = Util.EnvironmentTickCount(); | ||
327 | |||
281 | // get the length of data actually read from the socket, store it with the | 328 | // get the length of data actually read from the socket, store it with the |
282 | // buffer | 329 | // buffer |
283 | buffer.DataLength = m_udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint); | 330 | buffer.DataLength = m_udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint); |
@@ -285,9 +332,42 @@ namespace OpenMetaverse | |||
285 | // call the abstract method PacketReceived(), passing the buffer that | 332 | // call the abstract method PacketReceived(), passing the buffer that |
286 | // has just been filled from the socket read. | 333 | // has just been filled from the socket read. |
287 | PacketReceived(buffer); | 334 | PacketReceived(buffer); |
335 | |||
336 | // If more than one thread can be calling AsyncEndReceive() at once (e.g. if m_asyncPacketHandler) | ||
337 | // then a particular stat may be inaccurate due to a race condition. We won't worry about this | ||
338 | // since this should be rare and won't cause a runtime problem. | ||
339 | if (m_currentReceiveTimeSamples >= s_receiveTimeSamples) | ||
340 | { | ||
341 | AverageReceiveTicksForLastSamplePeriod | ||
342 | = (float)m_receiveTicksInCurrentSamplePeriod / s_receiveTimeSamples; | ||
343 | |||
344 | m_receiveTicksInCurrentSamplePeriod = 0; | ||
345 | m_currentReceiveTimeSamples = 0; | ||
346 | } | ||
347 | else | ||
348 | { | ||
349 | m_receiveTicksInCurrentSamplePeriod += Util.EnvironmentTickCountSubtract(startTick); | ||
350 | m_currentReceiveTimeSamples++; | ||
351 | } | ||
352 | } | ||
353 | catch (SocketException se) | ||
354 | { | ||
355 | m_log.Error( | ||
356 | string.Format( | ||
357 | "[UDPBASE]: Error processing UDP end receive {0}, socket error code {1}. Exception ", | ||
358 | UdpReceives, se.ErrorCode), | ||
359 | se); | ||
360 | } | ||
361 | catch (ObjectDisposedException e) | ||
362 | { | ||
363 | m_log.Error( | ||
364 | string.Format("[UDPBASE]: Error processing UDP end receive {0}. Exception ", UdpReceives), e); | ||
365 | } | ||
366 | catch (Exception e) | ||
367 | { | ||
368 | m_log.Error( | ||
369 | string.Format("[UDPBASE]: Error processing UDP end receive {0}. Exception ", UdpReceives), e); | ||
288 | } | 370 | } |
289 | catch (SocketException) { } | ||
290 | catch (ObjectDisposedException) { } | ||
291 | finally | 371 | finally |
292 | { | 372 | { |
293 | // if (UsePools) | 373 | // if (UsePools) |
@@ -298,14 +378,13 @@ namespace OpenMetaverse | |||
298 | if (!m_asyncPacketHandling) | 378 | if (!m_asyncPacketHandling) |
299 | AsyncBeginReceive(); | 379 | AsyncBeginReceive(); |
300 | } | 380 | } |
301 | |||
302 | } | 381 | } |
303 | } | 382 | } |
304 | 383 | ||
305 | public void AsyncBeginSend(UDPPacketBuffer buf) | 384 | public void AsyncBeginSend(UDPPacketBuffer buf) |
306 | { | 385 | { |
307 | if (IsRunningOutbound) | 386 | // if (IsRunningOutbound) |
308 | { | 387 | // { |
309 | try | 388 | try |
310 | { | 389 | { |
311 | m_udpSocket.BeginSendTo( | 390 | m_udpSocket.BeginSendTo( |
@@ -319,7 +398,7 @@ namespace OpenMetaverse | |||
319 | } | 398 | } |
320 | catch (SocketException) { } | 399 | catch (SocketException) { } |
321 | catch (ObjectDisposedException) { } | 400 | catch (ObjectDisposedException) { } |
322 | } | 401 | // } |
323 | } | 402 | } |
324 | 403 | ||
325 | void AsyncEndSend(IAsyncResult result) | 404 | void AsyncEndSend(IAsyncResult result) |
@@ -328,6 +407,8 @@ namespace OpenMetaverse | |||
328 | { | 407 | { |
329 | // UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState; | 408 | // UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState; |
330 | m_udpSocket.EndSendTo(result); | 409 | m_udpSocket.EndSendTo(result); |
410 | |||
411 | UdpSends++; | ||
331 | } | 412 | } |
332 | catch (SocketException) { } | 413 | catch (SocketException) { } |
333 | catch (ObjectDisposedException) { } | 414 | catch (ObjectDisposedException) { } |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs index 1fdc410..5a2bcee 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs | |||
@@ -145,39 +145,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
145 | return packet; | 145 | return packet; |
146 | } | 146 | } |
147 | 147 | ||
148 | // private byte[] decoded_header = new byte[10]; | ||
149 | private static PacketType GetType(byte[] bytes) | 148 | private static PacketType GetType(byte[] bytes) |
150 | { | 149 | { |
151 | byte[] decoded_header = new byte[10 + 8]; | ||
152 | ushort id; | 150 | ushort id; |
153 | PacketFrequency freq; | 151 | PacketFrequency freq; |
152 | bool isZeroCoded = (bytes[0] & Helpers.MSG_ZEROCODED) != 0; | ||
154 | 153 | ||
155 | if ((bytes[0] & Helpers.MSG_ZEROCODED) != 0) | 154 | if (bytes[6] == 0xFF) |
156 | { | 155 | { |
157 | Helpers.ZeroDecode(bytes, 16, decoded_header); | 156 | if (bytes[7] == 0xFF) |
158 | } | ||
159 | else | ||
160 | { | ||
161 | Buffer.BlockCopy(bytes, 0, decoded_header, 0, 10); | ||
162 | } | ||
163 | |||
164 | if (decoded_header[6] == 0xFF) | ||
165 | { | ||
166 | if (decoded_header[7] == 0xFF) | ||
167 | { | 157 | { |
168 | id = (ushort) ((decoded_header[8] << 8) + decoded_header[9]); | ||
169 | freq = PacketFrequency.Low; | 158 | freq = PacketFrequency.Low; |
159 | if (isZeroCoded && bytes[8] == 0) | ||
160 | id = bytes[10]; | ||
161 | else | ||
162 | id = (ushort)((bytes[8] << 8) + bytes[9]); | ||
170 | } | 163 | } |
171 | else | 164 | else |
172 | { | 165 | { |
173 | id = decoded_header[7]; | ||
174 | freq = PacketFrequency.Medium; | 166 | freq = PacketFrequency.Medium; |
167 | id = bytes[7]; | ||
175 | } | 168 | } |
176 | } | 169 | } |
177 | else | 170 | else |
178 | { | 171 | { |
179 | id = decoded_header[6]; | ||
180 | freq = PacketFrequency.High; | 172 | freq = PacketFrequency.High; |
173 | id = bytes[6]; | ||
181 | } | 174 | } |
182 | 175 | ||
183 | return Packet.GetType(id, freq); | 176 | return Packet.GetType(id, freq); |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs b/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs index 98ef72f..f8d0c02 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs | |||
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices; | |||
29 | // Build Number | 29 | // Build Number |
30 | // Revision | 30 | // Revision |
31 | // | 31 | // |
32 | [assembly: AssemblyVersion("0.7.6.*")] | 32 | [assembly: AssemblyVersion("0.8.0.*")] |
33 | 33 | ||
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs index 556df30..9700224 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs | |||
@@ -33,6 +33,7 @@ using NUnit.Framework; | |||
33 | using OpenMetaverse; | 33 | using OpenMetaverse; |
34 | using OpenMetaverse.Packets; | 34 | using OpenMetaverse.Packets; |
35 | using OpenSim.Framework; | 35 | using OpenSim.Framework; |
36 | using OpenSim.Framework.Monitoring; | ||
36 | using OpenSim.Region.Framework.Scenes; | 37 | using OpenSim.Region.Framework.Scenes; |
37 | using OpenSim.Tests.Common; | 38 | using OpenSim.Tests.Common; |
38 | using OpenSim.Tests.Common.Mock; | 39 | using OpenSim.Tests.Common.Mock; |
@@ -69,6 +70,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
69 | { | 70 | { |
70 | base.SetUp(); | 71 | base.SetUp(); |
71 | m_scene = new SceneHelpers().SetupScene(); | 72 | m_scene = new SceneHelpers().SetupScene(); |
73 | StatsManager.SimExtraStats = new SimExtraStatsCollector(); | ||
72 | } | 74 | } |
73 | 75 | ||
74 | /// <summary> | 76 | /// <summary> |
@@ -198,7 +200,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
198 | public void TestLogoutClientDueToAck() | 200 | public void TestLogoutClientDueToAck() |
199 | { | 201 | { |
200 | TestHelpers.InMethod(); | 202 | TestHelpers.InMethod(); |
201 | // TestHelpers.EnableLogging(); | 203 | TestHelpers.EnableLogging(); |
202 | 204 | ||
203 | IniConfigSource ics = new IniConfigSource(); | 205 | IniConfigSource ics = new IniConfigSource(); |
204 | IConfig config = ics.AddConfig("ClientStack.LindenUDP"); | 206 | IConfig config = ics.AddConfig("ClientStack.LindenUDP"); |
@@ -210,8 +212,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
210 | 212 | ||
211 | ScenePresence spAfterAckTimeout = m_scene.GetScenePresence(sp.UUID); | 213 | ScenePresence spAfterAckTimeout = m_scene.GetScenePresence(sp.UUID); |
212 | Assert.That(spAfterAckTimeout, Is.Null); | 214 | Assert.That(spAfterAckTimeout, Is.Null); |
213 | |||
214 | // TestHelpers.DisableLogging(); | ||
215 | } | 215 | } |
216 | 216 | ||
217 | // /// <summary> | 217 | // /// <summary> |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs index 7d9f581..575e54c 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs | |||
@@ -29,6 +29,7 @@ using System; | |||
29 | using System.IO; | 29 | using System.IO; |
30 | using System.Net; | 30 | using System.Net; |
31 | using System.Reflection; | 31 | using System.Reflection; |
32 | using System.Threading; | ||
32 | using log4net.Config; | 33 | using log4net.Config; |
33 | using Nini.Config; | 34 | using Nini.Config; |
34 | using NUnit.Framework; | 35 | using NUnit.Framework; |
@@ -53,6 +54,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
53 | [TestFixtureSetUp] | 54 | [TestFixtureSetUp] |
54 | public void FixtureInit() | 55 | public void FixtureInit() |
55 | { | 56 | { |
57 | // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. | ||
58 | Util.FireAndForgetMethod = FireAndForgetMethod.None; | ||
59 | |||
56 | using ( | 60 | using ( |
57 | Stream resource | 61 | Stream resource |
58 | = GetType().Assembly.GetManifestResourceStream( | 62 | = GetType().Assembly.GetManifestResourceStream( |
@@ -72,9 +76,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
72 | } | 76 | } |
73 | } | 77 | } |
74 | 78 | ||
79 | [TestFixtureTearDown] | ||
80 | public void TearDown() | ||
81 | { | ||
82 | // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple | ||
83 | // threads. Possibly, later tests should be rewritten not to worry about such things. | ||
84 | Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod; | ||
85 | } | ||
86 | |||
75 | [SetUp] | 87 | [SetUp] |
76 | public void SetUp() | 88 | public override void SetUp() |
77 | { | 89 | { |
90 | base.SetUp(); | ||
91 | |||
78 | UUID userId = TestHelpers.ParseTail(0x3); | 92 | UUID userId = TestHelpers.ParseTail(0x3); |
79 | 93 | ||
80 | J2KDecoderModule j2kdm = new J2KDecoderModule(); | 94 | J2KDecoderModule j2kdm = new J2KDecoderModule(); |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs index 119a677..e2178e5 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs | |||
@@ -52,17 +52,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
52 | public override void Update(int frames) {} | 52 | public override void Update(int frames) {} |
53 | public override void LoadWorldMap() {} | 53 | public override void LoadWorldMap() {} |
54 | 54 | ||
55 | public override ISceneAgent AddNewClient(IClientAPI client, PresenceType type) | 55 | public override ISceneAgent AddNewAgent(IClientAPI client, PresenceType type) |
56 | { | 56 | { |
57 | client.OnObjectName += RecordObjectNameCall; | 57 | client.OnObjectName += RecordObjectNameCall; |
58 | 58 | ||
59 | // FIXME | 59 | // FIXME |
60 | return null; | 60 | return null; |
61 | } | 61 | } |
62 | 62 | ||
63 | public override void RemoveClient(UUID agentID, bool someReason) {} | 63 | public override bool CloseAgent(UUID agentID, bool force) { return true; } |
64 | // public override void CloseAllAgents(uint circuitcode) {} | 64 | |
65 | public override bool CheckClient(UUID clientId, IPEndPoint endPoint) { return true; } | 65 | public override bool CheckClient(UUID clientId, IPEndPoint endPoint) { return true; } |
66 | |||
66 | public override void OtherRegionUp(GridRegion otherRegion) { } | 67 | public override void OtherRegionUp(GridRegion otherRegion) { } |
67 | 68 | ||
68 | public override bool TryGetScenePresence(UUID uuid, out ScenePresence sp) { sp = null; return false; } | 69 | public override bool TryGetScenePresence(UUID uuid, out ScenePresence sp) { sp = null; return false; } |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs index c9aac0b..e5bae6e 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs | |||
@@ -59,6 +59,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
59 | /// <summary>Flag used to enable adaptive throttles</summary> | 59 | /// <summary>Flag used to enable adaptive throttles</summary> |
60 | public bool AdaptiveThrottlesEnabled; | 60 | public bool AdaptiveThrottlesEnabled; |
61 | 61 | ||
62 | /// <summary>Amount of the texture throttle to steal for the task throttle</summary> | ||
63 | public double CannibalizeTextureRate; | ||
64 | |||
62 | /// <summary> | 65 | /// <summary> |
63 | /// Default constructor | 66 | /// Default constructor |
64 | /// </summary> | 67 | /// </summary> |
@@ -80,6 +83,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
80 | Total = throttleConfig.GetInt("client_throttle_max_bps", 0); | 83 | Total = throttleConfig.GetInt("client_throttle_max_bps", 0); |
81 | 84 | ||
82 | AdaptiveThrottlesEnabled = throttleConfig.GetBoolean("enable_adaptive_throttles", false); | 85 | AdaptiveThrottlesEnabled = throttleConfig.GetBoolean("enable_adaptive_throttles", false); |
86 | |||
87 | CannibalizeTextureRate = (double)throttleConfig.GetFloat("CannibalizeTextureRate", 0.0f); | ||
88 | CannibalizeTextureRate = Util.Clamp<double>(CannibalizeTextureRate,0.0, 0.9); | ||
83 | } | 89 | } |
84 | catch (Exception) { } | 90 | catch (Exception) { } |
85 | } | 91 | } |