diff options
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden')
26 files changed, 1641 insertions, 576 deletions
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..613bc24 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs | |||
@@ -282,13 +282,19 @@ namespace OpenSim.Region.ClientStack.Linden | |||
282 | m_HostCapsObj.RegisterHandler("UpdateNotecardAgentInventory", req); | 282 | m_HostCapsObj.RegisterHandler("UpdateNotecardAgentInventory", req); |
283 | m_HostCapsObj.RegisterHandler("UpdateScriptAgentInventory", req); | 283 | m_HostCapsObj.RegisterHandler("UpdateScriptAgentInventory", req); |
284 | m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req); | 284 | m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req); |
285 | IRequestHandler getObjectPhysicsDataHandler = new RestStreamHandler("POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData); | 285 | |
286 | IRequestHandler getObjectPhysicsDataHandler | ||
287 | = new RestStreamHandler( | ||
288 | "POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData, "GetObjectPhysicsData", null); | ||
286 | m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler); | 289 | m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler); |
287 | IRequestHandler getObjectCostHandler = new RestStreamHandler("POST", capsBase + m_getObjectCostPath, GetObjectCost); | 290 | IRequestHandler getObjectCostHandler = new RestStreamHandler("POST", capsBase + m_getObjectCostPath, GetObjectCost); |
288 | m_HostCapsObj.RegisterHandler("GetObjectCost", getObjectCostHandler); | 291 | m_HostCapsObj.RegisterHandler("GetObjectCost", getObjectCostHandler); |
289 | IRequestHandler ResourceCostSelectedHandler = new RestStreamHandler("POST", capsBase + m_ResourceCostSelectedPath, ResourceCostSelected); | 292 | IRequestHandler ResourceCostSelectedHandler = new RestStreamHandler("POST", capsBase + m_ResourceCostSelectedPath, ResourceCostSelected); |
290 | m_HostCapsObj.RegisterHandler("ResourceCostSelected", ResourceCostSelectedHandler); | 293 | m_HostCapsObj.RegisterHandler("ResourceCostSelected", ResourceCostSelectedHandler); |
291 | IRequestHandler UpdateAgentInformationHandler = new RestStreamHandler("POST", capsBase + m_UpdateAgentInformationPath, UpdateAgentInformation); | 294 | |
295 | IRequestHandler UpdateAgentInformationHandler | ||
296 | = new RestStreamHandler( | ||
297 | "POST", capsBase + m_UpdateAgentInformationPath, UpdateAgentInformation, "UpdateAgentInformation", null); | ||
292 | m_HostCapsObj.RegisterHandler("UpdateAgentInformation", UpdateAgentInformationHandler); | 298 | m_HostCapsObj.RegisterHandler("UpdateAgentInformation", UpdateAgentInformationHandler); |
293 | 299 | ||
294 | m_HostCapsObj.RegisterHandler( | 300 | m_HostCapsObj.RegisterHandler( |
@@ -361,18 +367,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
361 | foreach (OSD c in capsRequested) | 367 | foreach (OSD c in capsRequested) |
362 | validCaps.Add(c.AsString()); | 368 | validCaps.Add(c.AsString()); |
363 | 369 | ||
364 | Hashtable caps = m_HostCapsObj.CapsHandlers.GetCapsDetails(true, validCaps); | 370 | 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 | 371 | ||
377 | //m_log.DebugFormat("[CAPS] CapsRequest {0}", result); | 372 | //m_log.DebugFormat("[CAPS] CapsRequest {0}", result); |
378 | 373 | ||
@@ -748,6 +743,10 @@ namespace OpenSim.Region.ClientStack.Linden | |||
748 | inType = (sbyte)InventoryType.Sound; | 743 | inType = (sbyte)InventoryType.Sound; |
749 | assType = (sbyte)AssetType.Sound; | 744 | assType = (sbyte)AssetType.Sound; |
750 | } | 745 | } |
746 | else if (inventoryType == "snapshot") | ||
747 | { | ||
748 | inType = (sbyte)InventoryType.Snapshot; | ||
749 | } | ||
751 | else if (inventoryType == "animation") | 750 | else if (inventoryType == "animation") |
752 | { | 751 | { |
753 | inType = (sbyte)InventoryType.Animation; | 752 | inType = (sbyte)InventoryType.Animation; |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs index eb40eb1..ffb53af 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs | |||
@@ -65,6 +65,13 @@ 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>(); |
@@ -84,7 +91,6 @@ namespace OpenSim.Region.ClientStack.Linden | |||
84 | scene.RegisterModuleInterface<IEventQueue>(this); | 91 | scene.RegisterModuleInterface<IEventQueue>(this); |
85 | 92 | ||
86 | scene.EventManager.OnClientClosed += ClientClosed; | 93 | scene.EventManager.OnClientClosed += ClientClosed; |
87 | scene.EventManager.OnMakeChildAgent += MakeChildAgent; | ||
88 | scene.EventManager.OnRegisterCaps += OnRegisterCaps; | 94 | scene.EventManager.OnRegisterCaps += OnRegisterCaps; |
89 | 95 | ||
90 | MainConsole.Instance.Commands.AddCommand( | 96 | MainConsole.Instance.Commands.AddCommand( |
@@ -113,7 +119,6 @@ namespace OpenSim.Region.ClientStack.Linden | |||
113 | return; | 119 | return; |
114 | 120 | ||
115 | scene.EventManager.OnClientClosed -= ClientClosed; | 121 | scene.EventManager.OnClientClosed -= ClientClosed; |
116 | scene.EventManager.OnMakeChildAgent -= MakeChildAgent; | ||
117 | scene.EventManager.OnRegisterCaps -= OnRegisterCaps; | 122 | scene.EventManager.OnRegisterCaps -= OnRegisterCaps; |
118 | 123 | ||
119 | scene.UnregisterModuleInterface<IEventQueue>(this); | 124 | scene.UnregisterModuleInterface<IEventQueue>(this); |
@@ -182,14 +187,12 @@ namespace OpenSim.Region.ClientStack.Linden | |||
182 | { | 187 | { |
183 | if (!queues.ContainsKey(agentId)) | 188 | if (!queues.ContainsKey(agentId)) |
184 | { | 189 | { |
185 | /* | ||
186 | m_log.DebugFormat( | 190 | m_log.DebugFormat( |
187 | "[EVENTQUEUE]: Adding new queue for agent {0} in region {1}", | 191 | "[EVENTQUEUE]: Adding new queue for agent {0} in region {1}", |
188 | agentId, m_scene.RegionInfo.RegionName); | 192 | agentId, m_scene.RegionInfo.RegionName); |
189 | */ | ||
190 | queues[agentId] = new Queue<OSD>(); | 193 | queues[agentId] = new Queue<OSD>(); |
191 | } | 194 | } |
192 | 195 | ||
193 | return queues[agentId]; | 196 | return queues[agentId]; |
194 | } | 197 | } |
195 | } | 198 | } |
@@ -221,8 +224,17 @@ namespace OpenSim.Region.ClientStack.Linden | |||
221 | { | 224 | { |
222 | Queue<OSD> queue = GetQueue(avatarID); | 225 | Queue<OSD> queue = GetQueue(avatarID); |
223 | if (queue != null) | 226 | if (queue != null) |
227 | { | ||
224 | lock (queue) | 228 | lock (queue) |
225 | queue.Enqueue(ev); | 229 | queue.Enqueue(ev); |
230 | } | ||
231 | else | ||
232 | { | ||
233 | OSDMap evMap = (OSDMap)ev; | ||
234 | m_log.WarnFormat( | ||
235 | "[EVENTQUEUE]: (Enqueue) No queue found for agent {0} when placing message {1} in region {2}", | ||
236 | avatarID, evMap["message"], m_scene.Name); | ||
237 | } | ||
226 | } | 238 | } |
227 | catch (NullReferenceException e) | 239 | catch (NullReferenceException e) |
228 | { | 240 | { |
@@ -237,44 +249,14 @@ namespace OpenSim.Region.ClientStack.Linden | |||
237 | 249 | ||
238 | private void ClientClosed(UUID agentID, Scene scene) | 250 | private void ClientClosed(UUID agentID, Scene scene) |
239 | { | 251 | { |
240 | // m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", agentID, m_scene.RegionInfo.RegionName); | 252 | //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 | 253 | ||
248 | lock (queues) | 254 | lock (queues) |
249 | { | ||
250 | queues.Remove(agentID); | 255 | queues.Remove(agentID); |
251 | } | ||
252 | 256 | ||
253 | List<UUID> removeitems = new List<UUID>(); | 257 | List<UUID> removeitems = new List<UUID>(); |
254 | lock (m_AvatarQueueUUIDMapping) | 258 | lock (m_AvatarQueueUUIDMapping) |
255 | { | 259 | 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 | |||
270 | string eqgPath = GenerateEqgCapPath(eventQueueGetUuid); | ||
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 | 260 | ||
279 | UUID searchval = UUID.Zero; | 261 | UUID searchval = UUID.Zero; |
280 | 262 | ||
@@ -295,19 +277,9 @@ namespace OpenSim.Region.ClientStack.Linden | |||
295 | foreach (UUID ky in removeitems) | 277 | foreach (UUID ky in removeitems) |
296 | m_QueueUUIDAvatarMapping.Remove(ky); | 278 | m_QueueUUIDAvatarMapping.Remove(ky); |
297 | } | 279 | } |
298 | } | ||
299 | 280 | ||
300 | private void MakeChildAgent(ScenePresence avatar) | 281 | // m_log.DebugFormat("[EVENTQUEUE]: Deleted queues for {0} in region {1}", agentID, m_scene.RegionInfo.RegionName); |
301 | { | 282 | |
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 | } | 283 | } |
312 | 284 | ||
313 | /// <summary> | 285 | /// <summary> |
@@ -323,9 +295,9 @@ namespace OpenSim.Region.ClientStack.Linden | |||
323 | { | 295 | { |
324 | // Register an event queue for the client | 296 | // Register an event queue for the client |
325 | 297 | ||
326 | //m_log.DebugFormat( | 298 | m_log.DebugFormat( |
327 | // "[EVENTQUEUE]: OnRegisterCaps: agentID {0} caps {1} region {2}", | 299 | "[EVENTQUEUE]: OnRegisterCaps: agentID {0} caps {1} region {2}", |
328 | // agentID, caps, m_scene.RegionInfo.RegionName); | 300 | agentID, caps, m_scene.RegionInfo.RegionName); |
329 | 301 | ||
330 | // Let's instantiate a Queue for this agent right now | 302 | // Let's instantiate a Queue for this agent right now |
331 | TryGetQueue(agentID); | 303 | TryGetQueue(agentID); |
@@ -359,28 +331,9 @@ namespace OpenSim.Region.ClientStack.Linden | |||
359 | m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID); | 331 | m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID); |
360 | } | 332 | } |
361 | 333 | ||
362 | string eventQueueGetPath = GenerateEqgCapPath(eventQueueGetUUID); | 334 | caps.RegisterPollHandler( |
363 | 335 | "EventQueueGet", | |
364 | // Register this as a caps handler | 336 | new PollServiceEventArgs(null, GenerateEqgCapPath(eventQueueGetUUID), HasEvents, GetEvents, NoEvents, agentID, SERVER_EQ_TIME_NO_EVENTS)); |
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 | 337 | ||
385 | Random rnd = new Random(Environment.TickCount); | 338 | Random rnd = new Random(Environment.TickCount); |
386 | lock (m_ids) | 339 | lock (m_ids) |
@@ -398,7 +351,10 @@ namespace OpenSim.Region.ClientStack.Linden | |||
398 | Queue<OSD> queue = GetQueue(agentID); | 351 | Queue<OSD> queue = GetQueue(agentID); |
399 | if (queue != null) | 352 | if (queue != null) |
400 | lock (queue) | 353 | lock (queue) |
354 | { | ||
355 | //m_log.WarnFormat("POLLED FOR EVENTS BY {0} in {1} -- {2}", agentID, m_scene.RegionInfo.RegionName, queue.Count); | ||
401 | return queue.Count > 0; | 356 | return queue.Count > 0; |
357 | } | ||
402 | 358 | ||
403 | return false; | 359 | return false; |
404 | } | 360 | } |
@@ -414,16 +370,21 @@ namespace OpenSim.Region.ClientStack.Linden | |||
414 | OSDMap ev = (OSDMap)element; | 370 | OSDMap ev = (OSDMap)element; |
415 | m_log.DebugFormat( | 371 | m_log.DebugFormat( |
416 | "Eq OUT {0,-30} to {1,-20} {2,-20}", | 372 | "Eq OUT {0,-30} to {1,-20} {2,-20}", |
417 | ev["message"], m_scene.GetScenePresence(agentId).Name, m_scene.RegionInfo.RegionName); | 373 | ev["message"], m_scene.GetScenePresence(agentId).Name, m_scene.Name); |
418 | } | 374 | } |
419 | } | 375 | } |
420 | 376 | ||
421 | public Hashtable GetEvents(UUID requestID, UUID pAgentId) | 377 | public Hashtable GetEvents(UUID requestID, UUID pAgentId) |
422 | { | 378 | { |
423 | if (DebugLevel >= 2) | 379 | if (DebugLevel >= 2) |
424 | m_log.DebugFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.RegionInfo.RegionName); | 380 | m_log.WarnFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.Name); |
381 | |||
382 | Queue<OSD> queue = GetQueue(pAgentId); | ||
383 | if (queue == null) | ||
384 | { | ||
385 | return NoEvents(requestID, pAgentId); | ||
386 | } | ||
425 | 387 | ||
426 | Queue<OSD> queue = TryGetQueue(pAgentId); | ||
427 | OSD element; | 388 | OSD element; |
428 | lock (queue) | 389 | lock (queue) |
429 | { | 390 | { |
@@ -750,34 +711,46 @@ namespace OpenSim.Region.ClientStack.Linden | |||
750 | Enqueue(item, avatarID); | 711 | Enqueue(item, avatarID); |
751 | } | 712 | } |
752 | 713 | ||
753 | public virtual void EnableSimulator(ulong handle, IPEndPoint endPoint, UUID avatarID) | 714 | public virtual void EnableSimulator(ulong handle, IPEndPoint endPoint, UUID avatarID, int regionSizeX, int regionSizeY) |
754 | { | 715 | { |
755 | OSD item = EventQueueHelper.EnableSimulator(handle, endPoint); | 716 | m_log.DebugFormat("{0} EnableSimulator. handle={1}, avatarID={2}, regionSize={3},{4}>", |
717 | "[EVENT QUEUE GET MODULE]", handle, avatarID, regionSizeX, regionSizeY); | ||
718 | |||
719 | OSD item = EventQueueHelper.EnableSimulator(handle, endPoint, regionSizeX, regionSizeY); | ||
756 | Enqueue(item, avatarID); | 720 | Enqueue(item, avatarID); |
757 | } | 721 | } |
758 | 722 | ||
759 | public virtual void EstablishAgentCommunication(UUID avatarID, IPEndPoint endPoint, string capsPath) | 723 | public virtual void EstablishAgentCommunication(UUID avatarID, IPEndPoint endPoint, string capsPath, |
724 | ulong regionHandle, int regionSizeX, int regionSizeY) | ||
760 | { | 725 | { |
761 | OSD item = EventQueueHelper.EstablishAgentCommunication(avatarID, endPoint.ToString(), capsPath); | 726 | m_log.DebugFormat("{0} EstablishAgentCommunication. handle={1}, avatarID={2}, regionSize={3},{4}>", |
727 | "[EVENT QUEUE GET MODULE]", regionHandle, avatarID, regionSizeX, regionSizeY); | ||
728 | OSD item = EventQueueHelper.EstablishAgentCommunication(avatarID, endPoint.ToString(), capsPath, regionHandle, regionSizeX, regionSizeY); | ||
762 | Enqueue(item, avatarID); | 729 | Enqueue(item, avatarID); |
763 | } | 730 | } |
764 | 731 | ||
765 | public virtual void TeleportFinishEvent(ulong regionHandle, byte simAccess, | 732 | public virtual void TeleportFinishEvent(ulong regionHandle, byte simAccess, |
766 | IPEndPoint regionExternalEndPoint, | 733 | IPEndPoint regionExternalEndPoint, |
767 | uint locationID, uint flags, string capsURL, | 734 | uint locationID, uint flags, string capsURL, |
768 | UUID avatarID) | 735 | UUID avatarID, int regionSizeX, int regionSizeY) |
769 | { | 736 | { |
737 | m_log.DebugFormat("{0} TeleportFinishEvent. handle={1}, avatarID={2}, regionSize={3},{4}>", | ||
738 | "[EVENT QUEUE GET MODULE]", regionHandle, avatarID, regionSizeX, regionSizeY); | ||
739 | |||
770 | OSD item = EventQueueHelper.TeleportFinishEvent(regionHandle, simAccess, regionExternalEndPoint, | 740 | OSD item = EventQueueHelper.TeleportFinishEvent(regionHandle, simAccess, regionExternalEndPoint, |
771 | locationID, flags, capsURL, avatarID); | 741 | locationID, flags, capsURL, avatarID, regionSizeX, regionSizeY); |
772 | Enqueue(item, avatarID); | 742 | Enqueue(item, avatarID); |
773 | } | 743 | } |
774 | 744 | ||
775 | public virtual void CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt, | 745 | public virtual void CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt, |
776 | IPEndPoint newRegionExternalEndPoint, | 746 | IPEndPoint newRegionExternalEndPoint, |
777 | string capsURL, UUID avatarID, UUID sessionID) | 747 | string capsURL, UUID avatarID, UUID sessionID, int regionSizeX, int regionSizeY) |
778 | { | 748 | { |
749 | m_log.DebugFormat("{0} CrossRegion. handle={1}, avatarID={2}, regionSize={3},{4}>", | ||
750 | "[EVENT QUEUE GET MODULE]", handle, avatarID, regionSizeX, regionSizeY); | ||
751 | |||
779 | OSD item = EventQueueHelper.CrossRegion(handle, pos, lookAt, newRegionExternalEndPoint, | 752 | OSD item = EventQueueHelper.CrossRegion(handle, pos, lookAt, newRegionExternalEndPoint, |
780 | capsURL, avatarID, sessionID); | 753 | capsURL, avatarID, sessionID, regionSizeX, regionSizeY); |
781 | Enqueue(item, avatarID); | 754 | Enqueue(item, avatarID); |
782 | } | 755 | } |
783 | 756 | ||
@@ -794,12 +767,12 @@ namespace OpenSim.Region.ClientStack.Linden | |||
794 | 767 | ||
795 | } | 768 | } |
796 | 769 | ||
797 | public void ChatterBoxSessionAgentListUpdates(UUID sessionID, UUID fromAgent, UUID toAgent, bool canVoiceChat, | 770 | public void ChatterBoxSessionAgentListUpdates(UUID sessionID, UUID fromAgent, UUID anotherAgent, bool canVoiceChat, |
798 | bool isModerator, bool textMute) | 771 | bool isModerator, bool textMute) |
799 | { | 772 | { |
800 | OSD item = EventQueueHelper.ChatterBoxSessionAgentListUpdates(sessionID, fromAgent, canVoiceChat, | 773 | OSD item = EventQueueHelper.ChatterBoxSessionAgentListUpdates(sessionID, fromAgent, canVoiceChat, |
801 | isModerator, textMute); | 774 | isModerator, textMute); |
802 | Enqueue(item, toAgent); | 775 | Enqueue(item, fromAgent); |
803 | //m_log.InfoFormat("########### eq ChatterBoxSessionAgentListUpdates #############\n{0}", item); | 776 | //m_log.InfoFormat("########### eq ChatterBoxSessionAgentListUpdates #############\n{0}", item); |
804 | } | 777 | } |
805 | 778 | ||
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..47988dd 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); |
@@ -280,23 +287,28 @@ namespace OpenSim.Region.ClientStack.Linden | |||
280 | 287 | ||
281 | public void RegisterCaps(UUID agentID, Caps caps) | 288 | public void RegisterCaps(UUID agentID, Caps caps) |
282 | { | 289 | { |
283 | UploadBakedTextureHandler avatarhandler = new UploadBakedTextureHandler( | 290 | // UUID capID = UUID.Random(); |
284 | caps, m_scene.AssetService, m_persistBakedTextures); | ||
285 | 291 | ||
286 | 292 | //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture)); | |
287 | 293 | if (m_URL == "localhost") | |
288 | caps.RegisterHandler( | 294 | { |
289 | "UploadBakedTexture", | 295 | UploadBakedTextureHandler avatarhandler = new UploadBakedTextureHandler( |
290 | new RestStreamHandler( | 296 | caps, m_scene.AssetService, m_persistBakedTextures); |
291 | "POST", | ||
292 | "/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath, | ||
293 | avatarhandler.UploadBakedTexture, | ||
294 | "UploadBakedTexture", | ||
295 | agentID.ToString())); | ||
296 | |||
297 | |||
298 | |||
299 | 297 | ||
298 | caps.RegisterHandler( | ||
299 | "UploadBakedTexture", | ||
300 | new RestStreamHandler( | ||
301 | "POST", | ||
302 | "/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath, | ||
303 | avatarhandler.UploadBakedTexture, | ||
304 | "UploadBakedTexture", | ||
305 | agentID.ToString())); | ||
306 | |||
307 | } | ||
308 | else | ||
309 | { | ||
310 | caps.RegisterHandler("UploadBakedTexture", m_URL); | ||
311 | } | ||
300 | } | 312 | } |
301 | } | 313 | } |
302 | } \ No newline at end of file | 314 | } |
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 7c62f90..f599342 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 |
@@ -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 |
@@ -504,6 +507,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
504 | m_udpServer = udpServer; | 507 | m_udpServer = udpServer; |
505 | m_udpClient = udpClient; | 508 | m_udpClient = udpClient; |
506 | m_udpClient.OnQueueEmpty += HandleQueueEmpty; | 509 | m_udpClient.OnQueueEmpty += HandleQueueEmpty; |
510 | m_udpClient.HasUpdates += HandleHasUpdates; | ||
507 | m_udpClient.OnPacketStats += PopulateStats; | 511 | m_udpClient.OnPacketStats += PopulateStats; |
508 | 512 | ||
509 | m_prioritizer = new Prioritizer(m_scene); | 513 | m_prioritizer = new Prioritizer(m_scene); |
@@ -533,7 +537,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 | 537 | // 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 | 538 | // there is some unidentified connection problem, not where we have issues due to deadlock |
535 | if (!IsActive && !force) | 539 | if (!IsActive && !force) |
540 | { | ||
541 | m_log.DebugFormat( | ||
542 | "[CLIENT]: Not attempting to close inactive client {0} in {1} since force flag is not set", | ||
543 | Name, m_scene.Name); | ||
544 | |||
536 | return; | 545 | return; |
546 | } | ||
537 | 547 | ||
538 | IsActive = false; | 548 | IsActive = false; |
539 | CloseWithoutChecks(sendStop); | 549 | CloseWithoutChecks(sendStop); |
@@ -709,12 +719,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
709 | //there is a local handler for this packet type | 719 | //there is a local handler for this packet type |
710 | if (pprocessor.Async) | 720 | if (pprocessor.Async) |
711 | { | 721 | { |
722 | ClientInfo cinfo = UDPClient.GetClientInfo(); | ||
723 | if (!cinfo.AsyncRequests.ContainsKey(packet.Type.ToString())) | ||
724 | cinfo.AsyncRequests[packet.Type.ToString()] = 0; | ||
725 | cinfo.AsyncRequests[packet.Type.ToString()]++; | ||
726 | |||
712 | object obj = new AsyncPacketProcess(this, pprocessor.method, packet); | 727 | object obj = new AsyncPacketProcess(this, pprocessor.method, packet); |
713 | Util.FireAndForget(ProcessSpecificPacketAsync, obj); | 728 | Util.FireAndForget(ProcessSpecificPacketAsync, obj); |
714 | result = true; | 729 | result = true; |
715 | } | 730 | } |
716 | else | 731 | else |
717 | { | 732 | { |
733 | ClientInfo cinfo = UDPClient.GetClientInfo(); | ||
734 | if (!cinfo.SyncRequests.ContainsKey(packet.Type.ToString())) | ||
735 | cinfo.SyncRequests[packet.Type.ToString()] = 0; | ||
736 | cinfo.SyncRequests[packet.Type.ToString()]++; | ||
737 | |||
718 | result = pprocessor.method(this, packet); | 738 | result = pprocessor.method(this, packet); |
719 | } | 739 | } |
720 | } | 740 | } |
@@ -729,6 +749,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
729 | } | 749 | } |
730 | if (found) | 750 | if (found) |
731 | { | 751 | { |
752 | ClientInfo cinfo = UDPClient.GetClientInfo(); | ||
753 | if (!cinfo.GenericRequests.ContainsKey(packet.Type.ToString())) | ||
754 | cinfo.GenericRequests[packet.Type.ToString()] = 0; | ||
755 | cinfo.GenericRequests[packet.Type.ToString()]++; | ||
756 | |||
732 | result = method(this, packet); | 757 | result = method(this, packet); |
733 | } | 758 | } |
734 | } | 759 | } |
@@ -758,7 +783,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
758 | 783 | ||
759 | public virtual void Start() | 784 | public virtual void Start() |
760 | { | 785 | { |
761 | m_scene.AddNewClient(this, PresenceType.User); | 786 | m_scene.AddNewAgent(this, PresenceType.User); |
762 | 787 | ||
763 | RefreshGroupMembership(); | 788 | RefreshGroupMembership(); |
764 | } | 789 | } |
@@ -820,12 +845,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
820 | handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType); | 845 | handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType); |
821 | handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes; | 846 | handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes; |
822 | 847 | ||
823 | handshake.RegionInfo4 = new RegionHandshakePacket.RegionInfo4Block[0]; | 848 | handshake.RegionInfo4 = new RegionHandshakePacket.RegionInfo4Block[1]; |
824 | // OutPacket(handshake, ThrottleOutPacketType.Task); | 849 | handshake.RegionInfo4[0] = new RegionHandshakePacket.RegionInfo4Block(); |
825 | // use same as MoveAgentIntoRegion (both should be task ) | 850 | handshake.RegionInfo4[0].RegionFlagsExtended = args.regionFlags; |
851 | handshake.RegionInfo4[0].RegionProtocols = 0; // 1 here would indicate that SSB is supported | ||
852 | |||
826 | OutPacket(handshake, ThrottleOutPacketType.Unknown); | 853 | OutPacket(handshake, ThrottleOutPacketType.Unknown); |
827 | } | 854 | } |
828 | 855 | ||
856 | |||
829 | public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look) | 857 | public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look) |
830 | { | 858 | { |
831 | AgentMovementCompletePacket mov = (AgentMovementCompletePacket)PacketPool.Instance.GetPacket(PacketType.AgentMovementComplete); | 859 | AgentMovementCompletePacket mov = (AgentMovementCompletePacket)PacketPool.Instance.GetPacket(PacketType.AgentMovementComplete); |
@@ -1210,9 +1238,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1210 | LLHeightFieldMoronize(map); | 1238 | LLHeightFieldMoronize(map); |
1211 | 1239 | ||
1212 | LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); | 1240 | LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); |
1213 | layerpack.Header.Reliable = true; | 1241 | |
1242 | // When a user edits the terrain, so much data is sent, the data queues up fast and presents a sub optimal editing experience. | ||
1243 | // To alleviate this issue, when the user edits the terrain, we start skipping the queues until they're done editing the terrain. | ||
1244 | // We also make them unreliable because it's extremely likely that multiple packets will be sent for a terrain patch area | ||
1245 | // invalidating previous packets for that area. | ||
1246 | |||
1247 | // It's possible for an editing user to flood themselves with edited packets but the majority of use cases are such that only a | ||
1248 | // tiny percentage of users will be editing the terrain. Other, non-editing users will see the edits much slower. | ||
1249 | |||
1250 | // 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 | ||
1251 | // have rezzed already and therefore this is not likely going to cause any additional issues with lost packets, objects or terrain | ||
1252 | // patches. | ||
1214 | 1253 | ||
1215 | OutPacket(layerpack, ThrottleOutPacketType.Task); | 1254 | // m_justEditedTerrain is volatile, so test once and duplicate two affected statements so we only have one cache miss. |
1255 | if (m_justEditedTerrain) | ||
1256 | { | ||
1257 | layerpack.Header.Reliable = false; | ||
1258 | OutPacket(layerpack, | ||
1259 | ThrottleOutPacketType.Unknown ); | ||
1260 | } | ||
1261 | else | ||
1262 | { | ||
1263 | layerpack.Header.Reliable = true; | ||
1264 | OutPacket(layerpack, | ||
1265 | ThrottleOutPacketType.Task); | ||
1266 | } | ||
1216 | } | 1267 | } |
1217 | catch (Exception e) | 1268 | catch (Exception e) |
1218 | { | 1269 | { |
@@ -1405,6 +1456,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1405 | 1456 | ||
1406 | mapReply.AgentData.AgentID = AgentId; | 1457 | mapReply.AgentData.AgentID = AgentId; |
1407 | mapReply.Data = new MapBlockReplyPacket.DataBlock[mapBlocks2.Length]; | 1458 | mapReply.Data = new MapBlockReplyPacket.DataBlock[mapBlocks2.Length]; |
1459 | mapReply.Size = new MapBlockReplyPacket.SizeBlock[mapBlocks2.Length]; | ||
1408 | mapReply.AgentData.Flags = flag; | 1460 | mapReply.AgentData.Flags = flag; |
1409 | 1461 | ||
1410 | for (int i = 0; i < mapBlocks2.Length; i++) | 1462 | for (int i = 0; i < mapBlocks2.Length; i++) |
@@ -1419,6 +1471,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1419 | mapReply.Data[i].RegionFlags = mapBlocks2[i].RegionFlags; | 1471 | mapReply.Data[i].RegionFlags = mapBlocks2[i].RegionFlags; |
1420 | mapReply.Data[i].Access = mapBlocks2[i].Access; | 1472 | mapReply.Data[i].Access = mapBlocks2[i].Access; |
1421 | mapReply.Data[i].Agents = mapBlocks2[i].Agents; | 1473 | mapReply.Data[i].Agents = mapBlocks2[i].Agents; |
1474 | |||
1475 | // TODO: hookup varregion sim size here | ||
1476 | mapReply.Size[i] = new MapBlockReplyPacket.SizeBlock(); | ||
1477 | mapReply.Size[i].SizeX = 256; | ||
1478 | mapReply.Size[i].SizeY = 256; | ||
1422 | } | 1479 | } |
1423 | OutPacket(mapReply, ThrottleOutPacketType.Land); | 1480 | OutPacket(mapReply, ThrottleOutPacketType.Land); |
1424 | } | 1481 | } |
@@ -1580,7 +1637,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1580 | OutPacket(pc, ThrottleOutPacketType.Unknown); | 1637 | OutPacket(pc, ThrottleOutPacketType.Unknown); |
1581 | } | 1638 | } |
1582 | 1639 | ||
1583 | public void SendKillObject(ulong regionHandle, List<uint> localIDs) | 1640 | public void SendKillObject(List<uint> localIDs) |
1584 | { | 1641 | { |
1585 | // foreach (uint id in localIDs) | 1642 | // foreach (uint id in localIDs) |
1586 | // m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle); | 1643 | // m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle); |
@@ -2594,11 +2651,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2594 | { | 2651 | { |
2595 | AvatarSitResponsePacket avatarSitResponse = new AvatarSitResponsePacket(); | 2652 | AvatarSitResponsePacket avatarSitResponse = new AvatarSitResponsePacket(); |
2596 | avatarSitResponse.SitObject.ID = TargetID; | 2653 | avatarSitResponse.SitObject.ID = TargetID; |
2597 | if (CameraAtOffset != Vector3.Zero) | 2654 | avatarSitResponse.SitTransform.CameraAtOffset = CameraAtOffset; |
2598 | { | 2655 | avatarSitResponse.SitTransform.CameraEyeOffset = CameraEyeOffset; |
2599 | avatarSitResponse.SitTransform.CameraAtOffset = CameraAtOffset; | ||
2600 | avatarSitResponse.SitTransform.CameraEyeOffset = CameraEyeOffset; | ||
2601 | } | ||
2602 | avatarSitResponse.SitTransform.ForceMouselook = ForceMouseLook; | 2656 | avatarSitResponse.SitTransform.ForceMouselook = ForceMouseLook; |
2603 | avatarSitResponse.SitTransform.AutoPilot = autopilot; | 2657 | avatarSitResponse.SitTransform.AutoPilot = autopilot; |
2604 | avatarSitResponse.SitTransform.SitPosition = OffsetPos; | 2658 | avatarSitResponse.SitTransform.SitPosition = OffsetPos; |
@@ -3794,12 +3848,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3794 | m_udpClient.NeedAcks.Remove(oPacket.SequenceNumber); | 3848 | m_udpClient.NeedAcks.Remove(oPacket.SequenceNumber); |
3795 | 3849 | ||
3796 | // Count this as a resent packet since we are going to requeue all of the updates contained in it | 3850 | // Count this as a resent packet since we are going to requeue all of the updates contained in it |
3797 | Interlocked.Increment(ref m_udpClient.PacketsResent); | 3851 | Interlocked.Increment(ref m_udpClient.PacketsResent); |
3852 | |||
3853 | // We're not going to worry about interlock yet since its not currently critical that this total count | ||
3854 | // is 100% correct | ||
3855 | m_udpServer.PacketsResentCount++; | ||
3798 | 3856 | ||
3799 | foreach (EntityUpdate update in updates) | 3857 | foreach (EntityUpdate update in updates) |
3800 | ResendPrimUpdate(update); | 3858 | ResendPrimUpdate(update); |
3801 | } | 3859 | } |
3802 | 3860 | ||
3861 | // OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>(); | ||
3862 | // OpenSim.Framework.Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>> compressedUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>>(); | ||
3863 | // OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>(); | ||
3864 | // OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>(); | ||
3865 | // | ||
3866 | // OpenSim.Framework.Lazy<List<EntityUpdate>> objectUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); | ||
3867 | // OpenSim.Framework.Lazy<List<EntityUpdate>> compressedUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); | ||
3868 | // OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); | ||
3869 | // OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); | ||
3870 | |||
3871 | |||
3803 | private void ProcessEntityUpdates(int maxUpdates) | 3872 | private void ProcessEntityUpdates(int maxUpdates) |
3804 | { | 3873 | { |
3805 | OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>(); | 3874 | OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>(); |
@@ -3812,6 +3881,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3812 | OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); | 3881 | 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>>(); | 3882 | OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); |
3814 | 3883 | ||
3884 | // objectUpdateBlocks.Value.Clear(); | ||
3885 | // compressedUpdateBlocks.Value.Clear(); | ||
3886 | // terseUpdateBlocks.Value.Clear(); | ||
3887 | // terseAgentUpdateBlocks.Value.Clear(); | ||
3888 | // objectUpdates.Value.Clear(); | ||
3889 | // compressedUpdates.Value.Clear(); | ||
3890 | // terseUpdates.Value.Clear(); | ||
3891 | // terseAgentUpdates.Value.Clear(); | ||
3892 | |||
3815 | // Check to see if this is a flush | 3893 | // Check to see if this is a flush |
3816 | if (maxUpdates <= 0) | 3894 | if (maxUpdates <= 0) |
3817 | { | 3895 | { |
@@ -4140,8 +4218,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4140 | 4218 | ||
4141 | void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories) | 4219 | void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories) |
4142 | { | 4220 | { |
4221 | // if (!m_udpServer.IsRunningOutbound) | ||
4222 | // return; | ||
4223 | |||
4143 | if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) | 4224 | if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) |
4144 | { | 4225 | { |
4226 | // if (!m_udpServer.IsRunningOutbound) | ||
4227 | // return; | ||
4228 | |||
4145 | if (m_maxUpdates == 0 || m_LastQueueFill == 0) | 4229 | if (m_maxUpdates == 0 || m_LastQueueFill == 0) |
4146 | { | 4230 | { |
4147 | m_maxUpdates = m_udpServer.PrimUpdatesPerCallback; | 4231 | m_maxUpdates = m_udpServer.PrimUpdatesPerCallback; |
@@ -4167,6 +4251,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4167 | ImageManager.ProcessImageQueue(m_udpServer.TextureSendLimit); | 4251 | ImageManager.ProcessImageQueue(m_udpServer.TextureSendLimit); |
4168 | } | 4252 | } |
4169 | 4253 | ||
4254 | internal bool HandleHasUpdates(ThrottleOutPacketTypeFlags categories) | ||
4255 | { | ||
4256 | bool hasUpdates = false; | ||
4257 | |||
4258 | if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) | ||
4259 | { | ||
4260 | if (m_entityUpdates.Count > 0) | ||
4261 | hasUpdates = true; | ||
4262 | else if (m_entityProps.Count > 0) | ||
4263 | hasUpdates = true; | ||
4264 | } | ||
4265 | |||
4266 | if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0) | ||
4267 | { | ||
4268 | if (ImageManager.HasUpdates()) | ||
4269 | hasUpdates = true; | ||
4270 | } | ||
4271 | |||
4272 | return hasUpdates; | ||
4273 | } | ||
4274 | |||
4170 | public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID) | 4275 | public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID) |
4171 | { | 4276 | { |
4172 | AssetUploadCompletePacket newPack = new AssetUploadCompletePacket(); | 4277 | AssetUploadCompletePacket newPack = new AssetUploadCompletePacket(); |
@@ -4312,6 +4417,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 | 4417 | // 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); | 4418 | Interlocked.Increment(ref m_udpClient.PacketsResent); |
4314 | 4419 | ||
4420 | // We're not going to worry about interlock yet since its not currently critical that this total count | ||
4421 | // is 100% correct | ||
4422 | m_udpServer.PacketsResentCount++; | ||
4423 | |||
4315 | foreach (ObjectPropertyUpdate update in updates) | 4424 | foreach (ObjectPropertyUpdate update in updates) |
4316 | ResendPropertyUpdate(update); | 4425 | ResendPropertyUpdate(update); |
4317 | } | 4426 | } |
@@ -4499,6 +4608,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4499 | SceneObjectPart root = sop.ParentGroup.RootPart; | 4608 | SceneObjectPart root = sop.ParentGroup.RootPart; |
4500 | 4609 | ||
4501 | block.TouchName = Util.StringToBytes256(root.TouchName); | 4610 | block.TouchName = Util.StringToBytes256(root.TouchName); |
4611 | |||
4612 | // SL 3.3.4, at least, appears to read this information as a concatenated byte[] stream of UUIDs but | ||
4613 | // it's not yet clear whether this is actually used. If this is done in the future then a pre-cached | ||
4614 | // copy is really needed since it's less efficient to be constantly recreating this byte array. | ||
4615 | // using (MemoryStream memStream = new MemoryStream()) | ||
4616 | // { | ||
4617 | // using (BinaryWriter binWriter = new BinaryWriter(memStream)) | ||
4618 | // { | ||
4619 | // for (int i = 0; i < sop.GetNumberOfSides(); i++) | ||
4620 | // { | ||
4621 | // Primitive.TextureEntryFace teFace = sop.Shape.Textures.FaceTextures[i]; | ||
4622 | // | ||
4623 | // UUID textureID; | ||
4624 | // | ||
4625 | // if (teFace != null) | ||
4626 | // textureID = teFace.TextureID; | ||
4627 | // else | ||
4628 | // textureID = sop.Shape.Textures.DefaultTexture.TextureID; | ||
4629 | // | ||
4630 | // binWriter.Write(textureID.GetBytes()); | ||
4631 | // } | ||
4632 | // | ||
4633 | // block.TextureID = memStream.ToArray(); | ||
4634 | // } | ||
4635 | // } | ||
4636 | |||
4502 | block.TextureID = new byte[0]; // TextureID ??? | 4637 | block.TextureID = new byte[0]; // TextureID ??? |
4503 | block.SitName = Util.StringToBytes256(root.SitName); | 4638 | block.SitName = Util.StringToBytes256(root.SitName); |
4504 | block.OwnerMask = root.OwnerMask; | 4639 | block.OwnerMask = root.OwnerMask; |
@@ -4877,7 +5012,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4877 | 5012 | ||
4878 | public void SendForceClientSelectObjects(List<uint> ObjectIDs) | 5013 | public void SendForceClientSelectObjects(List<uint> ObjectIDs) |
4879 | { | 5014 | { |
4880 | m_log.WarnFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count); | 5015 | // m_log.DebugFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count); |
4881 | 5016 | ||
4882 | bool firstCall = true; | 5017 | bool firstCall = true; |
4883 | const int MAX_OBJECTS_PER_PACKET = 251; | 5018 | const int MAX_OBJECTS_PER_PACKET = 251; |
@@ -5015,15 +5150,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5015 | } | 5150 | } |
5016 | 5151 | ||
5017 | attachPoint = 0; | 5152 | attachPoint = 0; |
5153 | // m_log.DebugFormat( | ||
5154 | // "[LLCLIENTVIEW]: Sending terse update to {0} with position {1} in {2}", Name, presence.OffsetPosition, m_scene.Name); | ||
5155 | |||
5156 | // attachPoint = presence.State; // Core: commented | ||
5018 | collisionPlane = presence.CollisionPlane; | 5157 | collisionPlane = presence.CollisionPlane; |
5019 | velocity = presence.Velocity; | 5158 | velocity = presence.Velocity; |
5020 | acceleration = Vector3.Zero; | 5159 | acceleration = Vector3.Zero; |
5021 | 5160 | ||
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) | 5161 | if (sendTexture) |
5028 | textureEntry = presence.Appearance.Texture.GetBytes(); | 5162 | textureEntry = presence.Appearance.Texture.GetBytes(); |
5029 | else | 5163 | else |
@@ -5034,7 +5168,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5034 | SceneObjectPart part = (SceneObjectPart)entity; | 5168 | SceneObjectPart part = (SceneObjectPart)entity; |
5035 | 5169 | ||
5036 | attachPoint = part.ParentGroup.AttachmentPoint; | 5170 | attachPoint = part.ParentGroup.AttachmentPoint; |
5037 | 5171 | attachPoint = ((attachPoint % 16) * 16 + (attachPoint / 16)); | |
5038 | // m_log.DebugFormat( | 5172 | // m_log.DebugFormat( |
5039 | // "[LLCLIENTVIEW]: Sending attachPoint {0} for {1} {2} to {3}", | 5173 | // "[LLCLIENTVIEW]: Sending attachPoint {0} for {1} {2} to {3}", |
5040 | // attachPoint, part.Name, part.LocalId, Name); | 5174 | // attachPoint, part.Name, part.LocalId, Name); |
@@ -5062,7 +5196,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5062 | pos += 4; | 5196 | pos += 4; |
5063 | 5197 | ||
5064 | // Avatar/CollisionPlane | 5198 | // Avatar/CollisionPlane |
5065 | data[pos++] = (byte)((attachPoint % 16) * 16 + (attachPoint / 16)); ; | 5199 | data[pos++] = (byte) attachPoint; |
5066 | if (avatar) | 5200 | if (avatar) |
5067 | { | 5201 | { |
5068 | data[pos++] = 1; | 5202 | data[pos++] = 1; |
@@ -5143,6 +5277,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5143 | parentID = part.ParentGroup.RootPart.LocalId; | 5277 | parentID = part.ParentGroup.RootPart.LocalId; |
5144 | } | 5278 | } |
5145 | } | 5279 | } |
5280 | // m_log.DebugFormat( | ||
5281 | // "[LLCLIENTVIEW]: Sending full update to {0} with position {1} in {2}", Name, data.OffsetPosition, m_scene.Name); | ||
5146 | 5282 | ||
5147 | byte[] objectData = new byte[76]; | 5283 | byte[] objectData = new byte[76]; |
5148 | 5284 | ||
@@ -5168,7 +5304,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5168 | update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " + | 5304 | update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " + |
5169 | data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle); | 5305 | data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle); |
5170 | update.ObjectData = objectData; | 5306 | update.ObjectData = objectData; |
5171 | update.ParentID = parentID; | 5307 | |
5308 | SceneObjectPart parentPart = data.ParentPart; | ||
5309 | if (parentPart != null) | ||
5310 | update.ParentID = parentPart.ParentGroup.LocalId; | ||
5311 | else | ||
5312 | update.ParentID = 0; | ||
5313 | |||
5172 | update.PathCurve = 16; | 5314 | update.PathCurve = 16; |
5173 | update.PathScaleX = 100; | 5315 | update.PathScaleX = 100; |
5174 | update.PathScaleY = 100; | 5316 | update.PathScaleY = 100; |
@@ -5387,7 +5529,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5387 | AddLocalPacketHandler(PacketType.RezObject, HandlerRezObject); | 5529 | AddLocalPacketHandler(PacketType.RezObject, HandlerRezObject); |
5388 | AddLocalPacketHandler(PacketType.DeRezObject, HandlerDeRezObject); | 5530 | AddLocalPacketHandler(PacketType.DeRezObject, HandlerDeRezObject); |
5389 | AddLocalPacketHandler(PacketType.ModifyLand, HandlerModifyLand); | 5531 | AddLocalPacketHandler(PacketType.ModifyLand, HandlerModifyLand); |
5390 | AddLocalPacketHandler(PacketType.RegionHandshakeReply, HandlerRegionHandshakeReply); | 5532 | AddLocalPacketHandler(PacketType.RegionHandshakeReply, HandlerRegionHandshakeReply, false); |
5391 | AddLocalPacketHandler(PacketType.AgentWearablesRequest, HandlerAgentWearablesRequest); | 5533 | AddLocalPacketHandler(PacketType.AgentWearablesRequest, HandlerAgentWearablesRequest); |
5392 | AddLocalPacketHandler(PacketType.AgentSetAppearance, HandlerAgentSetAppearance); | 5534 | AddLocalPacketHandler(PacketType.AgentSetAppearance, HandlerAgentSetAppearance); |
5393 | AddLocalPacketHandler(PacketType.AgentIsNowWearing, HandlerAgentIsNowWearing); | 5535 | AddLocalPacketHandler(PacketType.AgentIsNowWearing, HandlerAgentIsNowWearing); |
@@ -5448,8 +5590,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5448 | AddLocalPacketHandler(PacketType.ScriptAnswerYes, HandleScriptAnswerYes, false); | 5590 | AddLocalPacketHandler(PacketType.ScriptAnswerYes, HandleScriptAnswerYes, false); |
5449 | AddLocalPacketHandler(PacketType.ObjectClickAction, HandleObjectClickAction, false); | 5591 | AddLocalPacketHandler(PacketType.ObjectClickAction, HandleObjectClickAction, false); |
5450 | AddLocalPacketHandler(PacketType.ObjectMaterial, HandleObjectMaterial, false); | 5592 | AddLocalPacketHandler(PacketType.ObjectMaterial, HandleObjectMaterial, false); |
5451 | AddLocalPacketHandler(PacketType.RequestImage, HandleRequestImage); | 5593 | AddLocalPacketHandler(PacketType.RequestImage, HandleRequestImage, false); |
5452 | AddLocalPacketHandler(PacketType.TransferRequest, HandleTransferRequest); | 5594 | AddLocalPacketHandler(PacketType.TransferRequest, HandleTransferRequest, false); |
5453 | AddLocalPacketHandler(PacketType.AssetUploadRequest, HandleAssetUploadRequest); | 5595 | AddLocalPacketHandler(PacketType.AssetUploadRequest, HandleAssetUploadRequest); |
5454 | AddLocalPacketHandler(PacketType.RequestXfer, HandleRequestXfer); | 5596 | AddLocalPacketHandler(PacketType.RequestXfer, HandleRequestXfer); |
5455 | AddLocalPacketHandler(PacketType.SendXferPacket, HandleSendXferPacket); | 5597 | AddLocalPacketHandler(PacketType.SendXferPacket, HandleSendXferPacket); |
@@ -5481,7 +5623,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5481 | AddLocalPacketHandler(PacketType.TeleportCancel, HandleTeleportCancel); | 5623 | AddLocalPacketHandler(PacketType.TeleportCancel, HandleTeleportCancel); |
5482 | AddLocalPacketHandler(PacketType.TeleportLocationRequest, HandleTeleportLocationRequest); | 5624 | AddLocalPacketHandler(PacketType.TeleportLocationRequest, HandleTeleportLocationRequest); |
5483 | AddLocalPacketHandler(PacketType.UUIDNameRequest, HandleUUIDNameRequest, false); | 5625 | AddLocalPacketHandler(PacketType.UUIDNameRequest, HandleUUIDNameRequest, false); |
5484 | AddLocalPacketHandler(PacketType.RegionHandleRequest, HandleRegionHandleRequest); | 5626 | AddLocalPacketHandler(PacketType.RegionHandleRequest, HandleRegionHandleRequest, false); |
5485 | AddLocalPacketHandler(PacketType.ParcelInfoRequest, HandleParcelInfoRequest); | 5627 | AddLocalPacketHandler(PacketType.ParcelInfoRequest, HandleParcelInfoRequest); |
5486 | AddLocalPacketHandler(PacketType.ParcelAccessListRequest, HandleParcelAccessListRequest, false); | 5628 | AddLocalPacketHandler(PacketType.ParcelAccessListRequest, HandleParcelAccessListRequest, false); |
5487 | AddLocalPacketHandler(PacketType.ParcelAccessListUpdate, HandleParcelAccessListUpdate, false); | 5629 | AddLocalPacketHandler(PacketType.ParcelAccessListUpdate, HandleParcelAccessListUpdate, false); |
@@ -5594,83 +5736,137 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5594 | 5736 | ||
5595 | #region Packet Handlers | 5737 | #region Packet Handlers |
5596 | 5738 | ||
5739 | public int TotalAgentUpdates { get; set; } | ||
5740 | |||
5597 | #region Scene/Avatar | 5741 | #region Scene/Avatar |
5598 | 5742 | ||
5599 | private bool HandleAgentUpdate(IClientAPI sener, Packet packet) | 5743 | // Threshold for body rotation to be a significant agent update |
5744 | private const float QDELTA = 0.000001f; | ||
5745 | // Threshold for camera rotation to be a significant agent update | ||
5746 | private const float VDELTA = 0.01f; | ||
5747 | |||
5748 | /// <summary> | ||
5749 | /// This checks the update significance against the last update made. | ||
5750 | /// </summary> | ||
5751 | /// <remarks>Can only be called by one thread at a time</remarks> | ||
5752 | /// <returns></returns> | ||
5753 | /// <param name='x'></param> | ||
5754 | public bool CheckAgentUpdateSignificance(AgentUpdatePacket.AgentDataBlock x) | ||
5600 | { | 5755 | { |
5601 | if (OnAgentUpdate != null) | 5756 | return CheckAgentMovementUpdateSignificance(x) || CheckAgentCameraUpdateSignificance(x); |
5602 | { | 5757 | } |
5603 | AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet; | ||
5604 | 5758 | ||
5605 | #region Packet Session and User Check | 5759 | /// <summary> |
5606 | if (agentUpdate.AgentData.SessionID != SessionId || agentUpdate.AgentData.AgentID != AgentId) | 5760 | /// This checks the movement/state update significance against the last update made. |
5607 | { | 5761 | /// </summary> |
5608 | PacketPool.Instance.ReturnPacket(packet); | 5762 | /// <remarks>Can only be called by one thread at a time</remarks> |
5609 | return false; | 5763 | /// <returns></returns> |
5610 | } | 5764 | /// <param name='x'></param> |
5611 | #endregion | 5765 | private bool CheckAgentMovementUpdateSignificance(AgentUpdatePacket.AgentDataBlock x) |
5766 | { | ||
5767 | float qdelta1 = 1 - (float)Math.Pow(Quaternion.Dot(x.BodyRotation, m_thisAgentUpdateArgs.BodyRotation), 2); | ||
5768 | //qdelta2 = 1 - (float)Math.Pow(Quaternion.Dot(x.HeadRotation, m_thisAgentUpdateArgs.HeadRotation), 2); | ||
5769 | |||
5770 | bool movementSignificant = | ||
5771 | (qdelta1 > QDELTA) // significant if body rotation above threshold | ||
5772 | // Ignoring head rotation altogether, because it's not being used for anything interesting up the stack | ||
5773 | // || (qdelta2 > QDELTA * 10) // significant if head rotation above threshold | ||
5774 | || (x.ControlFlags != m_thisAgentUpdateArgs.ControlFlags) // significant if control flags changed | ||
5775 | || (x.ControlFlags != (byte)AgentManager.ControlFlags.NONE) // significant if user supplying any movement update commands | ||
5776 | || (x.Far != m_thisAgentUpdateArgs.Far) // significant if far distance changed | ||
5777 | || (x.Flags != m_thisAgentUpdateArgs.Flags) // significant if Flags changed | ||
5778 | || (x.State != m_thisAgentUpdateArgs.State) // significant if Stats changed | ||
5779 | ; | ||
5780 | //if (movementSignificant) | ||
5781 | //{ | ||
5782 | //m_log.DebugFormat("[LLCLIENTVIEW]: Bod {0} {1}", | ||
5783 | // qdelta1, qdelta2); | ||
5784 | //m_log.DebugFormat("[LLCLIENTVIEW]: St {0} {1} {2} {3}", | ||
5785 | // x.ControlFlags, x.Flags, x.Far, x.State); | ||
5786 | //} | ||
5787 | return movementSignificant; | ||
5788 | } | ||
5612 | 5789 | ||
5613 | bool update = false; | 5790 | /// <summary> |
5614 | AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData; | 5791 | /// This checks the camera update significance against the last update made. |
5615 | 5792 | /// </summary> | |
5616 | if (m_lastAgentUpdateArgs != null) | 5793 | /// <remarks>Can only be called by one thread at a time</remarks> |
5617 | { | 5794 | /// <returns></returns> |
5618 | // These should be ordered from most-likely to | 5795 | /// <param name='x'></param> |
5619 | // least likely to change. I've made an initial | 5796 | private bool CheckAgentCameraUpdateSignificance(AgentUpdatePacket.AgentDataBlock x) |
5620 | // guess at that. | 5797 | { |
5621 | update = | 5798 | float vdelta1 = Vector3.Distance(x.CameraAtAxis, m_thisAgentUpdateArgs.CameraAtAxis); |
5622 | ( | 5799 | float vdelta2 = Vector3.Distance(x.CameraCenter, m_thisAgentUpdateArgs.CameraCenter); |
5623 | (x.BodyRotation != m_lastAgentUpdateArgs.BodyRotation) || | 5800 | float vdelta3 = Vector3.Distance(x.CameraLeftAxis, m_thisAgentUpdateArgs.CameraLeftAxis); |
5624 | (x.CameraAtAxis != m_lastAgentUpdateArgs.CameraAtAxis) || | 5801 | float vdelta4 = Vector3.Distance(x.CameraUpAxis, m_thisAgentUpdateArgs.CameraUpAxis); |
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 | 5802 | ||
5644 | if (update) | 5803 | bool cameraSignificant = |
5645 | { | 5804 | (vdelta1 > VDELTA) || |
5646 | // m_log.DebugFormat("[LLCLIENTVIEW]: Triggered AgentUpdate for {0}", sener.Name); | 5805 | (vdelta2 > VDELTA) || |
5806 | (vdelta3 > VDELTA) || | ||
5807 | (vdelta4 > VDELTA) | ||
5808 | ; | ||
5647 | 5809 | ||
5648 | m_lastAgentUpdateArgs.AgentID = x.AgentID; | 5810 | //if (cameraSignificant) |
5649 | m_lastAgentUpdateArgs.BodyRotation = x.BodyRotation; | 5811 | //{ |
5650 | m_lastAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis; | 5812 | //m_log.DebugFormat("[LLCLIENTVIEW]: Cam1 {0} {1}", |
5651 | m_lastAgentUpdateArgs.CameraCenter = x.CameraCenter; | 5813 | // x.CameraAtAxis, x.CameraCenter); |
5652 | m_lastAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis; | 5814 | //m_log.DebugFormat("[LLCLIENTVIEW]: Cam2 {0} {1}", |
5653 | m_lastAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis; | 5815 | // x.CameraLeftAxis, x.CameraUpAxis); |
5654 | m_lastAgentUpdateArgs.ControlFlags = x.ControlFlags; | 5816 | //} |
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 | 5817 | ||
5661 | UpdateAgent handlerAgentUpdate = OnAgentUpdate; | 5818 | return cameraSignificant; |
5662 | UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate; | 5819 | } |
5663 | 5820 | ||
5664 | if (handlerPreAgentUpdate != null) | 5821 | private bool HandleAgentUpdate(IClientAPI sener, Packet packet) |
5665 | OnPreAgentUpdate(this, m_lastAgentUpdateArgs); | 5822 | { |
5823 | // We got here, which means that something in agent update was significant | ||
5666 | 5824 | ||
5667 | if (handlerAgentUpdate != null) | 5825 | AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet; |
5668 | OnAgentUpdate(this, m_lastAgentUpdateArgs); | 5826 | AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData; |
5669 | 5827 | ||
5670 | handlerAgentUpdate = null; | 5828 | if (x.AgentID != AgentId || x.SessionID != SessionId) |
5671 | handlerPreAgentUpdate = null; | 5829 | return false; |
5672 | } | 5830 | |
5673 | } | 5831 | // Before we update the current m_thisAgentUpdateArgs, let's check this again |
5832 | // to see what exactly changed | ||
5833 | bool movement = CheckAgentMovementUpdateSignificance(x); | ||
5834 | bool camera = CheckAgentCameraUpdateSignificance(x); | ||
5835 | |||
5836 | m_thisAgentUpdateArgs.AgentID = x.AgentID; | ||
5837 | m_thisAgentUpdateArgs.BodyRotation = x.BodyRotation; | ||
5838 | m_thisAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis; | ||
5839 | m_thisAgentUpdateArgs.CameraCenter = x.CameraCenter; | ||
5840 | m_thisAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis; | ||
5841 | m_thisAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis; | ||
5842 | m_thisAgentUpdateArgs.ControlFlags = x.ControlFlags; | ||
5843 | m_thisAgentUpdateArgs.Far = x.Far; | ||
5844 | m_thisAgentUpdateArgs.Flags = x.Flags; | ||
5845 | m_thisAgentUpdateArgs.HeadRotation = x.HeadRotation; | ||
5846 | m_thisAgentUpdateArgs.SessionID = x.SessionID; | ||
5847 | m_thisAgentUpdateArgs.State = x.State; | ||
5848 | |||
5849 | UpdateAgent handlerAgentUpdate = OnAgentUpdate; | ||
5850 | UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate; | ||
5851 | UpdateAgent handlerAgentCameraUpdate = OnAgentCameraUpdate; | ||
5852 | |||
5853 | // Was there a significant movement/state change? | ||
5854 | if (movement) | ||
5855 | { | ||
5856 | if (handlerPreAgentUpdate != null) | ||
5857 | OnPreAgentUpdate(this, m_thisAgentUpdateArgs); | ||
5858 | |||
5859 | if (handlerAgentUpdate != null) | ||
5860 | OnAgentUpdate(this, m_thisAgentUpdateArgs); | ||
5861 | } | ||
5862 | // Was there a significant camera(s) change? | ||
5863 | if (camera) | ||
5864 | if (handlerAgentCameraUpdate != null) | ||
5865 | handlerAgentCameraUpdate(this, m_thisAgentUpdateArgs); | ||
5866 | |||
5867 | handlerAgentUpdate = null; | ||
5868 | handlerPreAgentUpdate = null; | ||
5869 | handlerAgentCameraUpdate = null; | ||
5674 | 5870 | ||
5675 | PacketPool.Instance.ReturnPacket(packet); | 5871 | PacketPool.Instance.ReturnPacket(packet); |
5676 | 5872 | ||
@@ -6260,6 +6456,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6260 | //m_log.Info("[LAND]: LAND:" + modify.ToString()); | 6456 | //m_log.Info("[LAND]: LAND:" + modify.ToString()); |
6261 | if (modify.ParcelData.Length > 0) | 6457 | if (modify.ParcelData.Length > 0) |
6262 | { | 6458 | { |
6459 | // Note: the ModifyTerrain event handler sends out updated packets before the end of this event. Therefore, | ||
6460 | // a simple boolean value should work and perhaps queue up just a few terrain patch packets at the end of the edit. | ||
6461 | m_justEditedTerrain = true; // Prevent terrain packet (Land layer) from being queued, make it unreliable | ||
6263 | if (OnModifyTerrain != null) | 6462 | if (OnModifyTerrain != null) |
6264 | { | 6463 | { |
6265 | for (int i = 0; i < modify.ParcelData.Length; i++) | 6464 | for (int i = 0; i < modify.ParcelData.Length; i++) |
@@ -6275,6 +6474,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6275 | } | 6474 | } |
6276 | } | 6475 | } |
6277 | } | 6476 | } |
6477 | m_justEditedTerrain = false; // Queue terrain packet (Land layer) if necessary, make it reliable again | ||
6278 | } | 6478 | } |
6279 | 6479 | ||
6280 | return true; | 6480 | return true; |
@@ -6636,6 +6836,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6636 | } | 6836 | } |
6637 | #endregion | 6837 | #endregion |
6638 | 6838 | ||
6839 | if (SceneAgent.IsChildAgent) | ||
6840 | { | ||
6841 | SendCantSitBecauseChildAgentResponse(); | ||
6842 | return true; | ||
6843 | } | ||
6844 | |||
6639 | AgentRequestSit handlerAgentRequestSit = OnAgentRequestSit; | 6845 | AgentRequestSit handlerAgentRequestSit = OnAgentRequestSit; |
6640 | 6846 | ||
6641 | if (handlerAgentRequestSit != null) | 6847 | if (handlerAgentRequestSit != null) |
@@ -6660,6 +6866,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6660 | } | 6866 | } |
6661 | #endregion | 6867 | #endregion |
6662 | 6868 | ||
6869 | if (SceneAgent.IsChildAgent) | ||
6870 | { | ||
6871 | SendCantSitBecauseChildAgentResponse(); | ||
6872 | return true; | ||
6873 | } | ||
6874 | |||
6663 | AgentSit handlerAgentSit = OnAgentSit; | 6875 | AgentSit handlerAgentSit = OnAgentSit; |
6664 | if (handlerAgentSit != null) | 6876 | if (handlerAgentSit != null) |
6665 | { | 6877 | { |
@@ -6669,6 +6881,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6669 | return true; | 6881 | return true; |
6670 | } | 6882 | } |
6671 | 6883 | ||
6884 | /// <summary> | ||
6885 | /// Used when a child agent gets a sit response which should not be fulfilled. | ||
6886 | /// </summary> | ||
6887 | private void SendCantSitBecauseChildAgentResponse() | ||
6888 | { | ||
6889 | SendAlertMessage("Try moving closer. Can't sit on object because it is not in the same region as you."); | ||
6890 | } | ||
6891 | |||
6672 | private bool HandleSoundTrigger(IClientAPI sender, Packet Pack) | 6892 | private bool HandleSoundTrigger(IClientAPI sender, Packet Pack) |
6673 | { | 6893 | { |
6674 | SoundTriggerPacket soundTriggerPacket = (SoundTriggerPacket)Pack; | 6894 | SoundTriggerPacket soundTriggerPacket = (SoundTriggerPacket)Pack; |
@@ -7879,129 +8099,145 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
7879 | //m_log.Debug("ClientView.ProcessPackets.cs:ProcessInPacket() - Got transfer request"); | 8099 | //m_log.Debug("ClientView.ProcessPackets.cs:ProcessInPacket() - Got transfer request"); |
7880 | 8100 | ||
7881 | TransferRequestPacket transfer = (TransferRequestPacket)Pack; | 8101 | 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; | 8102 | UUID taskID = UUID.Zero; |
7887 | if (transfer.TransferInfo.SourceType == (int)SourceType.SimInventoryItem) | 8103 | if (transfer.TransferInfo.SourceType == (int)SourceType.SimInventoryItem) |
7888 | { | 8104 | { |
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())) | 8105 | if (!(((Scene)m_scene).Permissions.BypassPermissions())) |
7898 | { | 8106 | { |
7899 | if (taskID != UUID.Zero) // Prim | 8107 | // We're spawning a thread because the permissions check can block this thread |
8108 | Util.FireAndForget(delegate | ||
7900 | { | 8109 | { |
7901 | SceneObjectPart part = ((Scene)m_scene).GetSceneObjectPart(taskID); | 8110 | // This requests the asset if needed |
8111 | HandleSimInventoryTransferRequestWithPermsCheck(sender, transfer); | ||
8112 | }); | ||
8113 | return true; | ||
8114 | } | ||
8115 | } | ||
8116 | else if (transfer.TransferInfo.SourceType == (int)SourceType.SimEstate) | ||
8117 | { | ||
8118 | //TransferRequestPacket does not include covenant uuid? | ||
8119 | //get scene covenant uuid | ||
8120 | taskID = m_scene.RegionInfo.RegionSettings.Covenant; | ||
8121 | } | ||
7902 | 8122 | ||
7903 | if (part == null) | 8123 | // This is non-blocking |
7904 | { | 8124 | 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 | 8125 | ||
7911 | TaskInventoryItem tii = part.Inventory.GetInventoryItem(itemID); | 8126 | return true; |
7912 | if (tii == null) | 8127 | } |
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 | 8128 | ||
7920 | if (tii.Type == (int)AssetType.LSLText) | 8129 | private void HandleSimInventoryTransferRequestWithPermsCheck(IClientAPI sender, TransferRequestPacket transfer) |
7921 | { | 8130 | { |
7922 | if (!((Scene)m_scene).Permissions.CanEditScript(itemID, taskID, AgentId)) | 8131 | UUID taskID = new UUID(transfer.TransferInfo.Params, 48); |
7923 | return true; | 8132 | UUID itemID = new UUID(transfer.TransferInfo.Params, 64); |
7924 | } | 8133 | 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 | 8134 | ||
7942 | if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0) | 8135 | //m_log.DebugFormat( |
7943 | { | 8136 | // "[CLIENT]: Got request for asset {0} from item {1} in prim {2} by {3}", |
7944 | m_log.WarnFormat( | 8137 | // 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 | 8138 | ||
7950 | if (tii.OwnerID != AgentId) | 8139 | //m_log.Debug("Transfer Request: " + transfer.ToString()); |
7951 | { | 8140 | // Validate inventory transfers |
7952 | m_log.WarnFormat( | 8141 | // 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}", | 8142 | // |
7954 | Name, requestID, itemID, taskID, tii.OwnerID); | 8143 | if (taskID != UUID.Zero) // Prim |
7955 | return true; | 8144 | { |
7956 | } | 8145 | SceneObjectPart part = ((Scene)m_scene).GetSceneObjectPart(taskID); |
7957 | 8146 | ||
7958 | if (( | 8147 | if (part == null) |
7959 | tii.CurrentPermissions & ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) | 8148 | { |
7960 | != ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) | 8149 | m_log.WarnFormat( |
7961 | { | 8150 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but prim does not exist", |
7962 | m_log.WarnFormat( | 8151 | Name, requestID, itemID, taskID); |
7963 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item permissions are not modify/copy/transfer", | 8152 | return; |
7964 | Name, requestID, itemID, taskID); | 8153 | } |
7965 | return true; | ||
7966 | } | ||
7967 | 8154 | ||
7968 | if (tii.AssetID != requestID) | 8155 | TaskInventoryItem tii = part.Inventory.GetInventoryItem(itemID); |
7969 | { | 8156 | if (tii == null) |
7970 | m_log.WarnFormat( | 8157 | { |
7971 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but this does not match item's asset {4}", | 8158 | m_log.WarnFormat( |
7972 | Name, requestID, itemID, taskID, tii.AssetID); | 8159 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item does not exist", |
7973 | return true; | 8160 | Name, requestID, itemID, taskID); |
7974 | } | 8161 | return; |
7975 | } | 8162 | } |
8163 | |||
8164 | if (tii.Type == (int)AssetType.LSLText) | ||
8165 | { | ||
8166 | if (!((Scene)m_scene).Permissions.CanEditScript(itemID, taskID, AgentId)) | ||
8167 | return; | ||
8168 | } | ||
8169 | else if (tii.Type == (int)AssetType.Notecard) | ||
8170 | { | ||
8171 | if (!((Scene)m_scene).Permissions.CanEditNotecard(itemID, taskID, AgentId)) | ||
8172 | return; | ||
8173 | } | ||
8174 | else | ||
8175 | { | ||
8176 | // TODO: Change this code to allow items other than notecards and scripts to be successfully | ||
8177 | // shared with group. In fact, this whole block of permissions checking should move to an IPermissionsModule | ||
8178 | if (part.OwnerID != AgentId) | ||
8179 | { | ||
8180 | m_log.WarnFormat( | ||
8181 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the prim is owned by {4}", | ||
8182 | Name, requestID, itemID, taskID, part.OwnerID); | ||
8183 | return; | ||
7976 | } | 8184 | } |
7977 | else // Agent | 8185 | |
8186 | if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0) | ||
7978 | { | 8187 | { |
7979 | IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>(); | 8188 | m_log.WarnFormat( |
7980 | if (invAccess != null) | 8189 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but modify permissions are not set", |
7981 | { | 8190 | Name, requestID, itemID, taskID); |
7982 | if (!invAccess.CanGetAgentInventoryItem(this, itemID, requestID)) | 8191 | return; |
7983 | return false; | 8192 | } |
7984 | } | 8193 | |
7985 | else | 8194 | if (tii.OwnerID != AgentId) |
7986 | { | 8195 | { |
7987 | return false; | 8196 | m_log.WarnFormat( |
7988 | } | 8197 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the item is owned by {4}", |
8198 | Name, requestID, itemID, taskID, tii.OwnerID); | ||
8199 | return; | ||
8200 | } | ||
8201 | |||
8202 | if (( | ||
8203 | tii.CurrentPermissions & ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) | ||
8204 | != ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) | ||
8205 | { | ||
8206 | m_log.WarnFormat( | ||
8207 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item permissions are not modify/copy/transfer", | ||
8208 | Name, requestID, itemID, taskID); | ||
8209 | return; | ||
8210 | } | ||
8211 | |||
8212 | if (tii.AssetID != requestID) | ||
8213 | { | ||
8214 | m_log.WarnFormat( | ||
8215 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but this does not match item's asset {4}", | ||
8216 | Name, requestID, itemID, taskID, tii.AssetID); | ||
8217 | return; | ||
7989 | } | 8218 | } |
7990 | } | 8219 | } |
7991 | } | 8220 | } |
7992 | else | 8221 | else // Agent |
7993 | if (transfer.TransferInfo.SourceType == (int)SourceType.SimEstate) | 8222 | { |
8223 | IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>(); | ||
8224 | if (invAccess != null) | ||
7994 | { | 8225 | { |
7995 | //TransferRequestPacket does not include covenant uuid? | 8226 | if (!invAccess.CanGetAgentInventoryItem(this, itemID, requestID)) |
7996 | //get scene covenant uuid | 8227 | return; |
7997 | taskID = m_scene.RegionInfo.RegionSettings.Covenant; | ||
7998 | } | 8228 | } |
8229 | else | ||
8230 | { | ||
8231 | return; | ||
8232 | } | ||
8233 | } | ||
7999 | 8234 | ||
8235 | // Permissions out of the way, let's request the asset | ||
8000 | MakeAssetRequest(transfer, taskID); | 8236 | MakeAssetRequest(transfer, taskID); |
8001 | 8237 | ||
8002 | return true; | ||
8003 | } | 8238 | } |
8004 | 8239 | ||
8240 | |||
8005 | private bool HandleAssetUploadRequest(IClientAPI sender, Packet Pack) | 8241 | private bool HandleAssetUploadRequest(IClientAPI sender, Packet Pack) |
8006 | { | 8242 | { |
8007 | AssetUploadRequestPacket request = (AssetUploadRequestPacket)Pack; | 8243 | AssetUploadRequestPacket request = (AssetUploadRequestPacket)Pack; |
@@ -11732,8 +11968,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11732 | } | 11968 | } |
11733 | 11969 | ||
11734 | /// <summary> | 11970 | /// <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> | 11971 | /// </summary> |
11738 | /// <remarks> | 11972 | /// <remarks> |
11739 | /// At the moment, we always reply that there is no cached texture. | 11973 | /// At the moment, we always reply that there is no cached texture. |
@@ -11741,6 +11975,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11741 | /// <param name="simclient"></param> | 11975 | /// <param name="simclient"></param> |
11742 | /// <param name="packet"></param> | 11976 | /// <param name="packet"></param> |
11743 | /// <returns></returns> | 11977 | /// <returns></returns> |
11978 | // TODO: Convert old handler to use new method | ||
11979 | /*protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet) | ||
11980 | { | ||
11981 | AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet; | ||
11982 | |||
11983 | if (cachedtex.AgentData.SessionID != SessionId) | ||
11984 | return false; | ||
11985 | |||
11986 | |||
11987 | List<CachedTextureRequestArg> requestArgs = new List<CachedTextureRequestArg>(); | ||
11988 | |||
11989 | for (int i = 0; i < cachedtex.WearableData.Length; i++) | ||
11990 | { | ||
11991 | CachedTextureRequestArg arg = new CachedTextureRequestArg(); | ||
11992 | arg.BakedTextureIndex = cachedtex.WearableData[i].TextureIndex; | ||
11993 | arg.WearableHashID = cachedtex.WearableData[i].ID; | ||
11994 | |||
11995 | requestArgs.Add(arg); | ||
11996 | } | ||
11997 | |||
11998 | CachedTextureRequest handlerCachedTextureRequest = OnCachedTextureRequest; | ||
11999 | if (handlerCachedTextureRequest != null) | ||
12000 | { | ||
12001 | handlerCachedTextureRequest(simclient,cachedtex.AgentData.SerialNum,requestArgs); | ||
12002 | } | ||
12003 | |||
12004 | return true; | ||
12005 | }*/ | ||
12006 | |||
11744 | protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet) | 12007 | protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet) |
11745 | { | 12008 | { |
11746 | //m_log.Debug("texture cached: " + packet.ToString()); | 12009 | //m_log.Debug("texture cached: " + packet.ToString()); |
@@ -11899,6 +12162,40 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11899 | return true; | 12162 | return true; |
11900 | } | 12163 | } |
11901 | 12164 | ||
12165 | /// <summary> | ||
12166 | /// Send a response back to a client when it asks the asset server (via the region server) if it has | ||
12167 | /// its appearance texture cached. | ||
12168 | /// </summary> | ||
12169 | /// <param name="avatar"></param> | ||
12170 | /// <param name="serial"></param> | ||
12171 | /// <param name="cachedTextures"></param> | ||
12172 | /// <returns></returns> | ||
12173 | public void SendCachedTextureResponse(ISceneEntity avatar, int serial, List<CachedTextureResponseArg> cachedTextures) | ||
12174 | { | ||
12175 | ScenePresence presence = avatar as ScenePresence; | ||
12176 | if (presence == null) | ||
12177 | return; | ||
12178 | |||
12179 | AgentCachedTextureResponsePacket cachedresp = (AgentCachedTextureResponsePacket)PacketPool.Instance.GetPacket(PacketType.AgentCachedTextureResponse); | ||
12180 | |||
12181 | // TODO: don't create new blocks if recycling an old packet | ||
12182 | cachedresp.AgentData.AgentID = m_agentId; | ||
12183 | cachedresp.AgentData.SessionID = m_sessionId; | ||
12184 | cachedresp.AgentData.SerialNum = serial; | ||
12185 | cachedresp.WearableData = new AgentCachedTextureResponsePacket.WearableDataBlock[cachedTextures.Count]; | ||
12186 | |||
12187 | for (int i = 0; i < cachedTextures.Count; i++) | ||
12188 | { | ||
12189 | cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); | ||
12190 | cachedresp.WearableData[i].TextureIndex = (byte)cachedTextures[i].BakedTextureIndex; | ||
12191 | cachedresp.WearableData[i].TextureID = cachedTextures[i].BakedTextureID; | ||
12192 | cachedresp.WearableData[i].HostName = new byte[0]; | ||
12193 | } | ||
12194 | |||
12195 | cachedresp.Header.Zerocoded = true; | ||
12196 | OutPacket(cachedresp, ThrottleOutPacketType.Task); | ||
12197 | } | ||
12198 | |||
11902 | protected bool HandleMultipleObjUpdate(IClientAPI simClient, Packet packet) | 12199 | protected bool HandleMultipleObjUpdate(IClientAPI simClient, Packet packet) |
11903 | { | 12200 | { |
11904 | MultipleObjectUpdatePacket multipleupdate = (MultipleObjectUpdatePacket)packet; | 12201 | MultipleObjectUpdatePacket multipleupdate = (MultipleObjectUpdatePacket)packet; |
@@ -11924,8 +12221,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11924 | if (part == null) | 12221 | if (part == null) |
11925 | { | 12222 | { |
11926 | // It's a ghost! tell the client to delete it from view. | 12223 | // It's a ghost! tell the client to delete it from view. |
11927 | simClient.SendKillObject(Scene.RegionInfo.RegionHandle, | 12224 | simClient.SendKillObject(new List<uint> { localId }); |
11928 | new List<uint> { localId }); | ||
11929 | } | 12225 | } |
11930 | else | 12226 | else |
11931 | { | 12227 | { |
@@ -12299,6 +12595,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
12299 | 12595 | ||
12300 | shape.PCode = addPacket.ObjectData.PCode; | 12596 | shape.PCode = addPacket.ObjectData.PCode; |
12301 | shape.State = addPacket.ObjectData.State; | 12597 | shape.State = addPacket.ObjectData.State; |
12598 | shape.LastAttachPoint = addPacket.ObjectData.State; | ||
12302 | shape.PathBegin = addPacket.ObjectData.PathBegin; | 12599 | shape.PathBegin = addPacket.ObjectData.PathBegin; |
12303 | shape.PathEnd = addPacket.ObjectData.PathEnd; | 12600 | shape.PathEnd = addPacket.ObjectData.PathEnd; |
12304 | shape.PathScaleX = addPacket.ObjectData.PathScaleX; | 12601 | shape.PathScaleX = addPacket.ObjectData.PathScaleX; |
@@ -12329,7 +12626,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
12329 | ClientInfo info = m_udpClient.GetClientInfo(); | 12626 | ClientInfo info = m_udpClient.GetClientInfo(); |
12330 | 12627 | ||
12331 | info.proxyEP = null; | 12628 | info.proxyEP = null; |
12332 | info.agentcircuit = RequestClientInfo(); | 12629 | if (info.agentcircuit == null) |
12630 | info.agentcircuit = RequestClientInfo(); | ||
12333 | 12631 | ||
12334 | return info; | 12632 | return info; |
12335 | } | 12633 | } |
@@ -12712,11 +13010,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
12712 | OutPacket(dialog, ThrottleOutPacketType.Task); | 13010 | OutPacket(dialog, ThrottleOutPacketType.Task); |
12713 | } | 13011 | } |
12714 | 13012 | ||
12715 | public void StopFlying(ISceneEntity p) | 13013 | public void SendAgentTerseUpdate(ISceneEntity p) |
12716 | { | 13014 | { |
12717 | if (p is ScenePresence) | 13015 | if (p is ScenePresence) |
12718 | { | 13016 | { |
12719 | ScenePresence presence = p as ScenePresence; | 13017 | // m_log.DebugFormat( |
13018 | // "[LLCLIENTVIEW]: Immediately sending terse agent update for {0} to {1} in {2}", | ||
13019 | // p.Name, Name, Scene.Name); | ||
13020 | |||
12720 | // It turns out to get the agent to stop flying, you have to feed it stop flying velocities | 13021 | // 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 | 13022 | // 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 | 13023 | // velocity, collision plane and avatar height |
@@ -12724,34 +13025,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 | 13025 | // 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 | 13026 | // when the avatar stands up |
12726 | 13027 | ||
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 = | 13028 | ImprovedTerseObjectUpdatePacket.ObjectDataBlock block = |
12749 | CreateImprovedTerseBlock(p, false); | 13029 | CreateImprovedTerseBlock(p, false); |
12750 | 13030 | ||
12751 | const float TIME_DILATION = 1.0f; | 13031 | const float TIME_DILATION = 1.0f; |
12752 | ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f); | 13032 | ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f); |
12753 | 13033 | ||
12754 | |||
12755 | ImprovedTerseObjectUpdatePacket packet | 13034 | ImprovedTerseObjectUpdatePacket packet |
12756 | = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket( | 13035 | = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket( |
12757 | PacketType.ImprovedTerseObjectUpdate); | 13036 | 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..bd4e617 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> |
@@ -161,6 +164,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
161 | public bool m_deliverPackets = true; | 164 | public bool m_deliverPackets = true; |
162 | 165 | ||
163 | /// <summary> | 166 | /// <summary> |
167 | /// This is the percentage of the udp texture queue to add to the task queue since | ||
168 | /// textures are now generally handled through http. | ||
169 | /// </summary> | ||
170 | private double m_cannibalrate = 0.0; | ||
171 | |||
172 | private ClientInfo m_info = new ClientInfo(); | ||
173 | |||
174 | /// <summary> | ||
164 | /// Default constructor | 175 | /// Default constructor |
165 | /// </summary> | 176 | /// </summary> |
166 | /// <param name="server">Reference to the UDP server this client is connected to</param> | 177 | /// <param name="server">Reference to the UDP server this client is connected to</param> |
@@ -197,6 +208,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
197 | // Create an array of token buckets for this clients different throttle categories | 208 | // Create an array of token buckets for this clients different throttle categories |
198 | m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; | 209 | m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; |
199 | 210 | ||
211 | m_cannibalrate = rates.CannibalizeTextureRate; | ||
212 | |||
200 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) | 213 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) |
201 | { | 214 | { |
202 | ThrottleOutPacketType type = (ThrottleOutPacketType)i; | 215 | ThrottleOutPacketType type = (ThrottleOutPacketType)i; |
@@ -241,20 +254,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
241 | // TODO: This data structure is wrong in so many ways. Locking and copying the entire lists | 254 | // 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 | 255 | // of pending and needed ACKs for every client every time some method wants information about |
243 | // this connection is a recipe for poor performance | 256 | // this connection is a recipe for poor performance |
244 | ClientInfo info = new ClientInfo(); | 257 | |
245 | info.pendingAcks = new Dictionary<uint, uint>(); | 258 | m_info.resendThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate; |
246 | info.needAck = new Dictionary<uint, byte[]>(); | 259 | m_info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; |
247 | 260 | m_info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; | |
248 | info.resendThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate; | 261 | m_info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; |
249 | info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; | 262 | m_info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; |
250 | info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; | 263 | m_info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; |
251 | info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; | 264 | m_info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; |
252 | info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; | 265 | m_info.totalThrottle = (int)m_throttleCategory.DripRate; |
253 | info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; | 266 | |
254 | info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; | 267 | return m_info; |
255 | info.totalThrottle = (int)m_throttleCategory.DripRate; | ||
256 | |||
257 | return info; | ||
258 | } | 268 | } |
259 | 269 | ||
260 | /// <summary> | 270 | /// <summary> |
@@ -348,6 +358,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
348 | texture = Math.Max(texture, LLUDPServer.MTU); | 358 | texture = Math.Max(texture, LLUDPServer.MTU); |
349 | asset = Math.Max(asset, LLUDPServer.MTU); | 359 | asset = Math.Max(asset, LLUDPServer.MTU); |
350 | 360 | ||
361 | // Since most textures are now delivered through http, make it possible | ||
362 | // to cannibalize some of the bw from the texture throttle to use for | ||
363 | // the task queue (e.g. object updates) | ||
364 | task = task + (int)(m_cannibalrate * texture); | ||
365 | texture = (int)((1 - m_cannibalrate) * texture); | ||
366 | |||
351 | //int total = resend + land + wind + cloud + task + texture + asset; | 367 | //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}", | 368 | //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); | 369 | // AgentID, resend, land, wind, cloud, task, texture, asset, total); |
@@ -646,15 +662,38 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
646 | /// <param name="categories">Throttle categories to fire the callback for</param> | 662 | /// <param name="categories">Throttle categories to fire the callback for</param> |
647 | private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories) | 663 | private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories) |
648 | { | 664 | { |
649 | if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty) | 665 | // if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty) |
666 | if (!m_isQueueEmptyRunning && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty) | ||
650 | { | 667 | { |
668 | m_isQueueEmptyRunning = true; | ||
669 | |||
670 | int start = Environment.TickCount & Int32.MaxValue; | ||
671 | const int MIN_CALLBACK_MS = 30; | ||
672 | |||
673 | m_nextOnQueueEmpty = start + MIN_CALLBACK_MS; | ||
674 | if (m_nextOnQueueEmpty == 0) | ||
675 | m_nextOnQueueEmpty = 1; | ||
676 | |||
651 | // Use a value of 0 to signal that FireQueueEmpty is running | 677 | // Use a value of 0 to signal that FireQueueEmpty is running |
652 | m_nextOnQueueEmpty = 0; | 678 | // m_nextOnQueueEmpty = 0; |
653 | // Asynchronously run the callback | 679 | |
654 | Util.FireAndForget(FireQueueEmpty, categories); | 680 | m_categories = categories; |
681 | |||
682 | if (HasUpdates(m_categories)) | ||
683 | { | ||
684 | // Asynchronously run the callback | ||
685 | Util.FireAndForget(FireQueueEmpty, categories); | ||
686 | } | ||
687 | else | ||
688 | { | ||
689 | m_isQueueEmptyRunning = false; | ||
690 | } | ||
655 | } | 691 | } |
656 | } | 692 | } |
657 | 693 | ||
694 | private bool m_isQueueEmptyRunning; | ||
695 | private ThrottleOutPacketTypeFlags m_categories = 0; | ||
696 | |||
658 | /// <summary> | 697 | /// <summary> |
659 | /// Fires the OnQueueEmpty callback and sets the minimum time that it | 698 | /// Fires the OnQueueEmpty callback and sets the minimum time that it |
660 | /// can be called again | 699 | /// can be called again |
@@ -664,22 +703,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
664 | /// signature</param> | 703 | /// signature</param> |
665 | private void FireQueueEmpty(object o) | 704 | private void FireQueueEmpty(object o) |
666 | { | 705 | { |
667 | const int MIN_CALLBACK_MS = 30; | 706 | // int start = Environment.TickCount & Int32.MaxValue; |
707 | // const int MIN_CALLBACK_MS = 30; | ||
668 | 708 | ||
669 | ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o; | 709 | // if (m_udpServer.IsRunningOutbound) |
670 | QueueEmpty callback = OnQueueEmpty; | 710 | // { |
671 | 711 | ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o; | |
672 | int start = Environment.TickCount & Int32.MaxValue; | 712 | QueueEmpty callback = OnQueueEmpty; |
673 | 713 | ||
674 | if (callback != null) | 714 | if (callback != null) |
675 | { | 715 | { |
676 | try { callback(categories); } | 716 | // if (m_udpServer.IsRunningOutbound) |
677 | catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); } | 717 | // { |
678 | } | 718 | try { callback(categories); } |
719 | catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); } | ||
720 | // } | ||
721 | } | ||
722 | // } | ||
723 | |||
724 | // m_nextOnQueueEmpty = start + MIN_CALLBACK_MS; | ||
725 | // if (m_nextOnQueueEmpty == 0) | ||
726 | // m_nextOnQueueEmpty = 1; | ||
727 | |||
728 | // } | ||
679 | 729 | ||
680 | m_nextOnQueueEmpty = start + MIN_CALLBACK_MS; | 730 | m_isQueueEmptyRunning = false; |
681 | if (m_nextOnQueueEmpty == 0) | ||
682 | m_nextOnQueueEmpty = 1; | ||
683 | } | 731 | } |
684 | internal void ForceThrottleSetting(int throttle, int setting) | 732 | internal void ForceThrottleSetting(int throttle, int setting) |
685 | { | 733 | { |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 4154ef2..50dae2a 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; |
@@ -184,6 +294,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
184 | protected bool m_sendPing; | 294 | protected bool m_sendPing; |
185 | 295 | ||
186 | private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>(); | 296 | private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>(); |
297 | |||
298 | /// <summary> | ||
299 | /// Event used to signal when queued packets are available for sending. | ||
300 | /// </summary> | ||
301 | /// <remarks> | ||
302 | /// This allows the outbound loop to only operate when there is data to send rather than continuously polling. | ||
303 | /// Some data is sent immediately and not queued. That data would not trigger this event. | ||
304 | /// </remarks> | ||
305 | private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false); | ||
306 | |||
187 | private Pool<IncomingPacket> m_incomingPacketPool; | 307 | private Pool<IncomingPacket> m_incomingPacketPool; |
188 | 308 | ||
189 | /// <summary> | 309 | /// <summary> |
@@ -204,7 +324,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
204 | 324 | ||
205 | public Socket Server { get { return null; } } | 325 | public Socket Server { get { return null; } } |
206 | 326 | ||
207 | private int m_malformedCount = 0; // Guard against a spamming attack | 327 | /// <summary> |
328 | /// Record how many packets have been resent | ||
329 | /// </summary> | ||
330 | internal int PacketsResentCount { get; set; } | ||
331 | |||
332 | /// <summary> | ||
333 | /// Record how many packets have been sent | ||
334 | /// </summary> | ||
335 | internal int PacketsSentCount { get; set; } | ||
336 | |||
337 | /// <summary> | ||
338 | /// Record how many incoming packets are indicated as resends by clients. | ||
339 | /// </summary> | ||
340 | internal int IncomingPacketsResentCount { get; set; } | ||
341 | |||
342 | /// <summary> | ||
343 | /// Record how many inbound packets could not be recognized as LLUDP packets. | ||
344 | /// </summary> | ||
345 | public int IncomingMalformedPacketCount { get; private set; } | ||
346 | |||
347 | /// <summary> | ||
348 | /// Record how many inbound packets could not be associated with a simulator circuit. | ||
349 | /// </summary> | ||
350 | public int IncomingOrphanedPacketCount { get; private set; } | ||
208 | 351 | ||
209 | /// <summary> | 352 | /// <summary> |
210 | /// Record current outgoing client for monitoring purposes. | 353 | /// Record current outgoing client for monitoring purposes. |
@@ -461,6 +604,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
461 | m_scene = (Scene)scene; | 604 | m_scene = (Scene)scene; |
462 | m_location = new Location(m_scene.RegionInfo.RegionHandle); | 605 | m_location = new Location(m_scene.RegionInfo.RegionHandle); |
463 | 606 | ||
607 | StatsManager.RegisterStat( | ||
608 | new Stat( | ||
609 | "InboxPacketsCount", | ||
610 | "Number of LL protocol packets waiting for the second stage of processing after initial receive.", | ||
611 | "Number of LL protocol packets waiting for the second stage of processing after initial receive.", | ||
612 | "", | ||
613 | "clientstack", | ||
614 | scene.Name, | ||
615 | StatType.Pull, | ||
616 | MeasuresOfInterest.AverageChangeOverTime, | ||
617 | stat => stat.Value = packetInbox.Count, | ||
618 | StatVerbosity.Debug)); | ||
619 | |||
464 | // XXX: These stats are also pool stats but we register them separately since they are currently not | 620 | // 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() | 621 | // turned on and off by EnablePools()/DisablePools() |
466 | StatsManager.RegisterStat( | 622 | StatsManager.RegisterStat( |
@@ -521,6 +677,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
521 | EnablePoolStats(); | 677 | EnablePoolStats(); |
522 | 678 | ||
523 | MainConsole.Instance.Commands.AddCommand( | 679 | MainConsole.Instance.Commands.AddCommand( |
680 | "Debug", false, "debug lludp packet", | ||
681 | "debug lludp packet [--default] <level> [<avatar-first-name> <avatar-last-name>]", | ||
682 | "Turn on packet debugging", | ||
683 | "If level > 255 then all incoming and outgoing packets are logged.\n" | ||
684 | + "If level <= 255 then incoming AgentUpdate and outgoing SimStats and SimulatorViewerTimeMessage packets are not logged.\n" | ||
685 | + "If level <= 200 then incoming RequestImage and outgoing ImagePacket, ImageData, LayerData and CoarseLocationUpdate packets are not logged.\n" | ||
686 | + "If level <= 100 then incoming ViewerEffect and AgentAnimation and outgoing ViewerEffect and AvatarAnimation packets are not logged.\n" | ||
687 | + "If level <= 50 then outgoing ImprovedTerseObjectUpdate packets are not logged.\n" | ||
688 | + "If level <= 0 then no packets are logged.\n" | ||
689 | + "If --default is specified then the level becomes the default logging level for all subsequent agents.\n" | ||
690 | + "In this case, you cannot also specify an avatar name.\n" | ||
691 | + "If an avatar name is given then only packets from that avatar are logged.", | ||
692 | HandlePacketCommand); | ||
693 | |||
694 | MainConsole.Instance.Commands.AddCommand( | ||
524 | "Debug", | 695 | "Debug", |
525 | false, | 696 | false, |
526 | "debug lludp start", | 697 | "debug lludp start", |
@@ -559,10 +730,78 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
559 | "debug lludp status", | 730 | "debug lludp status", |
560 | "Return status of LLUDP packet processing.", | 731 | "Return status of LLUDP packet processing.", |
561 | HandleStatusCommand); | 732 | HandleStatusCommand); |
733 | |||
734 | MainConsole.Instance.Commands.AddCommand( | ||
735 | "Debug", | ||
736 | false, | ||
737 | "debug lludp toggle agentupdate", | ||
738 | "debug lludp toggle agentupdate", | ||
739 | "Toggle whether agentupdate packets are processed or simply discarded.", | ||
740 | HandleAgentUpdateCommand); | ||
741 | } | ||
742 | |||
743 | private void HandlePacketCommand(string module, string[] args) | ||
744 | { | ||
745 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) | ||
746 | return; | ||
747 | |||
748 | bool setAsDefaultLevel = false; | ||
749 | OptionSet optionSet = new OptionSet().Add("default", o => setAsDefaultLevel = o != null); | ||
750 | List<string> filteredArgs = optionSet.Parse(args); | ||
751 | |||
752 | string name = null; | ||
753 | |||
754 | if (filteredArgs.Count == 6) | ||
755 | { | ||
756 | if (!setAsDefaultLevel) | ||
757 | { | ||
758 | name = string.Format("{0} {1}", filteredArgs[4], filteredArgs[5]); | ||
759 | } | ||
760 | else | ||
761 | { | ||
762 | MainConsole.Instance.OutputFormat("ERROR: Cannot specify a user name when setting default logging level"); | ||
763 | return; | ||
764 | } | ||
765 | } | ||
766 | |||
767 | if (filteredArgs.Count > 3) | ||
768 | { | ||
769 | int newDebug; | ||
770 | if (int.TryParse(filteredArgs[3], out newDebug)) | ||
771 | { | ||
772 | if (setAsDefaultLevel) | ||
773 | { | ||
774 | DefaultClientPacketDebugLevel = newDebug; | ||
775 | MainConsole.Instance.OutputFormat( | ||
776 | "Debug packet debug for new clients set to {0} in {1}", DefaultClientPacketDebugLevel, m_scene.Name); | ||
777 | } | ||
778 | else | ||
779 | { | ||
780 | m_scene.ForEachScenePresence(sp => | ||
781 | { | ||
782 | if (name == null || sp.Name == name) | ||
783 | { | ||
784 | MainConsole.Instance.OutputFormat( | ||
785 | "Packet debug for {0} ({1}) set to {2} in {3}", | ||
786 | sp.Name, sp.IsChildAgent ? "child" : "root", newDebug, m_scene.Name); | ||
787 | |||
788 | sp.ControllingClient.DebugPacketLevel = newDebug; | ||
789 | } | ||
790 | }); | ||
791 | } | ||
792 | } | ||
793 | else | ||
794 | { | ||
795 | MainConsole.Instance.Output("Usage: debug lludp packet [--default] 0..255 [<first-name> <last-name>]"); | ||
796 | } | ||
797 | } | ||
562 | } | 798 | } |
563 | 799 | ||
564 | private void HandleStartCommand(string module, string[] args) | 800 | private void HandleStartCommand(string module, string[] args) |
565 | { | 801 | { |
802 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) | ||
803 | return; | ||
804 | |||
566 | if (args.Length != 4) | 805 | if (args.Length != 4) |
567 | { | 806 | { |
568 | MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>"); | 807 | MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>"); |
@@ -580,6 +819,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
580 | 819 | ||
581 | private void HandleStopCommand(string module, string[] args) | 820 | private void HandleStopCommand(string module, string[] args) |
582 | { | 821 | { |
822 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) | ||
823 | return; | ||
824 | |||
583 | if (args.Length != 4) | 825 | if (args.Length != 4) |
584 | { | 826 | { |
585 | MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>"); | 827 | MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>"); |
@@ -597,6 +839,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
597 | 839 | ||
598 | private void HandlePoolCommand(string module, string[] args) | 840 | private void HandlePoolCommand(string module, string[] args) |
599 | { | 841 | { |
842 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) | ||
843 | return; | ||
844 | |||
600 | if (args.Length != 4) | 845 | if (args.Length != 4) |
601 | { | 846 | { |
602 | MainConsole.Instance.Output("Usage: debug lludp pool <on|off>"); | 847 | MainConsole.Instance.Output("Usage: debug lludp pool <on|off>"); |
@@ -627,8 +872,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
627 | } | 872 | } |
628 | } | 873 | } |
629 | 874 | ||
875 | bool m_discardAgentUpdates; | ||
876 | |||
877 | private void HandleAgentUpdateCommand(string module, string[] args) | ||
878 | { | ||
879 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) | ||
880 | return; | ||
881 | |||
882 | m_discardAgentUpdates = !m_discardAgentUpdates; | ||
883 | |||
884 | MainConsole.Instance.OutputFormat( | ||
885 | "Discard AgentUpdates now {0} for {1}", m_discardAgentUpdates, m_scene.Name); | ||
886 | } | ||
887 | |||
630 | private void HandleStatusCommand(string module, string[] args) | 888 | private void HandleStatusCommand(string module, string[] args) |
631 | { | 889 | { |
890 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) | ||
891 | return; | ||
892 | |||
632 | MainConsole.Instance.OutputFormat( | 893 | MainConsole.Instance.OutputFormat( |
633 | "IN LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningInbound ? "enabled" : "disabled"); | 894 | "IN LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningInbound ? "enabled" : "disabled"); |
634 | 895 | ||
@@ -636,6 +897,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
636 | "OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled"); | 897 | "OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled"); |
637 | 898 | ||
638 | MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_scene.Name, UsePools ? "on" : "off"); | 899 | MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_scene.Name, UsePools ? "on" : "off"); |
900 | |||
901 | MainConsole.Instance.OutputFormat( | ||
902 | "Packet debug level for new clients is {0}", DefaultClientPacketDebugLevel); | ||
639 | } | 903 | } |
640 | 904 | ||
641 | public bool HandlesRegion(Location x) | 905 | public bool HandlesRegion(Location x) |
@@ -643,44 +907,44 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
643 | return x == m_location; | 907 | return x == m_location; |
644 | } | 908 | } |
645 | 909 | ||
646 | public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting) | 910 | // public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting) |
647 | { | 911 | // { |
648 | // CoarseLocationUpdate and AvatarGroupsReply packets cannot be split in an automated way | 912 | // // CoarseLocationUpdate and AvatarGroupsReply packets cannot be split in an automated way |
649 | if ((packet.Type == PacketType.CoarseLocationUpdate || packet.Type == PacketType.AvatarGroupsReply) && allowSplitting) | 913 | // if ((packet.Type == PacketType.CoarseLocationUpdate || packet.Type == PacketType.AvatarGroupsReply) && allowSplitting) |
650 | allowSplitting = false; | 914 | // allowSplitting = false; |
651 | 915 | // | |
652 | if (allowSplitting && packet.HasVariableBlocks) | 916 | // if (allowSplitting && packet.HasVariableBlocks) |
653 | { | 917 | // { |
654 | byte[][] datas = packet.ToBytesMultiple(); | 918 | // byte[][] datas = packet.ToBytesMultiple(); |
655 | int packetCount = datas.Length; | 919 | // int packetCount = datas.Length; |
656 | 920 | // | |
657 | if (packetCount < 1) | 921 | // if (packetCount < 1) |
658 | m_log.Error("[LLUDPSERVER]: Failed to split " + packet.Type + " with estimated length " + packet.Length); | 922 | // m_log.Error("[LLUDPSERVER]: Failed to split " + packet.Type + " with estimated length " + packet.Length); |
659 | 923 | // | |
660 | for (int i = 0; i < packetCount; i++) | 924 | // for (int i = 0; i < packetCount; i++) |
661 | { | 925 | // { |
662 | byte[] data = datas[i]; | 926 | // byte[] data = datas[i]; |
663 | m_scene.ForEachClient( | 927 | // m_scene.ForEachClient( |
664 | delegate(IClientAPI client) | 928 | // delegate(IClientAPI client) |
665 | { | 929 | // { |
666 | if (client is LLClientView) | 930 | // if (client is LLClientView) |
667 | SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null); | 931 | // SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null); |
668 | } | 932 | // } |
669 | ); | 933 | // ); |
670 | } | 934 | // } |
671 | } | 935 | // } |
672 | else | 936 | // else |
673 | { | 937 | // { |
674 | byte[] data = packet.ToBytes(); | 938 | // byte[] data = packet.ToBytes(); |
675 | m_scene.ForEachClient( | 939 | // m_scene.ForEachClient( |
676 | delegate(IClientAPI client) | 940 | // delegate(IClientAPI client) |
677 | { | 941 | // { |
678 | if (client is LLClientView) | 942 | // if (client is LLClientView) |
679 | SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null); | 943 | // SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null); |
680 | } | 944 | // } |
681 | ); | 945 | // ); |
682 | } | 946 | // } |
683 | } | 947 | // } |
684 | 948 | ||
685 | /// <summary> | 949 | /// <summary> |
686 | /// Start the process of sending a packet to the client. | 950 | /// Start the process of sending a packet to the client. |
@@ -700,6 +964,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
700 | if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting) | 964 | if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting) |
701 | allowSplitting = false; | 965 | allowSplitting = false; |
702 | 966 | ||
967 | bool packetQueued = false; | ||
968 | |||
703 | if (allowSplitting && packet.HasVariableBlocks) | 969 | if (allowSplitting && packet.HasVariableBlocks) |
704 | { | 970 | { |
705 | byte[][] datas = packet.ToBytesMultiple(); | 971 | byte[][] datas = packet.ToBytesMultiple(); |
@@ -711,16 +977,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
711 | for (int i = 0; i < packetCount; i++) | 977 | for (int i = 0; i < packetCount; i++) |
712 | { | 978 | { |
713 | byte[] data = datas[i]; | 979 | byte[] data = datas[i]; |
714 | SendPacketData(udpClient, data, packet.Type, category, method); | 980 | |
981 | if (!SendPacketData(udpClient, data, packet.Type, category, method)) | ||
982 | packetQueued = true; | ||
715 | } | 983 | } |
716 | } | 984 | } |
717 | else | 985 | else |
718 | { | 986 | { |
719 | byte[] data = packet.ToBytes(); | 987 | byte[] data = packet.ToBytes(); |
720 | SendPacketData(udpClient, data, packet.Type, category, method); | 988 | packetQueued = SendPacketData(udpClient, data, packet.Type, category, method); |
721 | } | 989 | } |
722 | 990 | ||
723 | PacketPool.Instance.ReturnPacket(packet); | 991 | PacketPool.Instance.ReturnPacket(packet); |
992 | |||
993 | if (packetQueued) | ||
994 | m_dataPresentEvent.Set(); | ||
724 | } | 995 | } |
725 | 996 | ||
726 | /// <summary> | 997 | /// <summary> |
@@ -734,7 +1005,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 | 1005 | /// 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. | 1006 | /// resend of the packet is done. |
736 | /// </param> | 1007 | /// </param> |
737 | public void SendPacketData( | 1008 | /// <returns>true if the data was sent immediately, false if it was queued for sending</returns> |
1009 | public bool SendPacketData( | ||
738 | LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category, UnackedPacketMethod method) | 1010 | LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category, UnackedPacketMethod method) |
739 | { | 1011 | { |
740 | int dataLength = data.Length; | 1012 | int dataLength = data.Length; |
@@ -807,7 +1079,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
807 | // packet so that it isn't sent before a queued update packet. | 1079 | // packet so that it isn't sent before a queued update packet. |
808 | bool requestQueue = type == PacketType.KillObject; | 1080 | bool requestQueue = type == PacketType.KillObject; |
809 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue, highPriority)) | 1081 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue, highPriority)) |
1082 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue)) | ||
1083 | { | ||
810 | SendPacketFinal(outgoingPacket); | 1084 | SendPacketFinal(outgoingPacket); |
1085 | return true; | ||
1086 | } | ||
1087 | |||
1088 | return false; | ||
811 | 1089 | ||
812 | #endregion Queue or Send | 1090 | #endregion Queue or Send |
813 | } | 1091 | } |
@@ -883,7 +1161,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 | 1161 | // 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. | 1162 | // 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. | 1163 | // This is the same as processing as the async process of a logout request. |
886 | Util.FireAndForget(o => DeactivateClientDueToTimeout(client)); | 1164 | Util.FireAndForget(o => DeactivateClientDueToTimeout(client, timeoutTicks)); |
887 | 1165 | ||
888 | return; | 1166 | return; |
889 | } | 1167 | } |
@@ -988,6 +1266,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
988 | else | 1266 | else |
989 | { | 1267 | { |
990 | Interlocked.Increment(ref udpClient.PacketsResent); | 1268 | Interlocked.Increment(ref udpClient.PacketsResent); |
1269 | |||
1270 | // We're not going to worry about interlock yet since its not currently critical that this total count | ||
1271 | // is 100% correct | ||
1272 | PacketsResentCount++; | ||
991 | } | 1273 | } |
992 | 1274 | ||
993 | #endregion Sequence Number Assignment | 1275 | #endregion Sequence Number Assignment |
@@ -995,6 +1277,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
995 | // Stats tracking | 1277 | // Stats tracking |
996 | Interlocked.Increment(ref udpClient.PacketsSent); | 1278 | Interlocked.Increment(ref udpClient.PacketsSent); |
997 | 1279 | ||
1280 | // We're not going to worry about interlock yet since its not currently critical that this total count | ||
1281 | // is 100% correct | ||
1282 | PacketsSentCount++; | ||
1283 | |||
998 | // Put the UDP payload on the wire | 1284 | // Put the UDP payload on the wire |
999 | AsyncBeginSend(buffer); | 1285 | AsyncBeginSend(buffer); |
1000 | 1286 | ||
@@ -1002,6 +1288,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1002 | outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue; | 1288 | outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue; |
1003 | } | 1289 | } |
1004 | 1290 | ||
1291 | private void RecordMalformedInboundPacket(IPEndPoint endPoint) | ||
1292 | { | ||
1293 | // if (m_malformedCount < 100) | ||
1294 | // m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString()); | ||
1295 | |||
1296 | IncomingMalformedPacketCount++; | ||
1297 | |||
1298 | if ((IncomingMalformedPacketCount % 10000) == 0) | ||
1299 | m_log.WarnFormat( | ||
1300 | "[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack. Last was from {1}", | ||
1301 | IncomingMalformedPacketCount, endPoint); | ||
1302 | } | ||
1303 | |||
1005 | public override void PacketReceived(UDPPacketBuffer buffer) | 1304 | public override void PacketReceived(UDPPacketBuffer buffer) |
1006 | { | 1305 | { |
1007 | // Debugging/Profiling | 1306 | // Debugging/Profiling |
@@ -1023,6 +1322,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1023 | // "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}", | 1322 | // "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}", |
1024 | // buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); | 1323 | // buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); |
1025 | 1324 | ||
1325 | RecordMalformedInboundPacket(endPoint); | ||
1326 | |||
1026 | return; // Drop undersized packet | 1327 | return; // Drop undersized packet |
1027 | } | 1328 | } |
1028 | 1329 | ||
@@ -1041,6 +1342,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1041 | // "[LLUDPSERVER]: Dropping packet with malformed header received from {0} in {1}", | 1342 | // "[LLUDPSERVER]: Dropping packet with malformed header received from {0} in {1}", |
1042 | // buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); | 1343 | // buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); |
1043 | 1344 | ||
1345 | RecordMalformedInboundPacket(endPoint); | ||
1346 | |||
1044 | return; // Malformed header | 1347 | return; // Malformed header |
1045 | } | 1348 | } |
1046 | 1349 | ||
@@ -1056,34 +1359,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1056 | // Only allocate a buffer for zerodecoding if the packet is zerocoded | 1359 | // Only allocate a buffer for zerodecoding if the packet is zerocoded |
1057 | ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null); | 1360 | ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null); |
1058 | } | 1361 | } |
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) | 1362 | catch (Exception e) |
1071 | { | 1363 | { |
1072 | if (m_malformedCount < 100) | 1364 | if (IncomingMalformedPacketCount < 100) |
1073 | m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString()); | 1365 | 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 | } | 1366 | } |
1080 | 1367 | ||
1081 | // Fail-safe check | 1368 | // Fail-safe check |
1082 | if (packet == null) | 1369 | if (packet == null) |
1083 | { | 1370 | { |
1084 | m_log.ErrorFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}:", | 1371 | if (IncomingMalformedPacketCount < 100) |
1085 | buffer.DataLength, buffer.RemoteEndPoint); | 1372 | { |
1086 | m_log.Error(Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)); | 1373 | m_log.WarnFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}, data {2}:", |
1374 | buffer.DataLength, buffer.RemoteEndPoint, Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)); | ||
1375 | } | ||
1376 | |||
1377 | RecordMalformedInboundPacket(endPoint); | ||
1378 | |||
1087 | return; | 1379 | return; |
1088 | } | 1380 | } |
1089 | 1381 | ||
@@ -1127,12 +1419,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1127 | queue.Enqueue(buffer); | 1419 | queue.Enqueue(buffer); |
1128 | return; | 1420 | return; |
1129 | } | 1421 | } |
1422 | else if (packet.Type == PacketType.CompleteAgentMovement) | ||
1423 | { | ||
1424 | // Send ack straight away to let the viewer know that we got it. | ||
1425 | SendAckImmediate(endPoint, packet.Header.Sequence); | ||
1426 | |||
1427 | // We need to copy the endpoint so that it doesn't get changed when another thread reuses the | ||
1428 | // buffer. | ||
1429 | object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; | ||
1430 | |||
1431 | Util.FireAndForget(HandleCompleteMovementIntoRegion, array); | ||
1432 | |||
1433 | return; | ||
1434 | } | ||
1130 | } | 1435 | } |
1131 | 1436 | ||
1132 | // Determine which agent this packet came from | 1437 | // Determine which agent this packet came from |
1133 | if (client == null || !(client is LLClientView)) | 1438 | if (client == null || !(client is LLClientView)) |
1134 | { | 1439 | { |
1135 | //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); | 1440 | //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); |
1441 | |||
1442 | IncomingOrphanedPacketCount++; | ||
1443 | |||
1444 | if ((IncomingOrphanedPacketCount % 10000) == 0) | ||
1445 | m_log.WarnFormat( | ||
1446 | "[LLUDPSERVER]: Received {0} orphaned packets so far. Last was from {1}", | ||
1447 | IncomingOrphanedPacketCount, endPoint); | ||
1448 | |||
1136 | return; | 1449 | return; |
1137 | } | 1450 | } |
1138 | 1451 | ||
@@ -1211,6 +1524,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1211 | 1524 | ||
1212 | #region Incoming Packet Accounting | 1525 | #region Incoming Packet Accounting |
1213 | 1526 | ||
1527 | // We're not going to worry about interlock yet since its not currently critical that this total count | ||
1528 | // is 100% correct | ||
1529 | if (packet.Header.Resent) | ||
1530 | IncomingPacketsResentCount++; | ||
1531 | |||
1214 | // Check the archive of received reliable packet IDs to see whether we already received this packet | 1532 | // 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)) | 1533 | if (packet.Header.Reliable && !udpClient.PacketArchive.TryEnqueue(packet.Header.Sequence)) |
1216 | { | 1534 | { |
@@ -1233,6 +1551,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1233 | LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length); | 1551 | LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length); |
1234 | #endregion BinaryStats | 1552 | #endregion BinaryStats |
1235 | 1553 | ||
1554 | if (packet.Type == PacketType.AgentUpdate) | ||
1555 | { | ||
1556 | if (m_discardAgentUpdates) | ||
1557 | return; | ||
1558 | |||
1559 | ((LLClientView)client).TotalAgentUpdates++; | ||
1560 | |||
1561 | AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet; | ||
1562 | |||
1563 | LLClientView llClient = client as LLClientView; | ||
1564 | if (agentUpdate.AgentData.SessionID != client.SessionId | ||
1565 | || agentUpdate.AgentData.AgentID != client.AgentId | ||
1566 | || !(llClient == null || llClient.CheckAgentUpdateSignificance(agentUpdate.AgentData)) ) | ||
1567 | { | ||
1568 | PacketPool.Instance.ReturnPacket(packet); | ||
1569 | return; | ||
1570 | } | ||
1571 | } | ||
1572 | |||
1236 | #region Ping Check Handling | 1573 | #region Ping Check Handling |
1237 | 1574 | ||
1238 | if (packet.Type == PacketType.StartPingCheck) | 1575 | if (packet.Type == PacketType.StartPingCheck) |
@@ -1421,7 +1758,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1421 | 1758 | ||
1422 | // We only want to send initial data to new clients, not ones which are being converted from child to root. | 1759 | // We only want to send initial data to new clients, not ones which are being converted from child to root. |
1423 | if (client != null) | 1760 | if (client != null) |
1424 | client.SceneAgent.SendInitialDataToMe(); | 1761 | { |
1762 | AgentCircuitData aCircuit = m_scene.AuthenticateHandler.GetAgentCircuitData(uccp.CircuitCode.Code); | ||
1763 | bool tp = (aCircuit.teleportFlags > 0); | ||
1764 | // Let's delay this for TP agents, otherwise the viewer doesn't know where to get resources from | ||
1765 | if (!tp) | ||
1766 | client.SceneAgent.SendInitialDataToMe(); | ||
1767 | } | ||
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); |
@@ -1476,6 +1819,116 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1476 | } | 1819 | } |
1477 | } | 1820 | } |
1478 | 1821 | ||
1822 | private void HandleCompleteMovementIntoRegion(object o) | ||
1823 | { | ||
1824 | IPEndPoint endPoint = null; | ||
1825 | IClientAPI client = null; | ||
1826 | |||
1827 | try | ||
1828 | { | ||
1829 | object[] array = (object[])o; | ||
1830 | endPoint = (IPEndPoint)array[0]; | ||
1831 | CompleteAgentMovementPacket packet = (CompleteAgentMovementPacket)array[1]; | ||
1832 | |||
1833 | m_log.DebugFormat( | ||
1834 | "[LLUDPSERVER]: Handling CompleteAgentMovement request from {0} in {1}", endPoint, m_scene.Name); | ||
1835 | |||
1836 | // Determine which agent this packet came from | ||
1837 | // We need to wait here because in when using the OpenSimulator V2 teleport protocol to travel to a destination | ||
1838 | // simulator with no existing child presence, the viewer (at least LL 3.3.4) will send UseCircuitCode | ||
1839 | // and then CompleteAgentMovement immediately without waiting for an ack. As we are now handling these | ||
1840 | // packets asynchronously, we need to account for this thread proceeding more quickly than the | ||
1841 | // UseCircuitCode thread. | ||
1842 | int count = 40; | ||
1843 | while (count-- > 0) | ||
1844 | { | ||
1845 | if (m_scene.TryGetClient(endPoint, out client)) | ||
1846 | { | ||
1847 | if (!client.IsActive) | ||
1848 | { | ||
1849 | // This check exists to catch a condition where the client has been closed by another thread | ||
1850 | // but has not yet been removed from the client manager (and possibly a new connection has | ||
1851 | // not yet been established). | ||
1852 | m_log.DebugFormat( | ||
1853 | "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client is not active yet. Waiting.", | ||
1854 | endPoint, client.Name, m_scene.Name); | ||
1855 | } | ||
1856 | else if (client.SceneAgent == null) | ||
1857 | { | ||
1858 | // This check exists to catch a condition where the new client has been added to the client | ||
1859 | // manager but the SceneAgent has not yet been set in Scene.AddNewAgent(). If we are too | ||
1860 | // eager, then the new ScenePresence may not have registered a listener for this messsage | ||
1861 | // before we try to process it. | ||
1862 | // XXX: A better long term fix may be to add the SceneAgent before the client is added to | ||
1863 | // the client manager | ||
1864 | m_log.DebugFormat( | ||
1865 | "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client SceneAgent not set yet. Waiting.", | ||
1866 | endPoint, client.Name, m_scene.Name); | ||
1867 | } | ||
1868 | else | ||
1869 | { | ||
1870 | break; | ||
1871 | } | ||
1872 | } | ||
1873 | else | ||
1874 | { | ||
1875 | m_log.DebugFormat( | ||
1876 | "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} in {1} but no client exists yet. Waiting.", | ||
1877 | endPoint, m_scene.Name); | ||
1878 | } | ||
1879 | |||
1880 | Thread.Sleep(200); | ||
1881 | } | ||
1882 | |||
1883 | if (client == null) | ||
1884 | { | ||
1885 | m_log.DebugFormat( | ||
1886 | "[LLUDPSERVER]: No client found for CompleteAgentMovement from {0} in {1} after wait. Dropping.", | ||
1887 | endPoint, m_scene.Name); | ||
1888 | |||
1889 | return; | ||
1890 | } | ||
1891 | else if (!client.IsActive || client.SceneAgent == null) | ||
1892 | { | ||
1893 | // This check exists to catch a condition where the client has been closed by another thread | ||
1894 | // but has not yet been removed from the client manager. | ||
1895 | // The packet could be simply ignored but it is useful to know if this condition occurred for other debugging | ||
1896 | // purposes. | ||
1897 | m_log.DebugFormat( | ||
1898 | "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client is not active after wait. Dropping.", | ||
1899 | endPoint, client.Name, m_scene.Name); | ||
1900 | |||
1901 | return; | ||
1902 | } | ||
1903 | |||
1904 | IncomingPacket incomingPacket1; | ||
1905 | |||
1906 | // Inbox insertion | ||
1907 | if (UsePools) | ||
1908 | { | ||
1909 | incomingPacket1 = m_incomingPacketPool.GetObject(); | ||
1910 | incomingPacket1.Client = (LLClientView)client; | ||
1911 | incomingPacket1.Packet = packet; | ||
1912 | } | ||
1913 | else | ||
1914 | { | ||
1915 | incomingPacket1 = new IncomingPacket((LLClientView)client, packet); | ||
1916 | } | ||
1917 | |||
1918 | packetInbox.Enqueue(incomingPacket1); | ||
1919 | } | ||
1920 | catch (Exception e) | ||
1921 | { | ||
1922 | m_log.ErrorFormat( | ||
1923 | "[LLUDPSERVER]: CompleteAgentMovement handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}", | ||
1924 | endPoint != null ? endPoint.ToString() : "n/a", | ||
1925 | client != null ? client.Name : "unknown", | ||
1926 | client != null ? client.AgentId.ToString() : "unknown", | ||
1927 | e.Message, | ||
1928 | e.StackTrace); | ||
1929 | } | ||
1930 | } | ||
1931 | |||
1479 | /// <summary> | 1932 | /// <summary> |
1480 | /// Send an ack immediately to the given endpoint. | 1933 | /// Send an ack immediately to the given endpoint. |
1481 | /// </summary> | 1934 | /// </summary> |
@@ -1544,6 +1997,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1544 | 1997 | ||
1545 | client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); | 1998 | client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); |
1546 | client.OnLogout += LogoutHandler; | 1999 | client.OnLogout += LogoutHandler; |
2000 | client.DebugPacketLevel = DefaultClientPacketDebugLevel; | ||
1547 | 2001 | ||
1548 | ((LLClientView)client).DisableFacelights = m_disableFacelights; | 2002 | ((LLClientView)client).DisableFacelights = m_disableFacelights; |
1549 | 2003 | ||
@@ -1562,21 +2016,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1562 | /// regular client pings. | 2016 | /// regular client pings. |
1563 | /// </remarks> | 2017 | /// </remarks> |
1564 | /// <param name='client'></param> | 2018 | /// <param name='client'></param> |
1565 | private void DeactivateClientDueToTimeout(LLClientView client) | 2019 | /// <param name='timeoutTicks'></param> |
2020 | private void DeactivateClientDueToTimeout(LLClientView client, int timeoutTicks) | ||
1566 | { | 2021 | { |
1567 | lock (client.CloseSyncLock) | 2022 | lock (client.CloseSyncLock) |
1568 | { | 2023 | { |
2024 | ClientLogoutsDueToNoReceives++; | ||
2025 | |||
1569 | m_log.WarnFormat( | 2026 | m_log.WarnFormat( |
1570 | "[LLUDPSERVER]: Ack timeout, disconnecting {0} agent for {1} in {2}", | 2027 | "[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); | 2028 | client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, timeoutTicks, m_scene.Name); |
1572 | |||
1573 | StatsManager.SimExtraStats.AddAbnormalClientThreadTermination(); | ||
1574 | 2029 | ||
1575 | if (!client.SceneAgent.IsChildAgent) | 2030 | if (!client.SceneAgent.IsChildAgent) |
1576 | client.Kick("Simulator logged you out due to connection timeout"); | 2031 | client.Kick("Simulator logged you out due to connection timeout."); |
1577 | |||
1578 | client.CloseWithoutChecks(true); | ||
1579 | } | 2032 | } |
2033 | |||
2034 | m_scene.CloseAgent(client.AgentId, true); | ||
1580 | } | 2035 | } |
1581 | 2036 | ||
1582 | private void IncomingPacketHandler() | 2037 | private void IncomingPacketHandler() |
@@ -1592,6 +2047,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1592 | { | 2047 | { |
1593 | IncomingPacket incomingPacket = null; | 2048 | IncomingPacket incomingPacket = null; |
1594 | 2049 | ||
2050 | /* | ||
1595 | // HACK: This is a test to try and rate limit packet handling on Mono. | 2051 | // 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 | 2052 | // If it works, a more elegant solution can be devised |
1597 | if (Util.FireAndForgetCount() < 2) | 2053 | if (Util.FireAndForgetCount() < 2) |
@@ -1599,6 +2055,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1599 | //m_log.Debug("[LLUDPSERVER]: Incoming packet handler is sleeping"); | 2055 | //m_log.Debug("[LLUDPSERVER]: Incoming packet handler is sleeping"); |
1600 | Thread.Sleep(30); | 2056 | Thread.Sleep(30); |
1601 | } | 2057 | } |
2058 | */ | ||
1602 | 2059 | ||
1603 | if (packetInbox.Dequeue(100, ref incomingPacket)) | 2060 | if (packetInbox.Dequeue(100, ref incomingPacket)) |
1604 | { | 2061 | { |
@@ -1694,8 +2151,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1694 | 2151 | ||
1695 | // If nothing was sent, sleep for the minimum amount of time before a | 2152 | // If nothing was sent, sleep for the minimum amount of time before a |
1696 | // token bucket could get more tokens | 2153 | // token bucket could get more tokens |
2154 | //if (!m_packetSent) | ||
2155 | // Thread.Sleep((int)TickCountResolution); | ||
2156 | // | ||
2157 | // Instead, now wait for data present to be explicitly signalled. Evidence so far is that with | ||
2158 | // modern mono it reduces CPU base load since there is no more continuous polling. | ||
1697 | if (!m_packetSent) | 2159 | if (!m_packetSent) |
1698 | Thread.Sleep((int)TickCountResolution); | 2160 | m_dataPresentEvent.WaitOne(100); |
1699 | 2161 | ||
1700 | Watchdog.UpdateThread(); | 2162 | Watchdog.UpdateThread(); |
1701 | } | 2163 | } |
@@ -1912,7 +2374,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1912 | if (!client.IsLoggingOut) | 2374 | if (!client.IsLoggingOut) |
1913 | { | 2375 | { |
1914 | client.IsLoggingOut = true; | 2376 | client.IsLoggingOut = true; |
1915 | client.Close(false, false); | 2377 | m_scene.CloseAgent(client.AgentId, false); |
1916 | } | 2378 | } |
1917 | } | 2379 | } |
1918 | } | 2380 | } |
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 | } |