diff options
Diffstat (limited to 'OpenSim/Region/ClientStack')
18 files changed, 1160 insertions, 441 deletions
diff --git a/OpenSim/Region/ClientStack/IClientNetworkServer.cs b/OpenSim/Region/ClientStack/IClientNetworkServer.cs index 54a441b..bb7e6d0 100644 --- a/OpenSim/Region/ClientStack/IClientNetworkServer.cs +++ b/OpenSim/Region/ClientStack/IClientNetworkServer.cs | |||
@@ -38,11 +38,22 @@ namespace OpenSim.Region.ClientStack | |||
38 | IPAddress _listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, | 38 | IPAddress _listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, |
39 | AgentCircuitManager authenticateClass); | 39 | AgentCircuitManager authenticateClass); |
40 | 40 | ||
41 | void NetworkStop(); | ||
42 | bool HandlesRegion(Location x); | 41 | bool HandlesRegion(Location x); |
43 | void AddScene(IScene x); | ||
44 | 42 | ||
43 | /// <summary> | ||
44 | /// Add the given scene to be handled by this IClientNetworkServer. | ||
45 | /// </summary> | ||
46 | /// <param name='scene'></param> | ||
47 | void AddScene(IScene scene); | ||
48 | |||
49 | /// <summary> | ||
50 | /// Start sending and receiving data. | ||
51 | /// </summary> | ||
45 | void Start(); | 52 | void Start(); |
53 | |||
54 | /// <summary> | ||
55 | /// Stop sending and receiving data. | ||
56 | /// </summary> | ||
46 | void Stop(); | 57 | void Stop(); |
47 | } | 58 | } |
48 | } | 59 | } |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs new file mode 100644 index 0000000..9f2aed0 --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs | |||
@@ -0,0 +1,139 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Specialized; | ||
31 | using System.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 | |||
53 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AvatarPickerSearchModule")] | ||
54 | public class AvatarPickerSearchModule : INonSharedRegionModule | ||
55 | { | ||
56 | private static readonly ILog m_log = | ||
57 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
58 | |||
59 | private Scene m_scene; | ||
60 | private IPeople m_People; | ||
61 | private bool m_Enabled = false; | ||
62 | |||
63 | private string m_URL; | ||
64 | |||
65 | #region ISharedRegionModule Members | ||
66 | |||
67 | public void Initialise(IConfigSource source) | ||
68 | { | ||
69 | IConfig config = source.Configs["ClientStack.LindenCaps"]; | ||
70 | if (config == null) | ||
71 | return; | ||
72 | |||
73 | m_URL = config.GetString("Cap_AvatarPickerSearch", string.Empty); | ||
74 | // Cap doesn't exist | ||
75 | if (m_URL != string.Empty) | ||
76 | m_Enabled = true; | ||
77 | } | ||
78 | |||
79 | public void AddRegion(Scene s) | ||
80 | { | ||
81 | if (!m_Enabled) | ||
82 | return; | ||
83 | |||
84 | m_scene = s; | ||
85 | } | ||
86 | |||
87 | public void RemoveRegion(Scene s) | ||
88 | { | ||
89 | if (!m_Enabled) | ||
90 | return; | ||
91 | |||
92 | m_scene.EventManager.OnRegisterCaps -= RegisterCaps; | ||
93 | m_scene = null; | ||
94 | } | ||
95 | |||
96 | public void RegionLoaded(Scene s) | ||
97 | { | ||
98 | if (!m_Enabled) | ||
99 | return; | ||
100 | |||
101 | m_People = m_scene.RequestModuleInterface<IPeople>(); | ||
102 | m_scene.EventManager.OnRegisterCaps += RegisterCaps; | ||
103 | } | ||
104 | |||
105 | public void PostInitialise() | ||
106 | { | ||
107 | } | ||
108 | |||
109 | public void Close() { } | ||
110 | |||
111 | public string Name { get { return "AvatarPickerSearchModule"; } } | ||
112 | |||
113 | public Type ReplaceableInterface | ||
114 | { | ||
115 | get { return null; } | ||
116 | } | ||
117 | |||
118 | #endregion | ||
119 | |||
120 | public void RegisterCaps(UUID agentID, Caps caps) | ||
121 | { | ||
122 | UUID capID = UUID.Random(); | ||
123 | |||
124 | if (m_URL == "localhost") | ||
125 | { | ||
126 | m_log.DebugFormat("[AVATAR PICKER SEARCH]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); | ||
127 | caps.RegisterHandler( | ||
128 | "AvatarPickerSearch", | ||
129 | new AvatarPickerSearchHandler("/CAPS/" + capID + "/", m_People, "AvatarPickerSearch", "Search for avatars by name")); | ||
130 | } | ||
131 | else | ||
132 | { | ||
133 | // m_log.DebugFormat("[AVATAR PICKER SEARCH]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName); | ||
134 | caps.RegisterHandler("AvatarPickerSearch", m_URL); | ||
135 | } | ||
136 | } | ||
137 | |||
138 | } | ||
139 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs index 8241e07..762e22a 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 | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs index eb40eb1..4272375 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,12 @@ 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 | m_log.WarnFormat("[EVENTQUEUE]: (Enqueue) No queue found for agent {0} in region {1}", avatarID, m_scene.RegionInfo.RegionName); | ||
226 | } | 233 | } |
227 | catch (NullReferenceException e) | 234 | catch (NullReferenceException e) |
228 | { | 235 | { |
@@ -237,44 +244,14 @@ namespace OpenSim.Region.ClientStack.Linden | |||
237 | 244 | ||
238 | private void ClientClosed(UUID agentID, Scene scene) | 245 | private void ClientClosed(UUID agentID, Scene scene) |
239 | { | 246 | { |
240 | // m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", agentID, m_scene.RegionInfo.RegionName); | 247 | //m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", agentID, m_scene.RegionInfo.RegionName); |
241 | |||
242 | int count = 0; | ||
243 | while (queues.ContainsKey(agentID) && queues[agentID].Count > 0 && count++ < 5) | ||
244 | { | ||
245 | Thread.Sleep(1000); | ||
246 | } | ||
247 | 248 | ||
248 | lock (queues) | 249 | lock (queues) |
249 | { | ||
250 | queues.Remove(agentID); | 250 | queues.Remove(agentID); |
251 | } | ||
252 | 251 | ||
253 | List<UUID> removeitems = new List<UUID>(); | 252 | List<UUID> removeitems = new List<UUID>(); |
254 | lock (m_AvatarQueueUUIDMapping) | 253 | lock (m_AvatarQueueUUIDMapping) |
255 | { | 254 | 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 | 255 | ||
279 | UUID searchval = UUID.Zero; | 256 | UUID searchval = UUID.Zero; |
280 | 257 | ||
@@ -295,19 +272,9 @@ namespace OpenSim.Region.ClientStack.Linden | |||
295 | foreach (UUID ky in removeitems) | 272 | foreach (UUID ky in removeitems) |
296 | m_QueueUUIDAvatarMapping.Remove(ky); | 273 | m_QueueUUIDAvatarMapping.Remove(ky); |
297 | } | 274 | } |
298 | } | ||
299 | 275 | ||
300 | private void MakeChildAgent(ScenePresence avatar) | 276 | // m_log.DebugFormat("[EVENTQUEUE]: Deleted queues for {0} in region {1}", agentID, m_scene.RegionInfo.RegionName); |
301 | { | 277 | |
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 | } | 278 | } |
312 | 279 | ||
313 | /// <summary> | 280 | /// <summary> |
@@ -359,28 +326,9 @@ namespace OpenSim.Region.ClientStack.Linden | |||
359 | m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID); | 326 | m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID); |
360 | } | 327 | } |
361 | 328 | ||
362 | string eventQueueGetPath = GenerateEqgCapPath(eventQueueGetUUID); | 329 | caps.RegisterPollHandler( |
363 | 330 | "EventQueueGet", | |
364 | // Register this as a caps handler | 331 | 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 | 332 | ||
385 | Random rnd = new Random(Environment.TickCount); | 333 | Random rnd = new Random(Environment.TickCount); |
386 | lock (m_ids) | 334 | lock (m_ids) |
@@ -398,7 +346,10 @@ namespace OpenSim.Region.ClientStack.Linden | |||
398 | Queue<OSD> queue = GetQueue(agentID); | 346 | Queue<OSD> queue = GetQueue(agentID); |
399 | if (queue != null) | 347 | if (queue != null) |
400 | lock (queue) | 348 | lock (queue) |
349 | { | ||
350 | //m_log.WarnFormat("POLLED FOR EVENTS BY {0} in {1} -- {2}", agentID, m_scene.RegionInfo.RegionName, queue.Count); | ||
401 | return queue.Count > 0; | 351 | return queue.Count > 0; |
352 | } | ||
402 | 353 | ||
403 | return false; | 354 | return false; |
404 | } | 355 | } |
@@ -421,9 +372,14 @@ namespace OpenSim.Region.ClientStack.Linden | |||
421 | public Hashtable GetEvents(UUID requestID, UUID pAgentId) | 372 | public Hashtable GetEvents(UUID requestID, UUID pAgentId) |
422 | { | 373 | { |
423 | if (DebugLevel >= 2) | 374 | if (DebugLevel >= 2) |
424 | m_log.DebugFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.RegionInfo.RegionName); | 375 | m_log.WarnFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.RegionInfo.RegionName); |
376 | |||
377 | Queue<OSD> queue = GetQueue(pAgentId); | ||
378 | if (queue == null) | ||
379 | { | ||
380 | return NoEvents(requestID, pAgentId); | ||
381 | } | ||
425 | 382 | ||
426 | Queue<OSD> queue = TryGetQueue(pAgentId); | ||
427 | OSD element; | 383 | OSD element; |
428 | lock (queue) | 384 | lock (queue) |
429 | { | 385 | { |
@@ -794,12 +750,12 @@ namespace OpenSim.Region.ClientStack.Linden | |||
794 | 750 | ||
795 | } | 751 | } |
796 | 752 | ||
797 | public void ChatterBoxSessionAgentListUpdates(UUID sessionID, UUID fromAgent, UUID toAgent, bool canVoiceChat, | 753 | public void ChatterBoxSessionAgentListUpdates(UUID sessionID, UUID fromAgent, UUID anotherAgent, bool canVoiceChat, |
798 | bool isModerator, bool textMute) | 754 | bool isModerator, bool textMute) |
799 | { | 755 | { |
800 | OSD item = EventQueueHelper.ChatterBoxSessionAgentListUpdates(sessionID, fromAgent, canVoiceChat, | 756 | OSD item = EventQueueHelper.ChatterBoxSessionAgentListUpdates(sessionID, fromAgent, canVoiceChat, |
801 | isModerator, textMute); | 757 | isModerator, textMute); |
802 | Enqueue(item, toAgent); | 758 | Enqueue(item, fromAgent); |
803 | //m_log.InfoFormat("########### eq ChatterBoxSessionAgentListUpdates #############\n{0}", item); | 759 | //m_log.InfoFormat("########### eq ChatterBoxSessionAgentListUpdates #############\n{0}", item); |
804 | } | 760 | } |
805 | 761 | ||
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 a42c96c..c8e1e83 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs | |||
@@ -82,6 +82,8 @@ namespace OpenSim.Region.ClientStack.Linden | |||
82 | 82 | ||
83 | private Dictionary<UUID,PollServiceTextureEventArgs> m_pollservices = new Dictionary<UUID,PollServiceTextureEventArgs>(); | 83 | private Dictionary<UUID,PollServiceTextureEventArgs> m_pollservices = new Dictionary<UUID,PollServiceTextureEventArgs>(); |
84 | 84 | ||
85 | private string m_URL; | ||
86 | |||
85 | #region ISharedRegionModule Members | 87 | #region ISharedRegionModule Members |
86 | 88 | ||
87 | public void Initialise(IConfigSource source) | 89 | public void Initialise(IConfigSource source) |
@@ -210,7 +212,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
210 | private Scene m_scene; | 212 | private Scene m_scene; |
211 | private CapsDataThrottler m_throttler = new CapsDataThrottler(100000, 1400000,10000); | 213 | private CapsDataThrottler m_throttler = new CapsDataThrottler(100000, 1400000,10000); |
212 | public PollServiceTextureEventArgs(UUID pId, Scene scene) : | 214 | public PollServiceTextureEventArgs(UUID pId, Scene scene) : |
213 | base(null, null, null, null, pId, int.MaxValue) | 215 | base(null, "", null, null, null, pId, int.MaxValue) |
214 | { | 216 | { |
215 | m_scene = scene; | 217 | m_scene = scene; |
216 | // x is request id, y is userid | 218 | // x is request id, y is userid |
@@ -343,13 +345,13 @@ namespace OpenSim.Region.ClientStack.Linden | |||
343 | 345 | ||
344 | private void RegisterCaps(UUID agentID, Caps caps) | 346 | private void RegisterCaps(UUID agentID, Caps caps) |
345 | { | 347 | { |
346 | string capUrl = "/CAPS/" + UUID.Random() + "/"; | 348 | m_URL = "/CAPS/" + UUID.Random() + "/"; |
347 | 349 | ||
348 | // Register this as a poll service | 350 | // Register this as a poll service |
349 | PollServiceTextureEventArgs args = new PollServiceTextureEventArgs(agentID, m_scene); | 351 | PollServiceTextureEventArgs args = new PollServiceTextureEventArgs(agentID, m_scene); |
350 | 352 | ||
351 | args.Type = PollServiceEventArgs.EventType.Texture; | 353 | args.Type = PollServiceEventArgs.EventType.Texture; |
352 | MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args); | 354 | MainServer.Instance.AddPollServiceHTTPHandler(m_URL, args); |
353 | 355 | ||
354 | string hostName = m_scene.RegionInfo.ExternalHostName; | 356 | string hostName = m_scene.RegionInfo.ExternalHostName; |
355 | uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port; | 357 | uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port; |
@@ -361,20 +363,23 @@ namespace OpenSim.Region.ClientStack.Linden | |||
361 | port = MainServer.Instance.SSLPort; | 363 | port = MainServer.Instance.SSLPort; |
362 | protocol = "https"; | 364 | protocol = "https"; |
363 | } | 365 | } |
364 | caps.RegisterHandler("GetTexture", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl)); | 366 | |
367 | IExternalCapsModule handler = m_scene.RequestModuleInterface<IExternalCapsModule>(); | ||
368 | if (handler != null) | ||
369 | handler.RegisterExternalUserCapsHandler(agentID, caps, "GetTexture", m_URL); | ||
370 | else | ||
371 | caps.RegisterHandler("GetTexture", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, m_URL)); | ||
365 | m_pollservices[agentID] = args; | 372 | m_pollservices[agentID] = args; |
366 | m_capsDict[agentID] = capUrl; | 373 | m_capsDict[agentID] = m_URL; |
367 | } | 374 | } |
368 | 375 | ||
369 | private void DeregisterCaps(UUID agentID, Caps caps) | 376 | private void DeregisterCaps(UUID agentID, Caps caps) |
370 | { | 377 | { |
371 | string capUrl; | ||
372 | PollServiceTextureEventArgs args; | 378 | PollServiceTextureEventArgs args; |
373 | if (m_capsDict.TryGetValue(agentID, out capUrl)) | 379 | |
374 | { | 380 | MainServer.Instance.RemoveHTTPHandler("", m_URL); |
375 | MainServer.Instance.RemoveHTTPHandler("", capUrl); | 381 | m_capsDict.Remove(agentID); |
376 | m_capsDict.Remove(agentID); | 382 | |
377 | } | ||
378 | if (m_pollservices.TryGetValue(agentID, out args)) | 383 | if (m_pollservices.TryGetValue(agentID, out args)) |
379 | { | 384 | { |
380 | m_pollservices.Remove(agentID); | 385 | m_pollservices.Remove(agentID); |
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..cf95463 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..f816ad3 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 | ||
@@ -284,47 +304,53 @@ namespace OpenSim.Region.ClientStack.Linden | |||
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 | if (m_fetchInventoryDescendents2Url == "") |
308 | return; | ||
288 | 309 | ||
289 | // Register this as a poll service | 310 | // Register this as a poll service |
290 | PollServiceInventoryEventArgs args = new PollServiceInventoryEventArgs(m_scene, agentID); | 311 | PollServiceInventoryEventArgs args |
291 | 312 | = new PollServiceInventoryEventArgs(m_scene, "/CAPS/" + UUID.Random() + "/", agentID); | |
292 | args.Type = PollServiceEventArgs.EventType.Inventory; | 313 | 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 | 314 | ||
307 | m_capsDict[agentID] = capUrl; | 315 | caps.RegisterPollHandler("FetchInventoryDescendents2", args); |
316 | |||
317 | // MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args); | ||
318 | // | ||
319 | // string hostName = m_scene.RegionInfo.ExternalHostName; | ||
320 | // uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port; | ||
321 | // string protocol = "http"; | ||
322 | // | ||
323 | // if (MainServer.Instance.UseSSL) | ||
324 | // { | ||
325 | // hostName = MainServer.Instance.SSLCommonName; | ||
326 | // port = MainServer.Instance.SSLPort; | ||
327 | // protocol = "https"; | ||
328 | // } | ||
329 | // | ||
330 | // caps.RegisterHandler("FetchInventoryDescendents2", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl)); | ||
308 | } | 331 | } |
309 | 332 | ||
310 | private void DeregisterCaps(UUID agentID, Caps caps) | 333 | // private void DeregisterCaps(UUID agentID, Caps caps) |
311 | { | 334 | // { |
312 | string capUrl; | 335 | // string capUrl; |
313 | 336 | // | |
314 | if (m_capsDict.TryGetValue(agentID, out capUrl)) | 337 | // if (m_capsDict.TryGetValue(agentID, out capUrl)) |
315 | { | 338 | // { |
316 | MainServer.Instance.RemoveHTTPHandler("", capUrl); | 339 | // MainServer.Instance.RemoveHTTPHandler("", capUrl); |
317 | m_capsDict.Remove(agentID); | 340 | // m_capsDict.Remove(agentID); |
318 | } | 341 | // } |
319 | } | 342 | // } |
320 | 343 | ||
321 | private void DoInventoryRequests() | 344 | private void DoInventoryRequests() |
322 | { | 345 | { |
323 | while (true) | 346 | while (true) |
324 | { | 347 | { |
348 | Watchdog.UpdateThread(); | ||
349 | |||
325 | aPollRequest poolreq = m_queue.Dequeue(); | 350 | aPollRequest poolreq = m_queue.Dequeue(); |
326 | 351 | ||
327 | poolreq.thepoll.Process(poolreq); | 352 | if (poolreq != null && poolreq.thepoll != null) |
353 | poolreq.thepoll.Process(poolreq); | ||
328 | } | 354 | } |
329 | } | 355 | } |
330 | } | 356 | } |
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 eebb8ae..0e20e38 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; |
@@ -367,7 +369,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 | 369 | /// 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. | 370 | /// cannot retain a reference to it outside of that method. |
369 | /// </remarks> | 371 | /// </remarks> |
370 | private AgentUpdateArgs m_lastAgentUpdateArgs; | 372 | private AgentUpdateArgs m_thisAgentUpdateArgs = new AgentUpdateArgs(); |
371 | 373 | ||
372 | protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>(); | 374 | 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 | 375 | protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers |
@@ -504,6 +506,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
504 | m_udpServer = udpServer; | 506 | m_udpServer = udpServer; |
505 | m_udpClient = udpClient; | 507 | m_udpClient = udpClient; |
506 | m_udpClient.OnQueueEmpty += HandleQueueEmpty; | 508 | m_udpClient.OnQueueEmpty += HandleQueueEmpty; |
509 | m_udpClient.HasUpdates += HandleHasUpdates; | ||
507 | m_udpClient.OnPacketStats += PopulateStats; | 510 | m_udpClient.OnPacketStats += PopulateStats; |
508 | 511 | ||
509 | m_prioritizer = new Prioritizer(m_scene); | 512 | m_prioritizer = new Prioritizer(m_scene); |
@@ -709,12 +712,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
709 | //there is a local handler for this packet type | 712 | //there is a local handler for this packet type |
710 | if (pprocessor.Async) | 713 | if (pprocessor.Async) |
711 | { | 714 | { |
715 | ClientInfo cinfo = UDPClient.GetClientInfo(); | ||
716 | if (!cinfo.AsyncRequests.ContainsKey(packet.Type.ToString())) | ||
717 | cinfo.AsyncRequests[packet.Type.ToString()] = 0; | ||
718 | cinfo.AsyncRequests[packet.Type.ToString()]++; | ||
719 | |||
712 | object obj = new AsyncPacketProcess(this, pprocessor.method, packet); | 720 | object obj = new AsyncPacketProcess(this, pprocessor.method, packet); |
713 | Util.FireAndForget(ProcessSpecificPacketAsync, obj); | 721 | Util.FireAndForget(ProcessSpecificPacketAsync, obj); |
714 | result = true; | 722 | result = true; |
715 | } | 723 | } |
716 | else | 724 | else |
717 | { | 725 | { |
726 | ClientInfo cinfo = UDPClient.GetClientInfo(); | ||
727 | if (!cinfo.SyncRequests.ContainsKey(packet.Type.ToString())) | ||
728 | cinfo.SyncRequests[packet.Type.ToString()] = 0; | ||
729 | cinfo.SyncRequests[packet.Type.ToString()]++; | ||
730 | |||
718 | result = pprocessor.method(this, packet); | 731 | result = pprocessor.method(this, packet); |
719 | } | 732 | } |
720 | } | 733 | } |
@@ -729,6 +742,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
729 | } | 742 | } |
730 | if (found) | 743 | if (found) |
731 | { | 744 | { |
745 | ClientInfo cinfo = UDPClient.GetClientInfo(); | ||
746 | if (!cinfo.GenericRequests.ContainsKey(packet.Type.ToString())) | ||
747 | cinfo.GenericRequests[packet.Type.ToString()] = 0; | ||
748 | cinfo.GenericRequests[packet.Type.ToString()]++; | ||
749 | |||
732 | result = method(this, packet); | 750 | result = method(this, packet); |
733 | } | 751 | } |
734 | } | 752 | } |
@@ -820,12 +838,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
820 | handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType); | 838 | handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType); |
821 | handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes; | 839 | handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes; |
822 | 840 | ||
823 | handshake.RegionInfo4 = new RegionHandshakePacket.RegionInfo4Block[0]; | 841 | handshake.RegionInfo4 = new RegionHandshakePacket.RegionInfo4Block[1]; |
824 | // OutPacket(handshake, ThrottleOutPacketType.Task); | 842 | handshake.RegionInfo4[0] = new RegionHandshakePacket.RegionInfo4Block(); |
825 | // use same as MoveAgentIntoRegion (both should be task ) | 843 | handshake.RegionInfo4[0].RegionFlagsExtended = args.regionFlags; |
844 | handshake.RegionInfo4[0].RegionProtocols = 0; // 1 here would indicate that SSB is supported | ||
845 | |||
826 | OutPacket(handshake, ThrottleOutPacketType.Unknown); | 846 | OutPacket(handshake, ThrottleOutPacketType.Unknown); |
827 | } | 847 | } |
828 | 848 | ||
849 | |||
829 | public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look) | 850 | public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look) |
830 | { | 851 | { |
831 | AgentMovementCompletePacket mov = (AgentMovementCompletePacket)PacketPool.Instance.GetPacket(PacketType.AgentMovementComplete); | 852 | AgentMovementCompletePacket mov = (AgentMovementCompletePacket)PacketPool.Instance.GetPacket(PacketType.AgentMovementComplete); |
@@ -1580,7 +1601,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1580 | OutPacket(pc, ThrottleOutPacketType.Unknown); | 1601 | OutPacket(pc, ThrottleOutPacketType.Unknown); |
1581 | } | 1602 | } |
1582 | 1603 | ||
1583 | public void SendKillObject(ulong regionHandle, List<uint> localIDs) | 1604 | public void SendKillObject(List<uint> localIDs) |
1584 | { | 1605 | { |
1585 | // foreach (uint id in localIDs) | 1606 | // foreach (uint id in localIDs) |
1586 | // m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle); | 1607 | // m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle); |
@@ -3797,6 +3818,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3797 | ResendPrimUpdate(update); | 3818 | ResendPrimUpdate(update); |
3798 | } | 3819 | } |
3799 | 3820 | ||
3821 | // OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>(); | ||
3822 | // OpenSim.Framework.Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>> compressedUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>>(); | ||
3823 | // OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>(); | ||
3824 | // OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>(); | ||
3825 | // | ||
3826 | // OpenSim.Framework.Lazy<List<EntityUpdate>> objectUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); | ||
3827 | // OpenSim.Framework.Lazy<List<EntityUpdate>> compressedUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); | ||
3828 | // OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); | ||
3829 | // OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); | ||
3830 | |||
3831 | |||
3800 | private void ProcessEntityUpdates(int maxUpdates) | 3832 | private void ProcessEntityUpdates(int maxUpdates) |
3801 | { | 3833 | { |
3802 | OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>(); | 3834 | OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>(); |
@@ -3809,6 +3841,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3809 | OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); | 3841 | OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); |
3810 | OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); | 3842 | OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); |
3811 | 3843 | ||
3844 | // objectUpdateBlocks.Value.Clear(); | ||
3845 | // compressedUpdateBlocks.Value.Clear(); | ||
3846 | // terseUpdateBlocks.Value.Clear(); | ||
3847 | // terseAgentUpdateBlocks.Value.Clear(); | ||
3848 | // objectUpdates.Value.Clear(); | ||
3849 | // compressedUpdates.Value.Clear(); | ||
3850 | // terseUpdates.Value.Clear(); | ||
3851 | // terseAgentUpdates.Value.Clear(); | ||
3852 | |||
3812 | // Check to see if this is a flush | 3853 | // Check to see if this is a flush |
3813 | if (maxUpdates <= 0) | 3854 | if (maxUpdates <= 0) |
3814 | { | 3855 | { |
@@ -4125,8 +4166,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4125 | 4166 | ||
4126 | void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories) | 4167 | void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories) |
4127 | { | 4168 | { |
4169 | // if (!m_udpServer.IsRunningOutbound) | ||
4170 | // return; | ||
4171 | |||
4128 | if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) | 4172 | if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) |
4129 | { | 4173 | { |
4174 | // if (!m_udpServer.IsRunningOutbound) | ||
4175 | // return; | ||
4176 | |||
4130 | if (m_maxUpdates == 0 || m_LastQueueFill == 0) | 4177 | if (m_maxUpdates == 0 || m_LastQueueFill == 0) |
4131 | { | 4178 | { |
4132 | m_maxUpdates = m_udpServer.PrimUpdatesPerCallback; | 4179 | m_maxUpdates = m_udpServer.PrimUpdatesPerCallback; |
@@ -4152,6 +4199,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4152 | ImageManager.ProcessImageQueue(m_udpServer.TextureSendLimit); | 4199 | ImageManager.ProcessImageQueue(m_udpServer.TextureSendLimit); |
4153 | } | 4200 | } |
4154 | 4201 | ||
4202 | internal bool HandleHasUpdates(ThrottleOutPacketTypeFlags categories) | ||
4203 | { | ||
4204 | bool hasUpdates = false; | ||
4205 | |||
4206 | if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) | ||
4207 | { | ||
4208 | if (m_entityUpdates.Count > 0) | ||
4209 | hasUpdates = true; | ||
4210 | else if (m_entityProps.Count > 0) | ||
4211 | hasUpdates = true; | ||
4212 | } | ||
4213 | |||
4214 | if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0) | ||
4215 | { | ||
4216 | if (ImageManager.HasUpdates()) | ||
4217 | hasUpdates = true; | ||
4218 | } | ||
4219 | |||
4220 | return hasUpdates; | ||
4221 | } | ||
4222 | |||
4155 | public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID) | 4223 | public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID) |
4156 | { | 4224 | { |
4157 | AssetUploadCompletePacket newPack = new AssetUploadCompletePacket(); | 4225 | AssetUploadCompletePacket newPack = new AssetUploadCompletePacket(); |
@@ -4862,7 +4930,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4862 | 4930 | ||
4863 | public void SendForceClientSelectObjects(List<uint> ObjectIDs) | 4931 | public void SendForceClientSelectObjects(List<uint> ObjectIDs) |
4864 | { | 4932 | { |
4865 | m_log.WarnFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count); | 4933 | // m_log.DebugFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count); |
4866 | 4934 | ||
4867 | bool firstCall = true; | 4935 | bool firstCall = true; |
4868 | const int MAX_OBJECTS_PER_PACKET = 251; | 4936 | const int MAX_OBJECTS_PER_PACKET = 251; |
@@ -5019,7 +5087,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5019 | SceneObjectPart part = (SceneObjectPart)entity; | 5087 | SceneObjectPart part = (SceneObjectPart)entity; |
5020 | 5088 | ||
5021 | attachPoint = part.ParentGroup.AttachmentPoint; | 5089 | attachPoint = part.ParentGroup.AttachmentPoint; |
5022 | 5090 | attachPoint = ((attachPoint % 16) * 16 + (attachPoint / 16)); | |
5023 | // m_log.DebugFormat( | 5091 | // m_log.DebugFormat( |
5024 | // "[LLCLIENTVIEW]: Sending attachPoint {0} for {1} {2} to {3}", | 5092 | // "[LLCLIENTVIEW]: Sending attachPoint {0} for {1} {2} to {3}", |
5025 | // attachPoint, part.Name, part.LocalId, Name); | 5093 | // attachPoint, part.Name, part.LocalId, Name); |
@@ -5047,7 +5115,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5047 | pos += 4; | 5115 | pos += 4; |
5048 | 5116 | ||
5049 | // Avatar/CollisionPlane | 5117 | // Avatar/CollisionPlane |
5050 | data[pos++] = (byte)((attachPoint % 16) * 16 + (attachPoint / 16)); ; | 5118 | data[pos++] = (byte) attachPoint; |
5051 | if (avatar) | 5119 | if (avatar) |
5052 | { | 5120 | { |
5053 | data[pos++] = 1; | 5121 | data[pos++] = 1; |
@@ -5372,7 +5440,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5372 | AddLocalPacketHandler(PacketType.RezObject, HandlerRezObject); | 5440 | AddLocalPacketHandler(PacketType.RezObject, HandlerRezObject); |
5373 | AddLocalPacketHandler(PacketType.DeRezObject, HandlerDeRezObject); | 5441 | AddLocalPacketHandler(PacketType.DeRezObject, HandlerDeRezObject); |
5374 | AddLocalPacketHandler(PacketType.ModifyLand, HandlerModifyLand); | 5442 | AddLocalPacketHandler(PacketType.ModifyLand, HandlerModifyLand); |
5375 | AddLocalPacketHandler(PacketType.RegionHandshakeReply, HandlerRegionHandshakeReply); | 5443 | AddLocalPacketHandler(PacketType.RegionHandshakeReply, HandlerRegionHandshakeReply, false); |
5376 | AddLocalPacketHandler(PacketType.AgentWearablesRequest, HandlerAgentWearablesRequest); | 5444 | AddLocalPacketHandler(PacketType.AgentWearablesRequest, HandlerAgentWearablesRequest); |
5377 | AddLocalPacketHandler(PacketType.AgentSetAppearance, HandlerAgentSetAppearance); | 5445 | AddLocalPacketHandler(PacketType.AgentSetAppearance, HandlerAgentSetAppearance); |
5378 | AddLocalPacketHandler(PacketType.AgentIsNowWearing, HandlerAgentIsNowWearing); | 5446 | AddLocalPacketHandler(PacketType.AgentIsNowWearing, HandlerAgentIsNowWearing); |
@@ -5433,8 +5501,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5433 | AddLocalPacketHandler(PacketType.ScriptAnswerYes, HandleScriptAnswerYes, false); | 5501 | AddLocalPacketHandler(PacketType.ScriptAnswerYes, HandleScriptAnswerYes, false); |
5434 | AddLocalPacketHandler(PacketType.ObjectClickAction, HandleObjectClickAction, false); | 5502 | AddLocalPacketHandler(PacketType.ObjectClickAction, HandleObjectClickAction, false); |
5435 | AddLocalPacketHandler(PacketType.ObjectMaterial, HandleObjectMaterial, false); | 5503 | AddLocalPacketHandler(PacketType.ObjectMaterial, HandleObjectMaterial, false); |
5436 | AddLocalPacketHandler(PacketType.RequestImage, HandleRequestImage); | 5504 | AddLocalPacketHandler(PacketType.RequestImage, HandleRequestImage, false); |
5437 | AddLocalPacketHandler(PacketType.TransferRequest, HandleTransferRequest); | 5505 | AddLocalPacketHandler(PacketType.TransferRequest, HandleTransferRequest, false); |
5438 | AddLocalPacketHandler(PacketType.AssetUploadRequest, HandleAssetUploadRequest); | 5506 | AddLocalPacketHandler(PacketType.AssetUploadRequest, HandleAssetUploadRequest); |
5439 | AddLocalPacketHandler(PacketType.RequestXfer, HandleRequestXfer); | 5507 | AddLocalPacketHandler(PacketType.RequestXfer, HandleRequestXfer); |
5440 | AddLocalPacketHandler(PacketType.SendXferPacket, HandleSendXferPacket); | 5508 | AddLocalPacketHandler(PacketType.SendXferPacket, HandleSendXferPacket); |
@@ -5466,7 +5534,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5466 | AddLocalPacketHandler(PacketType.TeleportCancel, HandleTeleportCancel); | 5534 | AddLocalPacketHandler(PacketType.TeleportCancel, HandleTeleportCancel); |
5467 | AddLocalPacketHandler(PacketType.TeleportLocationRequest, HandleTeleportLocationRequest); | 5535 | AddLocalPacketHandler(PacketType.TeleportLocationRequest, HandleTeleportLocationRequest); |
5468 | AddLocalPacketHandler(PacketType.UUIDNameRequest, HandleUUIDNameRequest, false); | 5536 | AddLocalPacketHandler(PacketType.UUIDNameRequest, HandleUUIDNameRequest, false); |
5469 | AddLocalPacketHandler(PacketType.RegionHandleRequest, HandleRegionHandleRequest); | 5537 | AddLocalPacketHandler(PacketType.RegionHandleRequest, HandleRegionHandleRequest, false); |
5470 | AddLocalPacketHandler(PacketType.ParcelInfoRequest, HandleParcelInfoRequest); | 5538 | AddLocalPacketHandler(PacketType.ParcelInfoRequest, HandleParcelInfoRequest); |
5471 | AddLocalPacketHandler(PacketType.ParcelAccessListRequest, HandleParcelAccessListRequest, false); | 5539 | AddLocalPacketHandler(PacketType.ParcelAccessListRequest, HandleParcelAccessListRequest, false); |
5472 | AddLocalPacketHandler(PacketType.ParcelAccessListUpdate, HandleParcelAccessListUpdate, false); | 5540 | AddLocalPacketHandler(PacketType.ParcelAccessListUpdate, HandleParcelAccessListUpdate, false); |
@@ -5579,83 +5647,137 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5579 | 5647 | ||
5580 | #region Packet Handlers | 5648 | #region Packet Handlers |
5581 | 5649 | ||
5650 | public int TotalAgentUpdates { get; set; } | ||
5651 | |||
5582 | #region Scene/Avatar | 5652 | #region Scene/Avatar |
5583 | 5653 | ||
5584 | private bool HandleAgentUpdate(IClientAPI sener, Packet packet) | 5654 | // Threshold for body rotation to be a significant agent update |
5655 | private const float QDELTA = 0.000001f; | ||
5656 | // Threshold for camera rotation to be a significant agent update | ||
5657 | private const float VDELTA = 0.01f; | ||
5658 | |||
5659 | /// <summary> | ||
5660 | /// This checks the update significance against the last update made. | ||
5661 | /// </summary> | ||
5662 | /// <remarks>Can only be called by one thread at a time</remarks> | ||
5663 | /// <returns></returns> | ||
5664 | /// <param name='x'></param> | ||
5665 | public bool CheckAgentUpdateSignificance(AgentUpdatePacket.AgentDataBlock x) | ||
5585 | { | 5666 | { |
5586 | if (OnAgentUpdate != null) | 5667 | return CheckAgentMovementUpdateSignificance(x) || CheckAgentCameraUpdateSignificance(x); |
5587 | { | 5668 | } |
5588 | AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet; | ||
5589 | 5669 | ||
5590 | #region Packet Session and User Check | 5670 | /// <summary> |
5591 | if (agentUpdate.AgentData.SessionID != SessionId || agentUpdate.AgentData.AgentID != AgentId) | 5671 | /// This checks the movement/state update significance against the last update made. |
5592 | { | 5672 | /// </summary> |
5593 | PacketPool.Instance.ReturnPacket(packet); | 5673 | /// <remarks>Can only be called by one thread at a time</remarks> |
5594 | return false; | 5674 | /// <returns></returns> |
5595 | } | 5675 | /// <param name='x'></param> |
5596 | #endregion | 5676 | private bool CheckAgentMovementUpdateSignificance(AgentUpdatePacket.AgentDataBlock x) |
5677 | { | ||
5678 | float qdelta1 = 1 - (float)Math.Pow(Quaternion.Dot(x.BodyRotation, m_thisAgentUpdateArgs.BodyRotation), 2); | ||
5679 | //qdelta2 = 1 - (float)Math.Pow(Quaternion.Dot(x.HeadRotation, m_thisAgentUpdateArgs.HeadRotation), 2); | ||
5680 | |||
5681 | bool movementSignificant = | ||
5682 | (qdelta1 > QDELTA) // significant if body rotation above threshold | ||
5683 | // Ignoring head rotation altogether, because it's not being used for anything interesting up the stack | ||
5684 | // || (qdelta2 > QDELTA * 10) // significant if head rotation above threshold | ||
5685 | || (x.ControlFlags != m_thisAgentUpdateArgs.ControlFlags) // significant if control flags changed | ||
5686 | || (x.ControlFlags != (byte)AgentManager.ControlFlags.NONE) // significant if user supplying any movement update commands | ||
5687 | || (x.Far != m_thisAgentUpdateArgs.Far) // significant if far distance changed | ||
5688 | || (x.Flags != m_thisAgentUpdateArgs.Flags) // significant if Flags changed | ||
5689 | || (x.State != m_thisAgentUpdateArgs.State) // significant if Stats changed | ||
5690 | ; | ||
5691 | //if (movementSignificant) | ||
5692 | //{ | ||
5693 | //m_log.DebugFormat("[LLCLIENTVIEW]: Bod {0} {1}", | ||
5694 | // qdelta1, qdelta2); | ||
5695 | //m_log.DebugFormat("[LLCLIENTVIEW]: St {0} {1} {2} {3}", | ||
5696 | // x.ControlFlags, x.Flags, x.Far, x.State); | ||
5697 | //} | ||
5698 | return movementSignificant; | ||
5699 | } | ||
5597 | 5700 | ||
5598 | bool update = false; | 5701 | /// <summary> |
5599 | AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData; | 5702 | /// This checks the camera update significance against the last update made. |
5600 | 5703 | /// </summary> | |
5601 | if (m_lastAgentUpdateArgs != null) | 5704 | /// <remarks>Can only be called by one thread at a time</remarks> |
5602 | { | 5705 | /// <returns></returns> |
5603 | // These should be ordered from most-likely to | 5706 | /// <param name='x'></param> |
5604 | // least likely to change. I've made an initial | 5707 | private bool CheckAgentCameraUpdateSignificance(AgentUpdatePacket.AgentDataBlock x) |
5605 | // guess at that. | 5708 | { |
5606 | update = | 5709 | float vdelta1 = Vector3.Distance(x.CameraAtAxis, m_thisAgentUpdateArgs.CameraAtAxis); |
5607 | ( | 5710 | float vdelta2 = Vector3.Distance(x.CameraCenter, m_thisAgentUpdateArgs.CameraCenter); |
5608 | (x.BodyRotation != m_lastAgentUpdateArgs.BodyRotation) || | 5711 | float vdelta3 = Vector3.Distance(x.CameraLeftAxis, m_thisAgentUpdateArgs.CameraLeftAxis); |
5609 | (x.CameraAtAxis != m_lastAgentUpdateArgs.CameraAtAxis) || | 5712 | float vdelta4 = Vector3.Distance(x.CameraUpAxis, m_thisAgentUpdateArgs.CameraUpAxis); |
5610 | (x.CameraCenter != m_lastAgentUpdateArgs.CameraCenter) || | ||
5611 | (x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) || | ||
5612 | (x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) || | ||
5613 | (x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) || | ||
5614 | (x.ControlFlags != 0) || | ||
5615 | (x.Far != m_lastAgentUpdateArgs.Far) || | ||
5616 | (x.Flags != m_lastAgentUpdateArgs.Flags) || | ||
5617 | (x.State != m_lastAgentUpdateArgs.State) || | ||
5618 | (x.HeadRotation != m_lastAgentUpdateArgs.HeadRotation) || | ||
5619 | (x.SessionID != m_lastAgentUpdateArgs.SessionID) || | ||
5620 | (x.AgentID != m_lastAgentUpdateArgs.AgentID) | ||
5621 | ); | ||
5622 | } | ||
5623 | else | ||
5624 | { | ||
5625 | m_lastAgentUpdateArgs = new AgentUpdateArgs(); | ||
5626 | update = true; | ||
5627 | } | ||
5628 | 5713 | ||
5629 | if (update) | 5714 | bool cameraSignificant = |
5630 | { | 5715 | (vdelta1 > VDELTA) || |
5631 | // m_log.DebugFormat("[LLCLIENTVIEW]: Triggered AgentUpdate for {0}", sener.Name); | 5716 | (vdelta2 > VDELTA) || |
5717 | (vdelta3 > VDELTA) || | ||
5718 | (vdelta4 > VDELTA) | ||
5719 | ; | ||
5632 | 5720 | ||
5633 | m_lastAgentUpdateArgs.AgentID = x.AgentID; | 5721 | //if (cameraSignificant) |
5634 | m_lastAgentUpdateArgs.BodyRotation = x.BodyRotation; | 5722 | //{ |
5635 | m_lastAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis; | 5723 | //m_log.DebugFormat("[LLCLIENTVIEW]: Cam1 {0} {1}", |
5636 | m_lastAgentUpdateArgs.CameraCenter = x.CameraCenter; | 5724 | // x.CameraAtAxis, x.CameraCenter); |
5637 | m_lastAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis; | 5725 | //m_log.DebugFormat("[LLCLIENTVIEW]: Cam2 {0} {1}", |
5638 | m_lastAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis; | 5726 | // x.CameraLeftAxis, x.CameraUpAxis); |
5639 | m_lastAgentUpdateArgs.ControlFlags = x.ControlFlags; | 5727 | //} |
5640 | m_lastAgentUpdateArgs.Far = x.Far; | ||
5641 | m_lastAgentUpdateArgs.Flags = x.Flags; | ||
5642 | m_lastAgentUpdateArgs.HeadRotation = x.HeadRotation; | ||
5643 | m_lastAgentUpdateArgs.SessionID = x.SessionID; | ||
5644 | m_lastAgentUpdateArgs.State = x.State; | ||
5645 | 5728 | ||
5646 | UpdateAgent handlerAgentUpdate = OnAgentUpdate; | 5729 | return cameraSignificant; |
5647 | UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate; | 5730 | } |
5648 | 5731 | ||
5649 | if (handlerPreAgentUpdate != null) | 5732 | private bool HandleAgentUpdate(IClientAPI sener, Packet packet) |
5650 | OnPreAgentUpdate(this, m_lastAgentUpdateArgs); | 5733 | { |
5734 | // We got here, which means that something in agent update was significant | ||
5651 | 5735 | ||
5652 | if (handlerAgentUpdate != null) | 5736 | AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet; |
5653 | OnAgentUpdate(this, m_lastAgentUpdateArgs); | 5737 | AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData; |
5654 | 5738 | ||
5655 | handlerAgentUpdate = null; | 5739 | if (x.AgentID != AgentId || x.SessionID != SessionId) |
5656 | handlerPreAgentUpdate = null; | 5740 | return false; |
5657 | } | 5741 | |
5658 | } | 5742 | // Before we update the current m_thisAgentUpdateArgs, let's check this again |
5743 | // to see what exactly changed | ||
5744 | bool movement = CheckAgentMovementUpdateSignificance(x); | ||
5745 | bool camera = CheckAgentCameraUpdateSignificance(x); | ||
5746 | |||
5747 | m_thisAgentUpdateArgs.AgentID = x.AgentID; | ||
5748 | m_thisAgentUpdateArgs.BodyRotation = x.BodyRotation; | ||
5749 | m_thisAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis; | ||
5750 | m_thisAgentUpdateArgs.CameraCenter = x.CameraCenter; | ||
5751 | m_thisAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis; | ||
5752 | m_thisAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis; | ||
5753 | m_thisAgentUpdateArgs.ControlFlags = x.ControlFlags; | ||
5754 | m_thisAgentUpdateArgs.Far = x.Far; | ||
5755 | m_thisAgentUpdateArgs.Flags = x.Flags; | ||
5756 | m_thisAgentUpdateArgs.HeadRotation = x.HeadRotation; | ||
5757 | m_thisAgentUpdateArgs.SessionID = x.SessionID; | ||
5758 | m_thisAgentUpdateArgs.State = x.State; | ||
5759 | |||
5760 | UpdateAgent handlerAgentUpdate = OnAgentUpdate; | ||
5761 | UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate; | ||
5762 | UpdateAgent handlerAgentCameraUpdate = OnAgentCameraUpdate; | ||
5763 | |||
5764 | // Was there a significant movement/state change? | ||
5765 | if (movement) | ||
5766 | { | ||
5767 | if (handlerPreAgentUpdate != null) | ||
5768 | OnPreAgentUpdate(this, m_thisAgentUpdateArgs); | ||
5769 | |||
5770 | if (handlerAgentUpdate != null) | ||
5771 | OnAgentUpdate(this, m_thisAgentUpdateArgs); | ||
5772 | } | ||
5773 | // Was there a significant camera(s) change? | ||
5774 | if (camera) | ||
5775 | if (handlerAgentCameraUpdate != null) | ||
5776 | handlerAgentCameraUpdate(this, m_thisAgentUpdateArgs); | ||
5777 | |||
5778 | handlerAgentUpdate = null; | ||
5779 | handlerPreAgentUpdate = null; | ||
5780 | handlerAgentCameraUpdate = null; | ||
5659 | 5781 | ||
5660 | PacketPool.Instance.ReturnPacket(packet); | 5782 | PacketPool.Instance.ReturnPacket(packet); |
5661 | 5783 | ||
@@ -7864,129 +7986,145 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
7864 | //m_log.Debug("ClientView.ProcessPackets.cs:ProcessInPacket() - Got transfer request"); | 7986 | //m_log.Debug("ClientView.ProcessPackets.cs:ProcessInPacket() - Got transfer request"); |
7865 | 7987 | ||
7866 | TransferRequestPacket transfer = (TransferRequestPacket)Pack; | 7988 | TransferRequestPacket transfer = (TransferRequestPacket)Pack; |
7867 | //m_log.Debug("Transfer Request: " + transfer.ToString()); | ||
7868 | // Validate inventory transfers | ||
7869 | // Has to be done here, because AssetCache can't do it | ||
7870 | // | ||
7871 | UUID taskID = UUID.Zero; | 7989 | UUID taskID = UUID.Zero; |
7872 | if (transfer.TransferInfo.SourceType == (int)SourceType.SimInventoryItem) | 7990 | if (transfer.TransferInfo.SourceType == (int)SourceType.SimInventoryItem) |
7873 | { | 7991 | { |
7874 | taskID = new UUID(transfer.TransferInfo.Params, 48); | ||
7875 | UUID itemID = new UUID(transfer.TransferInfo.Params, 64); | ||
7876 | UUID requestID = new UUID(transfer.TransferInfo.Params, 80); | ||
7877 | |||
7878 | // m_log.DebugFormat( | ||
7879 | // "[CLIENT]: Got request for asset {0} from item {1} in prim {2} by {3}", | ||
7880 | // requestID, itemID, taskID, Name); | ||
7881 | |||
7882 | if (!(((Scene)m_scene).Permissions.BypassPermissions())) | 7992 | if (!(((Scene)m_scene).Permissions.BypassPermissions())) |
7883 | { | 7993 | { |
7884 | if (taskID != UUID.Zero) // Prim | 7994 | // We're spawning a thread because the permissions check can block this thread |
7995 | Util.FireAndForget(delegate | ||
7885 | { | 7996 | { |
7886 | SceneObjectPart part = ((Scene)m_scene).GetSceneObjectPart(taskID); | 7997 | // This requests the asset if needed |
7998 | HandleSimInventoryTransferRequestWithPermsCheck(sender, transfer); | ||
7999 | }); | ||
8000 | return true; | ||
8001 | } | ||
8002 | } | ||
8003 | else if (transfer.TransferInfo.SourceType == (int)SourceType.SimEstate) | ||
8004 | { | ||
8005 | //TransferRequestPacket does not include covenant uuid? | ||
8006 | //get scene covenant uuid | ||
8007 | taskID = m_scene.RegionInfo.RegionSettings.Covenant; | ||
8008 | } | ||
7887 | 8009 | ||
7888 | if (part == null) | 8010 | // This is non-blocking |
7889 | { | 8011 | MakeAssetRequest(transfer, taskID); |
7890 | m_log.WarnFormat( | ||
7891 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but prim does not exist", | ||
7892 | Name, requestID, itemID, taskID); | ||
7893 | return true; | ||
7894 | } | ||
7895 | 8012 | ||
7896 | TaskInventoryItem tii = part.Inventory.GetInventoryItem(itemID); | 8013 | return true; |
7897 | if (tii == null) | 8014 | } |
7898 | { | ||
7899 | m_log.WarnFormat( | ||
7900 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item does not exist", | ||
7901 | Name, requestID, itemID, taskID); | ||
7902 | return true; | ||
7903 | } | ||
7904 | 8015 | ||
7905 | if (tii.Type == (int)AssetType.LSLText) | 8016 | private void HandleSimInventoryTransferRequestWithPermsCheck(IClientAPI sender, TransferRequestPacket transfer) |
7906 | { | 8017 | { |
7907 | if (!((Scene)m_scene).Permissions.CanEditScript(itemID, taskID, AgentId)) | 8018 | UUID taskID = new UUID(transfer.TransferInfo.Params, 48); |
7908 | return true; | 8019 | UUID itemID = new UUID(transfer.TransferInfo.Params, 64); |
7909 | } | 8020 | UUID requestID = new UUID(transfer.TransferInfo.Params, 80); |
7910 | else if (tii.Type == (int)AssetType.Notecard) | ||
7911 | { | ||
7912 | if (!((Scene)m_scene).Permissions.CanEditNotecard(itemID, taskID, AgentId)) | ||
7913 | return true; | ||
7914 | } | ||
7915 | else | ||
7916 | { | ||
7917 | // TODO: Change this code to allow items other than notecards and scripts to be successfully | ||
7918 | // shared with group. In fact, this whole block of permissions checking should move to an IPermissionsModule | ||
7919 | if (part.OwnerID != AgentId) | ||
7920 | { | ||
7921 | m_log.WarnFormat( | ||
7922 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the prim is owned by {4}", | ||
7923 | Name, requestID, itemID, taskID, part.OwnerID); | ||
7924 | return true; | ||
7925 | } | ||
7926 | 8021 | ||
7927 | if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0) | 8022 | //m_log.DebugFormat( |
7928 | { | 8023 | // "[CLIENT]: Got request for asset {0} from item {1} in prim {2} by {3}", |
7929 | m_log.WarnFormat( | 8024 | // requestID, itemID, taskID, Name); |
7930 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but modify permissions are not set", | ||
7931 | Name, requestID, itemID, taskID); | ||
7932 | return true; | ||
7933 | } | ||
7934 | 8025 | ||
7935 | if (tii.OwnerID != AgentId) | 8026 | //m_log.Debug("Transfer Request: " + transfer.ToString()); |
7936 | { | 8027 | // Validate inventory transfers |
7937 | m_log.WarnFormat( | 8028 | // Has to be done here, because AssetCache can't do it |
7938 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the item is owned by {4}", | 8029 | // |
7939 | Name, requestID, itemID, taskID, tii.OwnerID); | 8030 | if (taskID != UUID.Zero) // Prim |
7940 | return true; | 8031 | { |
7941 | } | 8032 | SceneObjectPart part = ((Scene)m_scene).GetSceneObjectPart(taskID); |
7942 | 8033 | ||
7943 | if (( | 8034 | if (part == null) |
7944 | tii.CurrentPermissions & ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) | 8035 | { |
7945 | != ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) | 8036 | m_log.WarnFormat( |
7946 | { | 8037 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but prim does not exist", |
7947 | m_log.WarnFormat( | 8038 | Name, requestID, itemID, taskID); |
7948 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item permissions are not modify/copy/transfer", | 8039 | return; |
7949 | Name, requestID, itemID, taskID); | 8040 | } |
7950 | return true; | ||
7951 | } | ||
7952 | 8041 | ||
7953 | if (tii.AssetID != requestID) | 8042 | TaskInventoryItem tii = part.Inventory.GetInventoryItem(itemID); |
7954 | { | 8043 | if (tii == null) |
7955 | m_log.WarnFormat( | 8044 | { |
7956 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but this does not match item's asset {4}", | 8045 | m_log.WarnFormat( |
7957 | Name, requestID, itemID, taskID, tii.AssetID); | 8046 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item does not exist", |
7958 | return true; | 8047 | Name, requestID, itemID, taskID); |
7959 | } | 8048 | return; |
7960 | } | 8049 | } |
8050 | |||
8051 | if (tii.Type == (int)AssetType.LSLText) | ||
8052 | { | ||
8053 | if (!((Scene)m_scene).Permissions.CanEditScript(itemID, taskID, AgentId)) | ||
8054 | return; | ||
8055 | } | ||
8056 | else if (tii.Type == (int)AssetType.Notecard) | ||
8057 | { | ||
8058 | if (!((Scene)m_scene).Permissions.CanEditNotecard(itemID, taskID, AgentId)) | ||
8059 | return; | ||
8060 | } | ||
8061 | else | ||
8062 | { | ||
8063 | // TODO: Change this code to allow items other than notecards and scripts to be successfully | ||
8064 | // shared with group. In fact, this whole block of permissions checking should move to an IPermissionsModule | ||
8065 | if (part.OwnerID != AgentId) | ||
8066 | { | ||
8067 | m_log.WarnFormat( | ||
8068 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the prim is owned by {4}", | ||
8069 | Name, requestID, itemID, taskID, part.OwnerID); | ||
8070 | return; | ||
7961 | } | 8071 | } |
7962 | else // Agent | 8072 | |
8073 | if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0) | ||
7963 | { | 8074 | { |
7964 | IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>(); | 8075 | m_log.WarnFormat( |
7965 | if (invAccess != null) | 8076 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but modify permissions are not set", |
7966 | { | 8077 | Name, requestID, itemID, taskID); |
7967 | if (!invAccess.CanGetAgentInventoryItem(this, itemID, requestID)) | 8078 | return; |
7968 | return false; | 8079 | } |
7969 | } | 8080 | |
7970 | else | 8081 | if (tii.OwnerID != AgentId) |
7971 | { | 8082 | { |
7972 | return false; | 8083 | m_log.WarnFormat( |
7973 | } | 8084 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the item is owned by {4}", |
8085 | Name, requestID, itemID, taskID, tii.OwnerID); | ||
8086 | return; | ||
8087 | } | ||
8088 | |||
8089 | if (( | ||
8090 | tii.CurrentPermissions & ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) | ||
8091 | != ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) | ||
8092 | { | ||
8093 | m_log.WarnFormat( | ||
8094 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item permissions are not modify/copy/transfer", | ||
8095 | Name, requestID, itemID, taskID); | ||
8096 | return; | ||
8097 | } | ||
8098 | |||
8099 | if (tii.AssetID != requestID) | ||
8100 | { | ||
8101 | m_log.WarnFormat( | ||
8102 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but this does not match item's asset {4}", | ||
8103 | Name, requestID, itemID, taskID, tii.AssetID); | ||
8104 | return; | ||
7974 | } | 8105 | } |
7975 | } | 8106 | } |
7976 | } | 8107 | } |
7977 | else | 8108 | else // Agent |
7978 | if (transfer.TransferInfo.SourceType == (int)SourceType.SimEstate) | 8109 | { |
8110 | IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>(); | ||
8111 | if (invAccess != null) | ||
7979 | { | 8112 | { |
7980 | //TransferRequestPacket does not include covenant uuid? | 8113 | if (!invAccess.CanGetAgentInventoryItem(this, itemID, requestID)) |
7981 | //get scene covenant uuid | 8114 | return; |
7982 | taskID = m_scene.RegionInfo.RegionSettings.Covenant; | ||
7983 | } | 8115 | } |
8116 | else | ||
8117 | { | ||
8118 | return; | ||
8119 | } | ||
8120 | } | ||
7984 | 8121 | ||
8122 | // Permissions out of the way, let's request the asset | ||
7985 | MakeAssetRequest(transfer, taskID); | 8123 | MakeAssetRequest(transfer, taskID); |
7986 | 8124 | ||
7987 | return true; | ||
7988 | } | 8125 | } |
7989 | 8126 | ||
8127 | |||
7990 | private bool HandleAssetUploadRequest(IClientAPI sender, Packet Pack) | 8128 | private bool HandleAssetUploadRequest(IClientAPI sender, Packet Pack) |
7991 | { | 8129 | { |
7992 | AssetUploadRequestPacket request = (AssetUploadRequestPacket)Pack; | 8130 | AssetUploadRequestPacket request = (AssetUploadRequestPacket)Pack; |
@@ -11717,8 +11855,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11717 | } | 11855 | } |
11718 | 11856 | ||
11719 | /// <summary> | 11857 | /// <summary> |
11720 | /// Send a response back to a client when it asks the asset server (via the region server) if it has | ||
11721 | /// its appearance texture cached. | ||
11722 | /// </summary> | 11858 | /// </summary> |
11723 | /// <remarks> | 11859 | /// <remarks> |
11724 | /// At the moment, we always reply that there is no cached texture. | 11860 | /// At the moment, we always reply that there is no cached texture. |
@@ -11726,6 +11862,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11726 | /// <param name="simclient"></param> | 11862 | /// <param name="simclient"></param> |
11727 | /// <param name="packet"></param> | 11863 | /// <param name="packet"></param> |
11728 | /// <returns></returns> | 11864 | /// <returns></returns> |
11865 | // TODO: Convert old handler to use new method | ||
11866 | /*protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet) | ||
11867 | { | ||
11868 | AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet; | ||
11869 | |||
11870 | if (cachedtex.AgentData.SessionID != SessionId) | ||
11871 | return false; | ||
11872 | |||
11873 | |||
11874 | List<CachedTextureRequestArg> requestArgs = new List<CachedTextureRequestArg>(); | ||
11875 | |||
11876 | for (int i = 0; i < cachedtex.WearableData.Length; i++) | ||
11877 | { | ||
11878 | CachedTextureRequestArg arg = new CachedTextureRequestArg(); | ||
11879 | arg.BakedTextureIndex = cachedtex.WearableData[i].TextureIndex; | ||
11880 | arg.WearableHashID = cachedtex.WearableData[i].ID; | ||
11881 | |||
11882 | requestArgs.Add(arg); | ||
11883 | } | ||
11884 | |||
11885 | CachedTextureRequest handlerCachedTextureRequest = OnCachedTextureRequest; | ||
11886 | if (handlerCachedTextureRequest != null) | ||
11887 | { | ||
11888 | handlerCachedTextureRequest(simclient,cachedtex.AgentData.SerialNum,requestArgs); | ||
11889 | } | ||
11890 | |||
11891 | return true; | ||
11892 | }*/ | ||
11893 | |||
11729 | protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet) | 11894 | protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet) |
11730 | { | 11895 | { |
11731 | //m_log.Debug("texture cached: " + packet.ToString()); | 11896 | //m_log.Debug("texture cached: " + packet.ToString()); |
@@ -11884,6 +12049,40 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11884 | return true; | 12049 | return true; |
11885 | } | 12050 | } |
11886 | 12051 | ||
12052 | /// <summary> | ||
12053 | /// Send a response back to a client when it asks the asset server (via the region server) if it has | ||
12054 | /// its appearance texture cached. | ||
12055 | /// </summary> | ||
12056 | /// <param name="avatar"></param> | ||
12057 | /// <param name="serial"></param> | ||
12058 | /// <param name="cachedTextures"></param> | ||
12059 | /// <returns></returns> | ||
12060 | public void SendCachedTextureResponse(ISceneEntity avatar, int serial, List<CachedTextureResponseArg> cachedTextures) | ||
12061 | { | ||
12062 | ScenePresence presence = avatar as ScenePresence; | ||
12063 | if (presence == null) | ||
12064 | return; | ||
12065 | |||
12066 | AgentCachedTextureResponsePacket cachedresp = (AgentCachedTextureResponsePacket)PacketPool.Instance.GetPacket(PacketType.AgentCachedTextureResponse); | ||
12067 | |||
12068 | // TODO: don't create new blocks if recycling an old packet | ||
12069 | cachedresp.AgentData.AgentID = m_agentId; | ||
12070 | cachedresp.AgentData.SessionID = m_sessionId; | ||
12071 | cachedresp.AgentData.SerialNum = serial; | ||
12072 | cachedresp.WearableData = new AgentCachedTextureResponsePacket.WearableDataBlock[cachedTextures.Count]; | ||
12073 | |||
12074 | for (int i = 0; i < cachedTextures.Count; i++) | ||
12075 | { | ||
12076 | cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); | ||
12077 | cachedresp.WearableData[i].TextureIndex = (byte)cachedTextures[i].BakedTextureIndex; | ||
12078 | cachedresp.WearableData[i].TextureID = cachedTextures[i].BakedTextureID; | ||
12079 | cachedresp.WearableData[i].HostName = new byte[0]; | ||
12080 | } | ||
12081 | |||
12082 | cachedresp.Header.Zerocoded = true; | ||
12083 | OutPacket(cachedresp, ThrottleOutPacketType.Task); | ||
12084 | } | ||
12085 | |||
11887 | protected bool HandleMultipleObjUpdate(IClientAPI simClient, Packet packet) | 12086 | protected bool HandleMultipleObjUpdate(IClientAPI simClient, Packet packet) |
11888 | { | 12087 | { |
11889 | MultipleObjectUpdatePacket multipleupdate = (MultipleObjectUpdatePacket)packet; | 12088 | MultipleObjectUpdatePacket multipleupdate = (MultipleObjectUpdatePacket)packet; |
@@ -11909,8 +12108,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11909 | if (part == null) | 12108 | if (part == null) |
11910 | { | 12109 | { |
11911 | // It's a ghost! tell the client to delete it from view. | 12110 | // It's a ghost! tell the client to delete it from view. |
11912 | simClient.SendKillObject(Scene.RegionInfo.RegionHandle, | 12111 | simClient.SendKillObject(new List<uint> { localId }); |
11913 | new List<uint> { localId }); | ||
11914 | } | 12112 | } |
11915 | else | 12113 | else |
11916 | { | 12114 | { |
@@ -12314,7 +12512,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
12314 | ClientInfo info = m_udpClient.GetClientInfo(); | 12512 | ClientInfo info = m_udpClient.GetClientInfo(); |
12315 | 12513 | ||
12316 | info.proxyEP = null; | 12514 | info.proxyEP = null; |
12317 | info.agentcircuit = RequestClientInfo(); | 12515 | if (info.agentcircuit == null) |
12516 | info.agentcircuit = RequestClientInfo(); | ||
12318 | 12517 | ||
12319 | return info; | 12518 | return info; |
12320 | } | 12519 | } |
@@ -12697,7 +12896,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
12697 | OutPacket(dialog, ThrottleOutPacketType.Task); | 12896 | OutPacket(dialog, ThrottleOutPacketType.Task); |
12698 | } | 12897 | } |
12699 | 12898 | ||
12700 | public void StopFlying(ISceneEntity p) | 12899 | public void SendAgentTerseUpdate(ISceneEntity p) |
12701 | { | 12900 | { |
12702 | if (p is ScenePresence) | 12901 | if (p is ScenePresence) |
12703 | { | 12902 | { |
@@ -12711,25 +12910,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
12711 | 12910 | ||
12712 | Vector3 pos = presence.AbsolutePosition; | 12911 | Vector3 pos = presence.AbsolutePosition; |
12713 | 12912 | ||
12714 | if (presence.Appearance.AvatarHeight != 127.0f) | ||
12715 | pos += new Vector3(0f, 0f, (presence.Appearance.AvatarHeight/6f)); | ||
12716 | else | ||
12717 | pos += new Vector3(0f, 0f, (1.56f/6f)); | ||
12718 | |||
12719 | presence.AbsolutePosition = pos; | ||
12720 | |||
12721 | // attach a suitable collision plane regardless of the actual situation to force the LLClient to land. | ||
12722 | // Collision plane below the avatar's position a 6th of the avatar's height is suitable. | ||
12723 | // Mind you, that this method doesn't get called if the avatar's velocity magnitude is greater then a | ||
12724 | // certain amount.. because the LLClient wouldn't land in that situation anyway. | ||
12725 | |||
12726 | // why are we still testing for this really old height value default??? | ||
12727 | if (presence.Appearance.AvatarHeight != 127.0f) | ||
12728 | presence.CollisionPlane = new Vector4(0, 0, 0, pos.Z - presence.Appearance.AvatarHeight/6f); | ||
12729 | else | ||
12730 | presence.CollisionPlane = new Vector4(0, 0, 0, pos.Z - (1.56f/6f)); | ||
12731 | |||
12732 | |||
12733 | ImprovedTerseObjectUpdatePacket.ObjectDataBlock block = | 12913 | ImprovedTerseObjectUpdatePacket.ObjectDataBlock block = |
12734 | CreateImprovedTerseBlock(p, false); | 12914 | CreateImprovedTerseBlock(p, false); |
12735 | 12915 | ||
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..d52ad7e 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs | |||
@@ -31,6 +31,7 @@ using System.Net; | |||
31 | using System.Threading; | 31 | using System.Threading; |
32 | using log4net; | 32 | using log4net; |
33 | using OpenSim.Framework; | 33 | using OpenSim.Framework; |
34 | using OpenSim.Framework.Monitoring; | ||
34 | using OpenMetaverse; | 35 | using OpenMetaverse; |
35 | using OpenMetaverse.Packets; | 36 | using OpenMetaverse.Packets; |
36 | 37 | ||
@@ -81,6 +82,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
81 | /// hooked to put more data on the empty queue</summary> | 82 | /// hooked to put more data on the empty queue</summary> |
82 | public event QueueEmpty OnQueueEmpty; | 83 | public event QueueEmpty OnQueueEmpty; |
83 | 84 | ||
85 | public event Func<ThrottleOutPacketTypeFlags, bool> HasUpdates; | ||
86 | |||
84 | /// <summary>AgentID for this client</summary> | 87 | /// <summary>AgentID for this client</summary> |
85 | public readonly UUID AgentID; | 88 | public readonly UUID AgentID; |
86 | /// <summary>The remote address of the connected client</summary> | 89 | /// <summary>The remote address of the connected client</summary> |
@@ -160,6 +163,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
160 | private int m_maxRTO = 60000; | 163 | private int m_maxRTO = 60000; |
161 | public bool m_deliverPackets = true; | 164 | public bool m_deliverPackets = true; |
162 | 165 | ||
166 | private ClientInfo m_info = new ClientInfo(); | ||
167 | |||
163 | /// <summary> | 168 | /// <summary> |
164 | /// Default constructor | 169 | /// Default constructor |
165 | /// </summary> | 170 | /// </summary> |
@@ -241,20 +246,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
241 | // TODO: This data structure is wrong in so many ways. Locking and copying the entire lists | 246 | // 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 | 247 | // of pending and needed ACKs for every client every time some method wants information about |
243 | // this connection is a recipe for poor performance | 248 | // this connection is a recipe for poor performance |
244 | ClientInfo info = new ClientInfo(); | 249 | |
245 | info.pendingAcks = new Dictionary<uint, uint>(); | 250 | m_info.resendThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate; |
246 | info.needAck = new Dictionary<uint, byte[]>(); | 251 | m_info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; |
247 | 252 | m_info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; | |
248 | info.resendThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate; | 253 | m_info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; |
249 | info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; | 254 | m_info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; |
250 | info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; | 255 | m_info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; |
251 | info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; | 256 | m_info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; |
252 | info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; | 257 | m_info.totalThrottle = (int)m_throttleCategory.DripRate; |
253 | info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; | 258 | |
254 | info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; | 259 | return m_info; |
255 | info.totalThrottle = (int)m_throttleCategory.DripRate; | ||
256 | |||
257 | return info; | ||
258 | } | 260 | } |
259 | 261 | ||
260 | /// <summary> | 262 | /// <summary> |
@@ -646,15 +648,38 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
646 | /// <param name="categories">Throttle categories to fire the callback for</param> | 648 | /// <param name="categories">Throttle categories to fire the callback for</param> |
647 | private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories) | 649 | private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories) |
648 | { | 650 | { |
649 | if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty) | 651 | // if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty) |
652 | if (!m_isQueueEmptyRunning && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty) | ||
650 | { | 653 | { |
654 | m_isQueueEmptyRunning = true; | ||
655 | |||
656 | int start = Environment.TickCount & Int32.MaxValue; | ||
657 | const int MIN_CALLBACK_MS = 30; | ||
658 | |||
659 | m_nextOnQueueEmpty = start + MIN_CALLBACK_MS; | ||
660 | if (m_nextOnQueueEmpty == 0) | ||
661 | m_nextOnQueueEmpty = 1; | ||
662 | |||
651 | // Use a value of 0 to signal that FireQueueEmpty is running | 663 | // Use a value of 0 to signal that FireQueueEmpty is running |
652 | m_nextOnQueueEmpty = 0; | 664 | // m_nextOnQueueEmpty = 0; |
653 | // Asynchronously run the callback | 665 | |
654 | Util.FireAndForget(FireQueueEmpty, categories); | 666 | m_categories = categories; |
667 | |||
668 | if (HasUpdates(m_categories)) | ||
669 | { | ||
670 | // Asynchronously run the callback | ||
671 | Util.FireAndForget(FireQueueEmpty, categories); | ||
672 | } | ||
673 | else | ||
674 | { | ||
675 | m_isQueueEmptyRunning = false; | ||
676 | } | ||
655 | } | 677 | } |
656 | } | 678 | } |
657 | 679 | ||
680 | private bool m_isQueueEmptyRunning; | ||
681 | private ThrottleOutPacketTypeFlags m_categories = 0; | ||
682 | |||
658 | /// <summary> | 683 | /// <summary> |
659 | /// Fires the OnQueueEmpty callback and sets the minimum time that it | 684 | /// Fires the OnQueueEmpty callback and sets the minimum time that it |
660 | /// can be called again | 685 | /// can be called again |
@@ -664,22 +689,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
664 | /// signature</param> | 689 | /// signature</param> |
665 | private void FireQueueEmpty(object o) | 690 | private void FireQueueEmpty(object o) |
666 | { | 691 | { |
667 | const int MIN_CALLBACK_MS = 30; | 692 | // int start = Environment.TickCount & Int32.MaxValue; |
693 | // const int MIN_CALLBACK_MS = 30; | ||
668 | 694 | ||
669 | ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o; | 695 | // if (m_udpServer.IsRunningOutbound) |
670 | QueueEmpty callback = OnQueueEmpty; | 696 | // { |
671 | 697 | ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o; | |
672 | int start = Environment.TickCount & Int32.MaxValue; | 698 | QueueEmpty callback = OnQueueEmpty; |
673 | 699 | ||
674 | if (callback != null) | 700 | if (callback != null) |
675 | { | 701 | { |
676 | try { callback(categories); } | 702 | // if (m_udpServer.IsRunningOutbound) |
677 | catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); } | 703 | // { |
678 | } | 704 | try { callback(categories); } |
705 | catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); } | ||
706 | // } | ||
707 | } | ||
708 | // } | ||
709 | |||
710 | // m_nextOnQueueEmpty = start + MIN_CALLBACK_MS; | ||
711 | // if (m_nextOnQueueEmpty == 0) | ||
712 | // m_nextOnQueueEmpty = 1; | ||
713 | |||
714 | // } | ||
679 | 715 | ||
680 | m_nextOnQueueEmpty = start + MIN_CALLBACK_MS; | 716 | m_isQueueEmptyRunning = false; |
681 | if (m_nextOnQueueEmpty == 0) | ||
682 | m_nextOnQueueEmpty = 1; | ||
683 | } | 717 | } |
684 | internal void ForceThrottleSetting(int throttle, int setting) | 718 | internal void ForceThrottleSetting(int throttle, int setting) |
685 | { | 719 | { |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 4154ef2..71b464b 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,34 @@ 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 | "OutgoingUDPSendsCount", | ||
112 | "Number of UDP sends performed", | ||
113 | "", | ||
114 | "", | ||
115 | "clientstack", | ||
116 | scene.Name, | ||
117 | StatType.Pull, | ||
118 | MeasuresOfInterest.AverageChangeOverTime, | ||
119 | stat => stat.Value = m_udpServer.UdpSends, | ||
120 | StatVerbosity.Debug)); | ||
121 | |||
122 | StatsManager.RegisterStat( | ||
123 | new Stat( | ||
124 | "AverageUDPProcessTime", | ||
125 | "Average number of milliseconds taken to process each incoming UDP packet in a sample.", | ||
126 | "This is for initial receive processing which is separate from the later client LL packet processing stage.", | ||
127 | "ms", | ||
128 | "clientstack", | ||
129 | scene.Name, | ||
130 | StatType.Pull, | ||
131 | MeasuresOfInterest.None, | ||
132 | stat => stat.Value = m_udpServer.AverageReceiveTicksForLastSamplePeriod / TimeSpan.TicksPerMillisecond, | ||
133 | // stat => | ||
134 | // stat.Value = Math.Round(m_udpServer.AverageReceiveTicksForLastSamplePeriod / TimeSpan.TicksPerMillisecond, 7), | ||
135 | StatVerbosity.Debug)); | ||
86 | } | 136 | } |
87 | 137 | ||
88 | public bool HandlesRegion(Location x) | 138 | public bool HandlesRegion(Location x) |
@@ -107,10 +157,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
107 | /// </summary> | 157 | /// </summary> |
108 | public class LLUDPServer : OpenSimUDPBase | 158 | public class LLUDPServer : OpenSimUDPBase |
109 | { | 159 | { |
160 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
161 | |||
110 | /// <summary>Maximum transmission unit, or UDP packet size, for the LLUDP protocol</summary> | 162 | /// <summary>Maximum transmission unit, or UDP packet size, for the LLUDP protocol</summary> |
111 | public const int MTU = 1400; | 163 | public const int MTU = 1400; |
112 | 164 | ||
113 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 165 | /// <summary>Number of forced client logouts due to no receipt of packets before timeout.</summary> |
166 | public int ClientLogoutsDueToNoReceives { get; private set; } | ||
167 | |||
168 | /// <summary> | ||
169 | /// Default packet debug level given to new clients | ||
170 | /// </summary> | ||
171 | public int DefaultClientPacketDebugLevel { get; set; } | ||
114 | 172 | ||
115 | /// <summary>The measured resolution of Environment.TickCount</summary> | 173 | /// <summary>The measured resolution of Environment.TickCount</summary> |
116 | public readonly float TickCountResolution; | 174 | public readonly float TickCountResolution; |
@@ -184,6 +242,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
184 | protected bool m_sendPing; | 242 | protected bool m_sendPing; |
185 | 243 | ||
186 | private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>(); | 244 | private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>(); |
245 | |||
246 | /// <summary> | ||
247 | /// Event used to signal when queued packets are available for sending. | ||
248 | /// </summary> | ||
249 | /// <remarks> | ||
250 | /// This allows the outbound loop to only operate when there is data to send rather than continuously polling. | ||
251 | /// Some data is sent immediately and not queued. That data would not trigger this event. | ||
252 | /// </remarks> | ||
253 | private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false); | ||
254 | |||
187 | private Pool<IncomingPacket> m_incomingPacketPool; | 255 | private Pool<IncomingPacket> m_incomingPacketPool; |
188 | 256 | ||
189 | /// <summary> | 257 | /// <summary> |
@@ -461,6 +529,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
461 | m_scene = (Scene)scene; | 529 | m_scene = (Scene)scene; |
462 | m_location = new Location(m_scene.RegionInfo.RegionHandle); | 530 | m_location = new Location(m_scene.RegionInfo.RegionHandle); |
463 | 531 | ||
532 | StatsManager.RegisterStat( | ||
533 | new Stat( | ||
534 | "InboxPacketsCount", | ||
535 | "Number of LL protocol packets waiting for the second stage of processing after initial receive.", | ||
536 | "Number of LL protocol packets waiting for the second stage of processing after initial receive.", | ||
537 | "", | ||
538 | "clientstack", | ||
539 | scene.Name, | ||
540 | StatType.Pull, | ||
541 | MeasuresOfInterest.AverageChangeOverTime, | ||
542 | stat => stat.Value = packetInbox.Count, | ||
543 | StatVerbosity.Debug)); | ||
544 | |||
464 | // XXX: These stats are also pool stats but we register them separately since they are currently not | 545 | // 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() | 546 | // turned on and off by EnablePools()/DisablePools() |
466 | StatsManager.RegisterStat( | 547 | StatsManager.RegisterStat( |
@@ -521,6 +602,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
521 | EnablePoolStats(); | 602 | EnablePoolStats(); |
522 | 603 | ||
523 | MainConsole.Instance.Commands.AddCommand( | 604 | MainConsole.Instance.Commands.AddCommand( |
605 | "Debug", false, "debug lludp packet", | ||
606 | "debug lludp packet [--default] <level> [<avatar-first-name> <avatar-last-name>]", | ||
607 | "Turn on packet debugging", | ||
608 | "If level > 255 then all incoming and outgoing packets are logged.\n" | ||
609 | + "If level <= 255 then incoming AgentUpdate and outgoing SimStats and SimulatorViewerTimeMessage packets are not logged.\n" | ||
610 | + "If level <= 200 then incoming RequestImage and outgoing ImagePacket, ImageData, LayerData and CoarseLocationUpdate packets are not logged.\n" | ||
611 | + "If level <= 100 then incoming ViewerEffect and AgentAnimation and outgoing ViewerEffect and AvatarAnimation packets are not logged.\n" | ||
612 | + "If level <= 50 then outgoing ImprovedTerseObjectUpdate packets are not logged.\n" | ||
613 | + "If level <= 0 then no packets are logged.\n" | ||
614 | + "If --default is specified then the level becomes the default logging level for all subsequent agents.\n" | ||
615 | + "In this case, you cannot also specify an avatar name.\n" | ||
616 | + "If an avatar name is given then only packets from that avatar are logged.", | ||
617 | HandlePacketCommand); | ||
618 | |||
619 | MainConsole.Instance.Commands.AddCommand( | ||
524 | "Debug", | 620 | "Debug", |
525 | false, | 621 | false, |
526 | "debug lludp start", | 622 | "debug lludp start", |
@@ -559,10 +655,78 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
559 | "debug lludp status", | 655 | "debug lludp status", |
560 | "Return status of LLUDP packet processing.", | 656 | "Return status of LLUDP packet processing.", |
561 | HandleStatusCommand); | 657 | HandleStatusCommand); |
658 | |||
659 | MainConsole.Instance.Commands.AddCommand( | ||
660 | "Debug", | ||
661 | false, | ||
662 | "debug lludp toggle agentupdate", | ||
663 | "debug lludp toggle agentupdate", | ||
664 | "Toggle whether agentupdate packets are processed or simply discarded.", | ||
665 | HandleAgentUpdateCommand); | ||
666 | } | ||
667 | |||
668 | private void HandlePacketCommand(string module, string[] args) | ||
669 | { | ||
670 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) | ||
671 | return; | ||
672 | |||
673 | bool setAsDefaultLevel = false; | ||
674 | OptionSet optionSet = new OptionSet().Add("default", o => setAsDefaultLevel = o != null); | ||
675 | List<string> filteredArgs = optionSet.Parse(args); | ||
676 | |||
677 | string name = null; | ||
678 | |||
679 | if (filteredArgs.Count == 6) | ||
680 | { | ||
681 | if (!setAsDefaultLevel) | ||
682 | { | ||
683 | name = string.Format("{0} {1}", filteredArgs[4], filteredArgs[5]); | ||
684 | } | ||
685 | else | ||
686 | { | ||
687 | MainConsole.Instance.OutputFormat("ERROR: Cannot specify a user name when setting default logging level"); | ||
688 | return; | ||
689 | } | ||
690 | } | ||
691 | |||
692 | if (filteredArgs.Count > 3) | ||
693 | { | ||
694 | int newDebug; | ||
695 | if (int.TryParse(filteredArgs[3], out newDebug)) | ||
696 | { | ||
697 | if (setAsDefaultLevel) | ||
698 | { | ||
699 | DefaultClientPacketDebugLevel = newDebug; | ||
700 | MainConsole.Instance.OutputFormat( | ||
701 | "Debug packet debug for new clients set to {0} in {1}", DefaultClientPacketDebugLevel, m_scene.Name); | ||
702 | } | ||
703 | else | ||
704 | { | ||
705 | m_scene.ForEachScenePresence(sp => | ||
706 | { | ||
707 | if (name == null || sp.Name == name) | ||
708 | { | ||
709 | MainConsole.Instance.OutputFormat( | ||
710 | "Packet debug for {0} ({1}) set to {2} in {3}", | ||
711 | sp.Name, sp.IsChildAgent ? "child" : "root", newDebug, m_scene.Name); | ||
712 | |||
713 | sp.ControllingClient.DebugPacketLevel = newDebug; | ||
714 | } | ||
715 | }); | ||
716 | } | ||
717 | } | ||
718 | else | ||
719 | { | ||
720 | MainConsole.Instance.Output("Usage: debug lludp packet [--default] 0..255 [<first-name> <last-name>]"); | ||
721 | } | ||
722 | } | ||
562 | } | 723 | } |
563 | 724 | ||
564 | private void HandleStartCommand(string module, string[] args) | 725 | private void HandleStartCommand(string module, string[] args) |
565 | { | 726 | { |
727 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) | ||
728 | return; | ||
729 | |||
566 | if (args.Length != 4) | 730 | if (args.Length != 4) |
567 | { | 731 | { |
568 | MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>"); | 732 | MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>"); |
@@ -580,6 +744,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
580 | 744 | ||
581 | private void HandleStopCommand(string module, string[] args) | 745 | private void HandleStopCommand(string module, string[] args) |
582 | { | 746 | { |
747 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) | ||
748 | return; | ||
749 | |||
583 | if (args.Length != 4) | 750 | if (args.Length != 4) |
584 | { | 751 | { |
585 | MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>"); | 752 | MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>"); |
@@ -597,6 +764,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
597 | 764 | ||
598 | private void HandlePoolCommand(string module, string[] args) | 765 | private void HandlePoolCommand(string module, string[] args) |
599 | { | 766 | { |
767 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) | ||
768 | return; | ||
769 | |||
600 | if (args.Length != 4) | 770 | if (args.Length != 4) |
601 | { | 771 | { |
602 | MainConsole.Instance.Output("Usage: debug lludp pool <on|off>"); | 772 | MainConsole.Instance.Output("Usage: debug lludp pool <on|off>"); |
@@ -627,8 +797,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
627 | } | 797 | } |
628 | } | 798 | } |
629 | 799 | ||
800 | bool m_discardAgentUpdates; | ||
801 | |||
802 | private void HandleAgentUpdateCommand(string module, string[] args) | ||
803 | { | ||
804 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) | ||
805 | return; | ||
806 | |||
807 | m_discardAgentUpdates = !m_discardAgentUpdates; | ||
808 | |||
809 | MainConsole.Instance.OutputFormat( | ||
810 | "Discard AgentUpdates now {0} for {1}", m_discardAgentUpdates, m_scene.Name); | ||
811 | } | ||
812 | |||
630 | private void HandleStatusCommand(string module, string[] args) | 813 | private void HandleStatusCommand(string module, string[] args) |
631 | { | 814 | { |
815 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) | ||
816 | return; | ||
817 | |||
632 | MainConsole.Instance.OutputFormat( | 818 | MainConsole.Instance.OutputFormat( |
633 | "IN LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningInbound ? "enabled" : "disabled"); | 819 | "IN LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningInbound ? "enabled" : "disabled"); |
634 | 820 | ||
@@ -636,6 +822,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
636 | "OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled"); | 822 | "OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled"); |
637 | 823 | ||
638 | MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_scene.Name, UsePools ? "on" : "off"); | 824 | MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_scene.Name, UsePools ? "on" : "off"); |
825 | |||
826 | MainConsole.Instance.OutputFormat( | ||
827 | "Packet debug level for new clients is {0}", DefaultClientPacketDebugLevel); | ||
639 | } | 828 | } |
640 | 829 | ||
641 | public bool HandlesRegion(Location x) | 830 | public bool HandlesRegion(Location x) |
@@ -721,6 +910,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
721 | } | 910 | } |
722 | 911 | ||
723 | PacketPool.Instance.ReturnPacket(packet); | 912 | PacketPool.Instance.ReturnPacket(packet); |
913 | |||
914 | m_dataPresentEvent.Set(); | ||
724 | } | 915 | } |
725 | 916 | ||
726 | /// <summary> | 917 | /// <summary> |
@@ -883,7 +1074,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 | 1074 | // 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. | 1075 | // 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. | 1076 | // This is the same as processing as the async process of a logout request. |
886 | Util.FireAndForget(o => DeactivateClientDueToTimeout(client)); | 1077 | Util.FireAndForget(o => DeactivateClientDueToTimeout(client, timeoutTicks)); |
887 | 1078 | ||
888 | return; | 1079 | return; |
889 | } | 1080 | } |
@@ -1127,6 +1318,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1127 | queue.Enqueue(buffer); | 1318 | queue.Enqueue(buffer); |
1128 | return; | 1319 | return; |
1129 | } | 1320 | } |
1321 | else if (packet.Type == PacketType.CompleteAgentMovement) | ||
1322 | { | ||
1323 | // Send ack straight away to let the viewer know that we got it. | ||
1324 | SendAckImmediate(endPoint, packet.Header.Sequence); | ||
1325 | |||
1326 | // We need to copy the endpoint so that it doesn't get changed when another thread reuses the | ||
1327 | // buffer. | ||
1328 | object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; | ||
1329 | |||
1330 | Util.FireAndForget(HandleCompleteMovementIntoRegion, array); | ||
1331 | |||
1332 | return; | ||
1333 | } | ||
1130 | } | 1334 | } |
1131 | 1335 | ||
1132 | // Determine which agent this packet came from | 1336 | // Determine which agent this packet came from |
@@ -1233,6 +1437,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1233 | LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length); | 1437 | LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length); |
1234 | #endregion BinaryStats | 1438 | #endregion BinaryStats |
1235 | 1439 | ||
1440 | if (packet.Type == PacketType.AgentUpdate) | ||
1441 | { | ||
1442 | if (m_discardAgentUpdates) | ||
1443 | return; | ||
1444 | |||
1445 | ((LLClientView)client).TotalAgentUpdates++; | ||
1446 | |||
1447 | AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet; | ||
1448 | |||
1449 | LLClientView llClient = client as LLClientView; | ||
1450 | if (agentUpdate.AgentData.SessionID != client.SessionId | ||
1451 | || agentUpdate.AgentData.AgentID != client.AgentId | ||
1452 | || !(llClient == null || llClient.CheckAgentUpdateSignificance(agentUpdate.AgentData)) ) | ||
1453 | { | ||
1454 | PacketPool.Instance.ReturnPacket(packet); | ||
1455 | return; | ||
1456 | } | ||
1457 | } | ||
1458 | |||
1236 | #region Ping Check Handling | 1459 | #region Ping Check Handling |
1237 | 1460 | ||
1238 | if (packet.Type == PacketType.StartPingCheck) | 1461 | if (packet.Type == PacketType.StartPingCheck) |
@@ -1421,7 +1644,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1421 | 1644 | ||
1422 | // We only want to send initial data to new clients, not ones which are being converted from child to root. | 1645 | // We only want to send initial data to new clients, not ones which are being converted from child to root. |
1423 | if (client != null) | 1646 | if (client != null) |
1424 | client.SceneAgent.SendInitialDataToMe(); | 1647 | { |
1648 | AgentCircuitData aCircuit = m_scene.AuthenticateHandler.GetAgentCircuitData(uccp.CircuitCode.Code); | ||
1649 | bool tp = (aCircuit.teleportFlags > 0); | ||
1650 | // Let's delay this for TP agents, otherwise the viewer doesn't know where to get resources from | ||
1651 | if (!tp) | ||
1652 | client.SceneAgent.SendInitialDataToMe(); | ||
1653 | } | ||
1425 | 1654 | ||
1426 | // Now we know we can handle more data | 1655 | // Now we know we can handle more data |
1427 | Thread.Sleep(200); | 1656 | Thread.Sleep(200); |
@@ -1476,6 +1705,72 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1476 | } | 1705 | } |
1477 | } | 1706 | } |
1478 | 1707 | ||
1708 | private void HandleCompleteMovementIntoRegion(object o) | ||
1709 | { | ||
1710 | IPEndPoint endPoint = null; | ||
1711 | IClientAPI client = null; | ||
1712 | |||
1713 | try | ||
1714 | { | ||
1715 | object[] array = (object[])o; | ||
1716 | endPoint = (IPEndPoint)array[0]; | ||
1717 | CompleteAgentMovementPacket packet = (CompleteAgentMovementPacket)array[1]; | ||
1718 | |||
1719 | // Determine which agent this packet came from | ||
1720 | int count = 20; | ||
1721 | bool ready = false; | ||
1722 | while (!ready && count-- > 0) | ||
1723 | { | ||
1724 | if (m_scene.TryGetClient(endPoint, out client) && client.IsActive && client.SceneAgent != null) | ||
1725 | { | ||
1726 | LLClientView llClientView = (LLClientView)client; | ||
1727 | LLUDPClient udpClient = llClientView.UDPClient; | ||
1728 | if (udpClient != null && udpClient.IsConnected) | ||
1729 | ready = true; | ||
1730 | else | ||
1731 | { | ||
1732 | m_log.Debug("[LLUDPSERVER]: Received a CompleteMovementIntoRegion in " + m_scene.RegionInfo.RegionName + " (not ready yet)"); | ||
1733 | Thread.Sleep(200); | ||
1734 | } | ||
1735 | } | ||
1736 | else | ||
1737 | { | ||
1738 | m_log.Debug("[LLUDPSERVER]: Received a CompleteMovementIntoRegion in " + m_scene.RegionInfo.RegionName + " (not ready yet)"); | ||
1739 | Thread.Sleep(200); | ||
1740 | } | ||
1741 | } | ||
1742 | |||
1743 | if (client == null) | ||
1744 | return; | ||
1745 | |||
1746 | IncomingPacket incomingPacket1; | ||
1747 | |||
1748 | // Inbox insertion | ||
1749 | if (UsePools) | ||
1750 | { | ||
1751 | incomingPacket1 = m_incomingPacketPool.GetObject(); | ||
1752 | incomingPacket1.Client = (LLClientView)client; | ||
1753 | incomingPacket1.Packet = packet; | ||
1754 | } | ||
1755 | else | ||
1756 | { | ||
1757 | incomingPacket1 = new IncomingPacket((LLClientView)client, packet); | ||
1758 | } | ||
1759 | |||
1760 | packetInbox.Enqueue(incomingPacket1); | ||
1761 | } | ||
1762 | catch (Exception e) | ||
1763 | { | ||
1764 | m_log.ErrorFormat( | ||
1765 | "[LLUDPSERVER]: CompleteMovementIntoRegion handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}", | ||
1766 | endPoint != null ? endPoint.ToString() : "n/a", | ||
1767 | client != null ? client.Name : "unknown", | ||
1768 | client != null ? client.AgentId.ToString() : "unknown", | ||
1769 | e.Message, | ||
1770 | e.StackTrace); | ||
1771 | } | ||
1772 | } | ||
1773 | |||
1479 | /// <summary> | 1774 | /// <summary> |
1480 | /// Send an ack immediately to the given endpoint. | 1775 | /// Send an ack immediately to the given endpoint. |
1481 | /// </summary> | 1776 | /// </summary> |
@@ -1544,6 +1839,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1544 | 1839 | ||
1545 | client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); | 1840 | client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); |
1546 | client.OnLogout += LogoutHandler; | 1841 | client.OnLogout += LogoutHandler; |
1842 | client.DebugPacketLevel = DefaultClientPacketDebugLevel; | ||
1547 | 1843 | ||
1548 | ((LLClientView)client).DisableFacelights = m_disableFacelights; | 1844 | ((LLClientView)client).DisableFacelights = m_disableFacelights; |
1549 | 1845 | ||
@@ -1562,18 +1858,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1562 | /// regular client pings. | 1858 | /// regular client pings. |
1563 | /// </remarks> | 1859 | /// </remarks> |
1564 | /// <param name='client'></param> | 1860 | /// <param name='client'></param> |
1565 | private void DeactivateClientDueToTimeout(LLClientView client) | 1861 | /// <param name='timeoutTicks'></param> |
1862 | private void DeactivateClientDueToTimeout(LLClientView client, int timeoutTicks) | ||
1566 | { | 1863 | { |
1567 | lock (client.CloseSyncLock) | 1864 | lock (client.CloseSyncLock) |
1568 | { | 1865 | { |
1866 | ClientLogoutsDueToNoReceives++; | ||
1867 | |||
1569 | m_log.WarnFormat( | 1868 | m_log.WarnFormat( |
1570 | "[LLUDPSERVER]: Ack timeout, disconnecting {0} agent for {1} in {2}", | 1869 | "[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); | 1870 | client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, timeoutTicks, m_scene.Name); |
1572 | |||
1573 | StatsManager.SimExtraStats.AddAbnormalClientThreadTermination(); | ||
1574 | 1871 | ||
1575 | if (!client.SceneAgent.IsChildAgent) | 1872 | if (!client.SceneAgent.IsChildAgent) |
1576 | client.Kick("Simulator logged you out due to connection timeout"); | 1873 | client.Kick("Simulator logged you out due to connection timeout."); |
1577 | 1874 | ||
1578 | client.CloseWithoutChecks(true); | 1875 | client.CloseWithoutChecks(true); |
1579 | } | 1876 | } |
@@ -1592,6 +1889,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1592 | { | 1889 | { |
1593 | IncomingPacket incomingPacket = null; | 1890 | IncomingPacket incomingPacket = null; |
1594 | 1891 | ||
1892 | /* | ||
1595 | // HACK: This is a test to try and rate limit packet handling on Mono. | 1893 | // 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 | 1894 | // If it works, a more elegant solution can be devised |
1597 | if (Util.FireAndForgetCount() < 2) | 1895 | if (Util.FireAndForgetCount() < 2) |
@@ -1599,6 +1897,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1599 | //m_log.Debug("[LLUDPSERVER]: Incoming packet handler is sleeping"); | 1897 | //m_log.Debug("[LLUDPSERVER]: Incoming packet handler is sleeping"); |
1600 | Thread.Sleep(30); | 1898 | Thread.Sleep(30); |
1601 | } | 1899 | } |
1900 | */ | ||
1602 | 1901 | ||
1603 | if (packetInbox.Dequeue(100, ref incomingPacket)) | 1902 | if (packetInbox.Dequeue(100, ref incomingPacket)) |
1604 | { | 1903 | { |
@@ -1694,8 +1993,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1694 | 1993 | ||
1695 | // If nothing was sent, sleep for the minimum amount of time before a | 1994 | // If nothing was sent, sleep for the minimum amount of time before a |
1696 | // token bucket could get more tokens | 1995 | // token bucket could get more tokens |
1996 | //if (!m_packetSent) | ||
1997 | // Thread.Sleep((int)TickCountResolution); | ||
1998 | // | ||
1999 | // Instead, now wait for data present to be explicitly signalled. Evidence so far is that with | ||
2000 | // modern mono it reduces CPU base load since there is no more continuous polling. | ||
1697 | if (!m_packetSent) | 2001 | if (!m_packetSent) |
1698 | Thread.Sleep((int)TickCountResolution); | 2002 | m_dataPresentEvent.WaitOne(100); |
1699 | 2003 | ||
1700 | Watchdog.UpdateThread(); | 2004 | Watchdog.UpdateThread(); |
1701 | } | 2005 | } |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs index 7035e38..48c5b37 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 | ||
@@ -267,6 +301,8 @@ namespace OpenMetaverse | |||
267 | // to AsyncBeginReceive | 301 | // to AsyncBeginReceive |
268 | if (IsRunningInbound) | 302 | if (IsRunningInbound) |
269 | { | 303 | { |
304 | UdpReceives++; | ||
305 | |||
270 | // Asynchronous mode will start another receive before the | 306 | // Asynchronous mode will start another receive before the |
271 | // callback for this packet is even fired. Very parallel :-) | 307 | // callback for this packet is even fired. Very parallel :-) |
272 | if (m_asyncPacketHandling) | 308 | if (m_asyncPacketHandling) |
@@ -278,6 +314,8 @@ namespace OpenMetaverse | |||
278 | 314 | ||
279 | try | 315 | try |
280 | { | 316 | { |
317 | int startTick = Util.EnvironmentTickCount(); | ||
318 | |||
281 | // get the length of data actually read from the socket, store it with the | 319 | // get the length of data actually read from the socket, store it with the |
282 | // buffer | 320 | // buffer |
283 | buffer.DataLength = m_udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint); | 321 | buffer.DataLength = m_udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint); |
@@ -285,6 +323,23 @@ namespace OpenMetaverse | |||
285 | // call the abstract method PacketReceived(), passing the buffer that | 323 | // call the abstract method PacketReceived(), passing the buffer that |
286 | // has just been filled from the socket read. | 324 | // has just been filled from the socket read. |
287 | PacketReceived(buffer); | 325 | PacketReceived(buffer); |
326 | |||
327 | // If more than one thread can be calling AsyncEndReceive() at once (e.g. if m_asyncPacketHandler) | ||
328 | // then a particular stat may be inaccurate due to a race condition. We won't worry about this | ||
329 | // since this should be rare and won't cause a runtime problem. | ||
330 | if (m_currentReceiveTimeSamples >= s_receiveTimeSamples) | ||
331 | { | ||
332 | AverageReceiveTicksForLastSamplePeriod | ||
333 | = (float)m_receiveTicksInCurrentSamplePeriod / s_receiveTimeSamples; | ||
334 | |||
335 | m_receiveTicksInCurrentSamplePeriod = 0; | ||
336 | m_currentReceiveTimeSamples = 0; | ||
337 | } | ||
338 | else | ||
339 | { | ||
340 | m_receiveTicksInCurrentSamplePeriod += Util.EnvironmentTickCountSubtract(startTick); | ||
341 | m_currentReceiveTimeSamples++; | ||
342 | } | ||
288 | } | 343 | } |
289 | catch (SocketException) { } | 344 | catch (SocketException) { } |
290 | catch (ObjectDisposedException) { } | 345 | catch (ObjectDisposedException) { } |
@@ -298,14 +353,13 @@ namespace OpenMetaverse | |||
298 | if (!m_asyncPacketHandling) | 353 | if (!m_asyncPacketHandling) |
299 | AsyncBeginReceive(); | 354 | AsyncBeginReceive(); |
300 | } | 355 | } |
301 | |||
302 | } | 356 | } |
303 | } | 357 | } |
304 | 358 | ||
305 | public void AsyncBeginSend(UDPPacketBuffer buf) | 359 | public void AsyncBeginSend(UDPPacketBuffer buf) |
306 | { | 360 | { |
307 | if (IsRunningOutbound) | 361 | // if (IsRunningOutbound) |
308 | { | 362 | // { |
309 | try | 363 | try |
310 | { | 364 | { |
311 | m_udpSocket.BeginSendTo( | 365 | m_udpSocket.BeginSendTo( |
@@ -319,7 +373,7 @@ namespace OpenMetaverse | |||
319 | } | 373 | } |
320 | catch (SocketException) { } | 374 | catch (SocketException) { } |
321 | catch (ObjectDisposedException) { } | 375 | catch (ObjectDisposedException) { } |
322 | } | 376 | // } |
323 | } | 377 | } |
324 | 378 | ||
325 | void AsyncEndSend(IAsyncResult result) | 379 | void AsyncEndSend(IAsyncResult result) |
@@ -328,6 +382,8 @@ namespace OpenMetaverse | |||
328 | { | 382 | { |
329 | // UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState; | 383 | // UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState; |
330 | m_udpSocket.EndSendTo(result); | 384 | m_udpSocket.EndSendTo(result); |
385 | |||
386 | UdpSends++; | ||
331 | } | 387 | } |
332 | catch (SocketException) { } | 388 | catch (SocketException) { } |
333 | catch (ObjectDisposedException) { } | 389 | catch (ObjectDisposedException) { } |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs index 556df30..b47ff54 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> |
@@ -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..83144e3 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs | |||
@@ -73,8 +73,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
73 | } | 73 | } |
74 | 74 | ||
75 | [SetUp] | 75 | [SetUp] |
76 | public void SetUp() | 76 | public override void SetUp() |
77 | { | 77 | { |
78 | base.SetUp(); | ||
79 | |||
78 | UUID userId = TestHelpers.ParseTail(0x3); | 80 | UUID userId = TestHelpers.ParseTail(0x3); |
79 | 81 | ||
80 | J2KDecoderModule j2kdm = new J2KDecoderModule(); | 82 | J2KDecoderModule j2kdm = new J2KDecoderModule(); |