aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/Linden/UDP
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/UDP')
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs4
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs1423
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs7
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs243
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs974
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs901
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs206
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs25
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs7
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs110
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs17
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs78
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs1
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/TestLLUDPServer.cs170
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs427
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs17
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs292
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs19
18 files changed, 3738 insertions, 1183 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
index afbe56b..4d0568d 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
@@ -421,12 +421,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
421 // foreign user is visiting, we need to try again after the first fail to the local 421 // foreign user is visiting, we need to try again after the first fail to the local
422 // asset service. 422 // asset service.
423 string assetServerURL = string.Empty; 423 string assetServerURL = string.Empty;
424 if (InventoryAccessModule.IsForeignUser(AgentID, out assetServerURL)) 424 if (InventoryAccessModule.IsForeignUser(AgentID, out assetServerURL) && !string.IsNullOrEmpty(assetServerURL))
425 { 425 {
426 if (!assetServerURL.EndsWith("/") && !assetServerURL.EndsWith("=")) 426 if (!assetServerURL.EndsWith("/") && !assetServerURL.EndsWith("="))
427 assetServerURL = assetServerURL + "/"; 427 assetServerURL = assetServerURL + "/";
428 428
429 m_log.DebugFormat("[J2KIMAGE]: texture {0} not found in local asset storage. Trying user's storage.", assetServerURL + id); 429// m_log.DebugFormat("[J2KIMAGE]: texture {0} not found in local asset storage. Trying user's storage.", assetServerURL + id);
430 AssetService.Get(assetServerURL + id, InventoryAccessModule, AssetReceived); 430 AssetService.Get(assetServerURL + id, InventoryAccessModule, AssetReceived);
431 return; 431 return;
432 } 432 }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
index 967fa44..b17b822 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -34,11 +34,13 @@ using System.Text;
34using System.Threading; 34using System.Threading;
35using System.Timers; 35using System.Timers;
36using System.Xml; 36using System.Xml;
37
37using log4net; 38using log4net;
38using OpenMetaverse; 39using OpenMetaverse;
39using OpenMetaverse.Packets; 40using OpenMetaverse.Packets;
40using OpenMetaverse.Messages.Linden; 41using OpenMetaverse.Messages.Linden;
41using OpenMetaverse.StructuredData; 42using OpenMetaverse.StructuredData;
43
42using OpenSim.Framework; 44using OpenSim.Framework;
43using OpenSim.Framework.Client; 45using OpenSim.Framework.Client;
44using OpenSim.Framework.Monitoring; 46using OpenSim.Framework.Monitoring;
@@ -48,9 +50,9 @@ using OpenSim.Services.Interfaces;
48using Timer = System.Timers.Timer; 50using Timer = System.Timers.Timer;
49using AssetLandmark = OpenSim.Framework.AssetLandmark; 51using AssetLandmark = OpenSim.Framework.AssetLandmark;
50using RegionFlags = OpenMetaverse.RegionFlags; 52using RegionFlags = OpenMetaverse.RegionFlags;
51using Nini.Config;
52 53
53using System.IO; 54using System.IO;
55using PermissionMask = OpenSim.Framework.PermissionMask;
54 56
55namespace OpenSim.Region.ClientStack.LindenUDP 57namespace OpenSim.Region.ClientStack.LindenUDP
56{ 58{
@@ -69,7 +71,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
69 71
70 #region Events 72 #region Events
71 73
72 public event GenericMessage OnGenericMessage;
73 public event BinaryGenericMessage OnBinaryGenericMessage; 74 public event BinaryGenericMessage OnBinaryGenericMessage;
74 public event Action<IClientAPI> OnLogout; 75 public event Action<IClientAPI> OnLogout;
75 public event ObjectPermissions OnObjectPermissions; 76 public event ObjectPermissions OnObjectPermissions;
@@ -77,7 +78,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
77 public event ViewerEffectEventHandler OnViewerEffect; 78 public event ViewerEffectEventHandler OnViewerEffect;
78 public event ImprovedInstantMessage OnInstantMessage; 79 public event ImprovedInstantMessage OnInstantMessage;
79 public event ChatMessage OnChatFromClient; 80 public event ChatMessage OnChatFromClient;
80 public event TextureRequest OnRequestTexture;
81 public event RezObject OnRezObject; 81 public event RezObject OnRezObject;
82 public event DeRezObject OnDeRezObject; 82 public event DeRezObject OnDeRezObject;
83 public event ModifyTerrain OnModifyTerrain; 83 public event ModifyTerrain OnModifyTerrain;
@@ -94,6 +94,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
94 public event Action<IClientAPI, bool> OnCompleteMovementToRegion; 94 public event Action<IClientAPI, bool> OnCompleteMovementToRegion;
95 public event UpdateAgent OnPreAgentUpdate; 95 public event UpdateAgent OnPreAgentUpdate;
96 public event UpdateAgent OnAgentUpdate; 96 public event UpdateAgent OnAgentUpdate;
97 public event UpdateAgent OnAgentCameraUpdate;
97 public event AgentRequestSit OnAgentRequestSit; 98 public event AgentRequestSit OnAgentRequestSit;
98 public event AgentSit OnAgentSit; 99 public event AgentSit OnAgentSit;
99 public event AvatarPickerRequest OnAvatarPickerRequest; 100 public event AvatarPickerRequest OnAvatarPickerRequest;
@@ -134,15 +135,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
134 public event UpdatePrimGroupRotation OnUpdatePrimGroupMouseRotation; 135 public event UpdatePrimGroupRotation OnUpdatePrimGroupMouseRotation;
135 public event UpdateVector OnUpdatePrimScale; 136 public event UpdateVector OnUpdatePrimScale;
136 public event UpdateVector OnUpdatePrimGroupScale; 137 public event UpdateVector OnUpdatePrimGroupScale;
137 public event StatusChange OnChildAgentStatus;
138 public event GenericCall2 OnStopMovement;
139 public event Action<UUID> OnRemoveAvatar;
140 public event RequestMapBlocks OnRequestMapBlocks; 138 public event RequestMapBlocks OnRequestMapBlocks;
141 public event RequestMapName OnMapNameRequest; 139 public event RequestMapName OnMapNameRequest;
142 public event TeleportLocationRequest OnTeleportLocationRequest; 140 public event TeleportLocationRequest OnTeleportLocationRequest;
143 public event TeleportLandmarkRequest OnTeleportLandmarkRequest; 141 public event TeleportLandmarkRequest OnTeleportLandmarkRequest;
144 public event TeleportCancel OnTeleportCancel; 142 public event TeleportCancel OnTeleportCancel;
145 public event DisconnectUser OnDisconnectUser;
146 public event RequestAvatarProperties OnRequestAvatarProperties; 143 public event RequestAvatarProperties OnRequestAvatarProperties;
147 public event SetAlwaysRun OnSetAlwaysRun; 144 public event SetAlwaysRun OnSetAlwaysRun;
148 public event FetchInventory OnAgentDataUpdateRequest; 145 public event FetchInventory OnAgentDataUpdateRequest;
@@ -172,7 +169,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
172 public event UpdateTaskInventory OnUpdateTaskInventory; 169 public event UpdateTaskInventory OnUpdateTaskInventory;
173 public event MoveTaskInventory OnMoveTaskItem; 170 public event MoveTaskInventory OnMoveTaskItem;
174 public event RemoveTaskInventory OnRemoveTaskItem; 171 public event RemoveTaskInventory OnRemoveTaskItem;
175 public event RequestAsset OnRequestAsset;
176 public event UUIDNameRequest OnNameFromUUIDRequest; 172 public event UUIDNameRequest OnNameFromUUIDRequest;
177 public event ParcelAccessListRequest OnParcelAccessListRequest; 173 public event ParcelAccessListRequest OnParcelAccessListRequest;
178 public event ParcelAccessListUpdateRequest OnParcelAccessListUpdateRequest; 174 public event ParcelAccessListUpdateRequest OnParcelAccessListUpdateRequest;
@@ -203,7 +199,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
203 public event RequestPayPrice OnRequestPayPrice; 199 public event RequestPayPrice OnRequestPayPrice;
204 public event ObjectSaleInfo OnObjectSaleInfo; 200 public event ObjectSaleInfo OnObjectSaleInfo;
205 public event ObjectBuy OnObjectBuy; 201 public event ObjectBuy OnObjectBuy;
206 public event BuyObjectInventory OnBuyObjectInventory;
207 public event AgentSit OnUndo; 202 public event AgentSit OnUndo;
208 public event AgentSit OnRedo; 203 public event AgentSit OnRedo;
209 public event LandUndo OnLandUndo; 204 public event LandUndo OnLandUndo;
@@ -212,7 +207,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
212 public event RequestObjectPropertiesFamily OnObjectGroupRequest; 207 public event RequestObjectPropertiesFamily OnObjectGroupRequest;
213 public event DetailedEstateDataRequest OnDetailedEstateDataRequest; 208 public event DetailedEstateDataRequest OnDetailedEstateDataRequest;
214 public event SetEstateFlagsRequest OnSetEstateFlagsRequest; 209 public event SetEstateFlagsRequest OnSetEstateFlagsRequest;
215 public event SetEstateTerrainBaseTexture OnSetEstateTerrainBaseTexture;
216 public event SetEstateTerrainDetailTexture OnSetEstateTerrainDetailTexture; 210 public event SetEstateTerrainDetailTexture OnSetEstateTerrainDetailTexture;
217 public event SetEstateTerrainTextureHeights OnSetEstateTerrainTextureHeights; 211 public event SetEstateTerrainTextureHeights OnSetEstateTerrainTextureHeights;
218 public event CommitEstateTerrainTextureRequest OnCommitEstateTerrainTextureRequest; 212 public event CommitEstateTerrainTextureRequest OnCommitEstateTerrainTextureRequest;
@@ -235,7 +229,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
235 public event GetScriptRunning OnGetScriptRunning; 229 public event GetScriptRunning OnGetScriptRunning;
236 public event SetScriptRunning OnSetScriptRunning; 230 public event SetScriptRunning OnSetScriptRunning;
237 public event Action<Vector3, bool, bool> OnAutoPilotGo; 231 public event Action<Vector3, bool, bool> OnAutoPilotGo;
238 public event TerrainUnacked OnUnackedTerrain;
239 public event ActivateGesture OnActivateGesture; 232 public event ActivateGesture OnActivateGesture;
240 public event DeactivateGesture OnDeactivateGesture; 233 public event DeactivateGesture OnDeactivateGesture;
241 public event ObjectOwner OnObjectOwner; 234 public event ObjectOwner OnObjectOwner;
@@ -293,6 +286,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
293 public event GodlikeMessage onGodlikeMessage; 286 public event GodlikeMessage onGodlikeMessage;
294 public event GodUpdateRegionInfoUpdate OnGodUpdateRegionInfoUpdate; 287 public event GodUpdateRegionInfoUpdate OnGodUpdateRegionInfoUpdate;
295 288
289#pragma warning disable 0067
290 public event GenericMessage OnGenericMessage;
291 public event TextureRequest OnRequestTexture;
292 public event StatusChange OnChildAgentStatus;
293 public event GenericCall2 OnStopMovement;
294 public event Action<UUID> OnRemoveAvatar;
295 public event DisconnectUser OnDisconnectUser;
296 public event RequestAsset OnRequestAsset;
297 public event BuyObjectInventory OnBuyObjectInventory;
298 public event SetEstateTerrainBaseTexture OnSetEstateTerrainBaseTexture;
299 public event TerrainUnacked OnUnackedTerrain;
300 public event CachedTextureRequest OnCachedTextureRequest;
301#pragma warning restore 0067
302
296 #endregion Events 303 #endregion Events
297 304
298 #region Class Members 305 #region Class Members
@@ -304,6 +311,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
304 private const float m_sunPainDaHalfOrbitalCutoff = 4.712388980384689858f; 311 private const float m_sunPainDaHalfOrbitalCutoff = 4.712388980384689858f;
305 312
306 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 313 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
314 private static string LogHeader = "[LLCLIENTVIEW]";
307 protected static Dictionary<PacketType, PacketMethod> PacketHandlers = new Dictionary<PacketType, PacketMethod>(); //Global/static handlers for all clients 315 protected static Dictionary<PacketType, PacketMethod> PacketHandlers = new Dictionary<PacketType, PacketMethod>(); //Global/static handlers for all clients
308 316
309 /// <summary> 317 /// <summary>
@@ -325,7 +333,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
325 private PriorityQueue m_entityProps; 333 private PriorityQueue m_entityProps;
326 private Prioritizer m_prioritizer; 334 private Prioritizer m_prioritizer;
327 private bool m_disableFacelights = false; 335 private bool m_disableFacelights = false;
328 336 private volatile bool m_justEditedTerrain = false;
329 /// <value> 337 /// <value>
330 /// List used in construction of data blocks for an object update packet. This is to stop us having to 338 /// List used in construction of data blocks for an object update packet. This is to stop us having to
331 /// continually recreate it. 339 /// continually recreate it.
@@ -344,7 +352,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
344 352
345// protected HashSet<uint> m_attachmentsSent; 353// protected HashSet<uint> m_attachmentsSent;
346 354
347 private int m_moneyBalance;
348 private int m_animationSequenceNumber = 1; 355 private int m_animationSequenceNumber = 1;
349 private bool m_SendLogoutPacketWhenClosing = true; 356 private bool m_SendLogoutPacketWhenClosing = true;
350 357
@@ -357,7 +364,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
357 /// This does mean that agent updates must be processed synchronously, at least for each client, and called methods 364 /// This does mean that agent updates must be processed synchronously, at least for each client, and called methods
358 /// cannot retain a reference to it outside of that method. 365 /// cannot retain a reference to it outside of that method.
359 /// </remarks> 366 /// </remarks>
360 private AgentUpdateArgs m_lastAgentUpdateArgs; 367 private AgentUpdateArgs m_thisAgentUpdateArgs = new AgentUpdateArgs();
361 368
362 protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>(); 369 protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>();
363 protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers 370 protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers
@@ -393,9 +400,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
393 } 400 }
394 public UUID AgentId { get { return m_agentId; } } 401 public UUID AgentId { get { return m_agentId; } }
395 public ISceneAgent SceneAgent { get; set; } 402 public ISceneAgent SceneAgent { get; set; }
396 public UUID ActiveGroupId { get { return m_activeGroupID; } } 403 public UUID ActiveGroupId { get { return m_activeGroupID; } private set { m_activeGroupID = value; } }
397 public string ActiveGroupName { get { return m_activeGroupName; } } 404 public string ActiveGroupName { get { return m_activeGroupName; } private set { m_activeGroupName = value; } }
398 public ulong ActiveGroupPowers { get { return m_activeGroupPowers; } } 405 public ulong ActiveGroupPowers { get { return m_activeGroupPowers; } private set { m_activeGroupPowers = value; } }
399 public bool IsGroupMember(UUID groupID) { return m_groupPowers.ContainsKey(groupID); } 406 public bool IsGroupMember(UUID groupID) { return m_groupPowers.ContainsKey(groupID); }
400 407
401 /// <summary> 408 /// <summary>
@@ -419,7 +426,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
419 public string Name { get { return FirstName + " " + LastName; } } 426 public string Name { get { return FirstName + " " + LastName; } }
420 427
421 public uint CircuitCode { get { return m_circuitCode; } } 428 public uint CircuitCode { get { return m_circuitCode; } }
422 public int MoneyBalance { get { return m_moneyBalance; } }
423 public int NextAnimationSequenceNumber { get { return m_animationSequenceNumber++; } } 429 public int NextAnimationSequenceNumber { get { return m_animationSequenceNumber++; } }
424 430
425 /// <summary> 431 /// <summary>
@@ -447,7 +453,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
447 453
448// ~LLClientView() 454// ~LLClientView()
449// { 455// {
450// m_log.DebugFormat("[LLCLIENTVIEW]: Destructor called for {0}, circuit code {1}", Name, CircuitCode); 456// m_log.DebugFormat("{0} Destructor called for {1}, circuit code {2}", LogHeader, Name, CircuitCode);
451// } 457// }
452 458
453 /// <summary> 459 /// <summary>
@@ -482,11 +488,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
482 m_firstName = sessionInfo.LoginInfo.First; 488 m_firstName = sessionInfo.LoginInfo.First;
483 m_lastName = sessionInfo.LoginInfo.Last; 489 m_lastName = sessionInfo.LoginInfo.Last;
484 m_startpos = sessionInfo.LoginInfo.StartPos; 490 m_startpos = sessionInfo.LoginInfo.StartPos;
485 m_moneyBalance = 1000;
486 491
487 m_udpServer = udpServer; 492 m_udpServer = udpServer;
488 m_udpClient = udpClient; 493 m_udpClient = udpClient;
489 m_udpClient.OnQueueEmpty += HandleQueueEmpty; 494 m_udpClient.OnQueueEmpty += HandleQueueEmpty;
495 m_udpClient.HasUpdates += HandleHasUpdates;
490 m_udpClient.OnPacketStats += PopulateStats; 496 m_udpClient.OnPacketStats += PopulateStats;
491 497
492 m_prioritizer = new Prioritizer(m_scene); 498 m_prioritizer = new Prioritizer(m_scene);
@@ -512,7 +518,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
512 // We still perform a force close inside the sync lock since this is intended to attempt close where 518 // We still perform a force close inside the sync lock since this is intended to attempt close where
513 // there is some unidentified connection problem, not where we have issues due to deadlock 519 // there is some unidentified connection problem, not where we have issues due to deadlock
514 if (!IsActive && !force) 520 if (!IsActive && !force)
521 {
522 m_log.DebugFormat( "{0} Not attempting to close inactive client {1} in {2} since force flag is not set",
523 LogHeader, Name, m_scene.Name);
524
515 return; 525 return;
526 }
516 527
517 IsActive = false; 528 IsActive = false;
518 CloseWithoutChecks(); 529 CloseWithoutChecks();
@@ -637,12 +648,36 @@ namespace OpenSim.Region.ClientStack.LindenUDP
637 /// <returns>true if the handler was added. This is currently always the case.</returns> 648 /// <returns>true if the handler was added. This is currently always the case.</returns>
638 public bool AddLocalPacketHandler(PacketType packetType, PacketMethod handler, bool doAsync) 649 public bool AddLocalPacketHandler(PacketType packetType, PacketMethod handler, bool doAsync)
639 { 650 {
651 return AddLocalPacketHandler(packetType, handler, doAsync, false);
652 }
653
654 /// <summary>
655 /// Add a handler for the given packet type.
656 /// </summary>
657 /// <param name="packetType"></param>
658 /// <param name="handler"></param>
659 /// <param name="doAsync">
660 /// If true, when the packet is received handle it on a different thread. Whether this is given direct to
661 /// a threadpool thread or placed in a queue depends on the inEngine parameter.
662 /// </param>
663 /// <param name="inEngine">
664 /// If async is false then this parameter is ignored.
665 /// If async is true and inEngine is false, then the packet is sent directly to a
666 /// threadpool thread.
667 /// If async is true and inEngine is true, then the packet is sent to the IncomingPacketAsyncHandlingEngine.
668 /// This may result in slower handling but reduces the risk of overloading the simulator when there are many
669 /// simultaneous async requests.
670 /// </param>
671 /// <returns>true if the handler was added. This is currently always the case.</returns>
672 public bool AddLocalPacketHandler(PacketType packetType, PacketMethod handler, bool doAsync, bool inEngine)
673 {
640 bool result = false; 674 bool result = false;
641 lock (m_packetHandlers) 675 lock (m_packetHandlers)
642 { 676 {
643 if (!m_packetHandlers.ContainsKey(packetType)) 677 if (!m_packetHandlers.ContainsKey(packetType))
644 { 678 {
645 m_packetHandlers.Add(packetType, new PacketProcessor() { method = handler, Async = doAsync }); 679 m_packetHandlers.Add(
680 packetType, new PacketProcessor() { method = handler, Async = doAsync, InEngine = inEngine });
646 result = true; 681 result = true;
647 } 682 }
648 } 683 }
@@ -677,15 +712,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP
677 PacketProcessor pprocessor; 712 PacketProcessor pprocessor;
678 if (m_packetHandlers.TryGetValue(packet.Type, out pprocessor)) 713 if (m_packetHandlers.TryGetValue(packet.Type, out pprocessor))
679 { 714 {
715 ClientInfo cinfo = UDPClient.GetClientInfo();
716
680 //there is a local handler for this packet type 717 //there is a local handler for this packet type
681 if (pprocessor.Async) 718 if (pprocessor.Async)
682 { 719 {
720 if (!cinfo.AsyncRequests.ContainsKey(packet.Type.ToString()))
721 cinfo.AsyncRequests[packet.Type.ToString()] = 0;
722 cinfo.AsyncRequests[packet.Type.ToString()]++;
723
683 object obj = new AsyncPacketProcess(this, pprocessor.method, packet); 724 object obj = new AsyncPacketProcess(this, pprocessor.method, packet);
684 Util.FireAndForget(ProcessSpecificPacketAsync, obj); 725
726 if (pprocessor.InEngine)
727 m_udpServer.IpahEngine.QueueJob(packet.Type.ToString(), () => ProcessSpecificPacketAsync(obj));
728 else
729 Util.FireAndForget(ProcessSpecificPacketAsync, obj, packet.Type.ToString());
730
685 result = true; 731 result = true;
686 } 732 }
687 else 733 else
688 { 734 {
735 if (!cinfo.SyncRequests.ContainsKey(packet.Type.ToString()))
736 cinfo.SyncRequests[packet.Type.ToString()] = 0;
737 cinfo.SyncRequests[packet.Type.ToString()]++;
738
689 result = pprocessor.method(this, packet); 739 result = pprocessor.method(this, packet);
690 } 740 }
691 } 741 }
@@ -700,6 +750,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
700 } 750 }
701 if (found) 751 if (found)
702 { 752 {
753 ClientInfo cinfo = UDPClient.GetClientInfo();
754 if (!cinfo.GenericRequests.ContainsKey(packet.Type.ToString()))
755 cinfo.GenericRequests[packet.Type.ToString()] = 0;
756 cinfo.GenericRequests[packet.Type.ToString()]++;
757
703 result = method(this, packet); 758 result = method(this, packet);
704 } 759 }
705 } 760 }
@@ -717,9 +772,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
717 catch (Exception e) 772 catch (Exception e)
718 { 773 {
719 // Make sure that we see any exception caused by the asynchronous operation. 774 // Make sure that we see any exception caused by the asynchronous operation.
720 m_log.ErrorFormat( 775 m_log.Error(
721 "[LLCLIENTVIEW]: Caught exception while processing {0} for {1}, {2} {3}", 776 string.Format(
722 packetObject.Pack, Name, e.Message, e.StackTrace); 777 "[LLCLIENTVIEW]: Caught exception while processing {0} for {1} ", packetObject.Pack, Name),
778 e);
723 } 779 }
724 } 780 }
725 781
@@ -729,7 +785,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
729 785
730 public virtual void Start() 786 public virtual void Start()
731 { 787 {
732 m_scene.AddNewClient(this, PresenceType.User); 788 m_scene.AddNewAgent(this, PresenceType.User);
733 789
734 RefreshGroupMembership(); 790 RefreshGroupMembership();
735 } 791 }
@@ -791,9 +847,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
791 handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType); 847 handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType);
792 handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes; 848 handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes;
793 849
794 OutPacket(handshake, ThrottleOutPacketType.Task); 850 handshake.RegionInfo4 = new RegionHandshakePacket.RegionInfo4Block[1];
851 handshake.RegionInfo4[0] = new RegionHandshakePacket.RegionInfo4Block();
852 handshake.RegionInfo4[0].RegionFlagsExtended = args.regionFlags;
853 handshake.RegionInfo4[0].RegionProtocols = 0; // 1 here would indicate that SSB is supported
854
855 OutPacket(handshake, ThrottleOutPacketType.Unknown);
795 } 856 }
796 857
858
797 public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look) 859 public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look)
798 { 860 {
799 AgentMovementCompletePacket mov = (AgentMovementCompletePacket)PacketPool.Instance.GetPacket(PacketType.AgentMovementComplete); 861 AgentMovementCompletePacket mov = (AgentMovementCompletePacket)PacketPool.Instance.GetPacket(PacketType.AgentMovementComplete);
@@ -893,9 +955,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
893 } 955 }
894 } 956 }
895 957
896 public void SendGenericMessage(string method, List<string> message) 958 public void SendGenericMessage(string method, UUID invoice, List<string> message)
897 { 959 {
898 GenericMessagePacket gmp = new GenericMessagePacket(); 960 GenericMessagePacket gmp = new GenericMessagePacket();
961
962 gmp.AgentData.AgentID = AgentId;
963 gmp.AgentData.SessionID = m_sessionId;
964 gmp.AgentData.TransactionID = invoice;
965
899 gmp.MethodData.Method = Util.StringToBytes256(method); 966 gmp.MethodData.Method = Util.StringToBytes256(method);
900 gmp.ParamList = new GenericMessagePacket.ParamListBlock[message.Count]; 967 gmp.ParamList = new GenericMessagePacket.ParamListBlock[message.Count];
901 int i = 0; 968 int i = 0;
@@ -908,9 +975,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
908 OutPacket(gmp, ThrottleOutPacketType.Task); 975 OutPacket(gmp, ThrottleOutPacketType.Task);
909 } 976 }
910 977
911 public void SendGenericMessage(string method, List<byte[]> message) 978 public void SendGenericMessage(string method, UUID invoice, List<byte[]> message)
912 { 979 {
913 GenericMessagePacket gmp = new GenericMessagePacket(); 980 GenericMessagePacket gmp = new GenericMessagePacket();
981
982 gmp.AgentData.AgentID = AgentId;
983 gmp.AgentData.SessionID = m_sessionId;
984 gmp.AgentData.TransactionID = invoice;
985
914 gmp.MethodData.Method = Util.StringToBytes256(method); 986 gmp.MethodData.Method = Util.StringToBytes256(method);
915 gmp.ParamList = new GenericMessagePacket.ParamListBlock[message.Count]; 987 gmp.ParamList = new GenericMessagePacket.ParamListBlock[message.Count];
916 int i = 0; 988 int i = 0;
@@ -1112,11 +1184,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1112 1184
1113 /// <summary> 1185 /// <summary>
1114 /// Send the region heightmap to the client 1186 /// Send the region heightmap to the client
1187 /// This method is only called when not doing intellegent terrain patch sending and
1188 /// is only called when the scene presence is initially created and sends all of the
1189 /// region's patches to the client.
1115 /// </summary> 1190 /// </summary>
1116 /// <param name="map">heightmap</param> 1191 /// <param name="map">heightmap</param>
1117 public virtual void SendLayerData(float[] map) 1192 public virtual void SendLayerData(float[] map)
1118 { 1193 {
1119 Util.FireAndForget(DoSendLayerData, map); 1194 Util.FireAndForget(DoSendLayerData, m_scene.Heightmap.GetTerrainData(), "LLClientView.DoSendLayerData");
1120 } 1195 }
1121 1196
1122 /// <summary> 1197 /// <summary>
@@ -1125,10 +1200,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1125 /// <param name="o"></param> 1200 /// <param name="o"></param>
1126 private void DoSendLayerData(object o) 1201 private void DoSendLayerData(object o)
1127 { 1202 {
1128 float[] map = LLHeightFieldMoronize((float[])o); 1203 TerrainData map = (TerrainData)o;
1129 1204
1130 try 1205 try
1131 { 1206 {
1207 // Send LayerData in typerwriter pattern
1132 //for (int y = 0; y < 16; y++) 1208 //for (int y = 0; y < 16; y++)
1133 //{ 1209 //{
1134 // for (int x = 0; x < 16; x++) 1210 // for (int x = 0; x < 16; x++)
@@ -1138,7 +1214,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1138 //} 1214 //}
1139 1215
1140 // Send LayerData in a spiral pattern. Fun! 1216 // Send LayerData in a spiral pattern. Fun!
1141 SendLayerTopRight(map, 0, 0, 15, 15); 1217 SendLayerTopRight(map, 0, 0, map.SizeX/Constants.TerrainPatchSize-1, map.SizeY/Constants.TerrainPatchSize-1);
1142 } 1218 }
1143 catch (Exception e) 1219 catch (Exception e)
1144 { 1220 {
@@ -1146,7 +1222,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1146 } 1222 }
1147 } 1223 }
1148 1224
1149 private void SendLayerTopRight(float[] map, int x1, int y1, int x2, int y2) 1225 private void SendLayerTopRight(TerrainData map, int x1, int y1, int x2, int y2)
1150 { 1226 {
1151 // Row 1227 // Row
1152 for (int i = x1; i <= x2; i++) 1228 for (int i = x1; i <= x2; i++)
@@ -1156,11 +1232,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1156 for (int j = y1 + 1; j <= y2; j++) 1232 for (int j = y1 + 1; j <= y2; j++)
1157 SendLayerData(x2, j, map); 1233 SendLayerData(x2, j, map);
1158 1234
1159 if (x2 - x1 > 0) 1235 if (x2 - x1 > 0 && y2 - y1 > 0)
1160 SendLayerBottomLeft(map, x1, y1 + 1, x2 - 1, y2); 1236 SendLayerBottomLeft(map, x1, y1 + 1, x2 - 1, y2);
1161 } 1237 }
1162 1238
1163 void SendLayerBottomLeft(float[] map, int x1, int y1, int x2, int y2) 1239 void SendLayerBottomLeft(TerrainData map, int x1, int y1, int x2, int y2)
1164 { 1240 {
1165 // Row in reverse 1241 // Row in reverse
1166 for (int i = x2; i >= x1; i--) 1242 for (int i = x2; i >= x1; i--)
@@ -1170,7 +1246,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1170 for (int j = y2 - 1; j >= y1; j--) 1246 for (int j = y2 - 1; j >= y1; j--)
1171 SendLayerData(x1, j, map); 1247 SendLayerData(x1, j, map);
1172 1248
1173 if (x2 - x1 > 0) 1249 if (x2 - x1 > 0 && y2 - y1 > 0)
1174 SendLayerTopRight(map, x1 + 1, y1, x2, y2 - 1); 1250 SendLayerTopRight(map, x1 + 1, y1, x2, y2 - 1);
1175 } 1251 }
1176 1252
@@ -1192,25 +1268,98 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1192 // OutPacket(layerpack, ThrottleOutPacketType.Land); 1268 // OutPacket(layerpack, ThrottleOutPacketType.Land);
1193 // } 1269 // }
1194 1270
1271 // Legacy form of invocation that passes around a bare data array.
1272 // Just ignore what was passed and use the real terrain info that is part of the scene.
1273 // As a HORRIBLE kludge in an attempt to not change the definition of IClientAPI,
1274 // there is a special form for specifying multiple terrain patches to send.
1275 // The form is to pass 'px' as negative the number of patches to send and to
1276 // pass the float array as pairs of patch X and Y coordinates. So, passing 'px'
1277 // as -2 and map= [3, 5, 8, 4] would mean to send two terrain heightmap patches
1278 // and the patches to send are <3,5> and <8,4>.
1279 public void SendLayerData(int px, int py, float[] map)
1280 {
1281 if (px >= 0)
1282 {
1283 SendLayerData(px, py, m_scene.Heightmap.GetTerrainData());
1284 }
1285 else
1286 {
1287 int numPatches = -px;
1288 int[] xPatches = new int[numPatches];
1289 int[] yPatches = new int[numPatches];
1290 for (int pp = 0; pp < numPatches; pp++)
1291 {
1292 xPatches[pp] = (int)map[pp * 2];
1293 yPatches[pp] = (int)map[pp * 2 + 1];
1294 }
1295
1296 // DebugSendingPatches("SendLayerData", xPatches, yPatches);
1297
1298 SendLayerData(xPatches, yPatches, m_scene.Heightmap.GetTerrainData());
1299 }
1300 }
1301
1302 private void DebugSendingPatches(string pWho, int[] pX, int[] pY)
1303 {
1304 if (m_log.IsDebugEnabled)
1305 {
1306 int numPatches = pX.Length;
1307 string Xs = "";
1308 string Ys = "";
1309 for (int pp = 0; pp < numPatches; pp++)
1310 {
1311 Xs += String.Format("{0}", (int)pX[pp]) + ",";
1312 Ys += String.Format("{0}", (int)pY[pp]) + ",";
1313 }
1314 m_log.DebugFormat("{0} {1}: numPatches={2}, X={3}, Y={4}", LogHeader, pWho, numPatches, Xs, Ys);
1315 }
1316 }
1317
1195 /// <summary> 1318 /// <summary>
1196 /// Sends a specified patch to a client 1319 /// Sends a terrain packet for the point specified.
1320 /// This is a legacy call that has refarbed the terrain into a flat map of floats.
1321 /// We just use the terrain from the region we know about.
1197 /// </summary> 1322 /// </summary>
1198 /// <param name="px">Patch coordinate (x) 0..15</param> 1323 /// <param name="px">Patch coordinate (x) 0..15</param>
1199 /// <param name="py">Patch coordinate (y) 0..15</param> 1324 /// <param name="py">Patch coordinate (y) 0..15</param>
1200 /// <param name="map">heightmap</param> 1325 /// <param name="map">heightmap</param>
1201 public void SendLayerData(int px, int py, float[] map) 1326 public void SendLayerData(int px, int py, TerrainData terrData)
1327 {
1328 int[] xPatches = new[] { px };
1329 int[] yPatches = new[] { py };
1330 SendLayerData(xPatches, yPatches, terrData);
1331 }
1332
1333 private void SendLayerData(int[] px, int[] py, TerrainData terrData)
1202 { 1334 {
1203 try 1335 try
1204 { 1336 {
1205 int[] patches = new int[] { py * 16 + px }; 1337 /* test code using the terrain compressor in libOpenMetaverse
1206 float[] heightmap = (map.Length == 65536) ? 1338 int[] patchInd = new int[1];
1207 map : 1339 patchInd[0] = px + (py * Constants.TerrainPatchSize);
1208 LLHeightFieldMoronize(map); 1340 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(terrData.GetFloatsSerialized(), patchInd);
1341 */
1342 // Many, many patches could have been passed to us. Since the patches will be compressed
1343 // into variable sized blocks, we cannot pre-compute how many will fit into one
1344 // packet. While some fancy packing algorithm is possible, 4 seems to always fit.
1345 int PatchesAssumedToFit = 4;
1346 for (int pcnt = 0; pcnt < px.Length; pcnt += PatchesAssumedToFit)
1347 {
1348 int remaining = Math.Min(px.Length - pcnt, PatchesAssumedToFit);
1349 int[] xPatches = new int[remaining];
1350 int[] yPatches = new int[remaining];
1351 for (int ii = 0; ii < remaining; ii++)
1352 {
1353 xPatches[ii] = px[pcnt + ii];
1354 yPatches[ii] = py[pcnt + ii];
1355 }
1356 LayerDataPacket layerpack = OpenSimTerrainCompressor.CreateLandPacket(terrData, xPatches, yPatches);
1357 // DebugSendingPatches("SendLayerDataInternal", xPatches, yPatches);
1209 1358
1210 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); 1359 SendTheLayerPacket(layerpack);
1211 layerpack.Header.Reliable = true; 1360 }
1361 // LayerDataPacket layerpack = OpenSimTerrainCompressor.CreateLandPacket(terrData, px, py);
1212 1362
1213 OutPacket(layerpack, ThrottleOutPacketType.Land);
1214 } 1363 }
1215 catch (Exception e) 1364 catch (Exception e)
1216 { 1365 {
@@ -1218,36 +1367,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1218 } 1367 }
1219 } 1368 }
1220 1369
1221 /// <summary> 1370 // When a user edits the terrain, so much data is sent, the data queues up fast and presents a
1222 /// Munges heightfield into the LLUDP backed in restricted heightfield. 1371 // sub optimal editing experience. To alleviate this issue, when the user edits the terrain, we
1223 /// </summary> 1372 // start skipping the queues until they're done editing the terrain. We also make them
1224 /// <param name="map">float array in the base; Constants.RegionSize</param> 1373 // unreliable because it's extremely likely that multiple packets will be sent for a terrain patch
1225 /// <returns>float array in the base 256</returns> 1374 // area invalidating previous packets for that area.
1226 internal float[] LLHeightFieldMoronize(float[] map) 1375
1376 // It's possible for an editing user to flood themselves with edited packets but the majority
1377 // of use cases are such that only a tiny percentage of users will be editing the terrain.
1378 // Other, non-editing users will see the edits much slower.
1379
1380 // One last note on this topic, by the time users are going to be editing the terrain, it's
1381 // extremely likely that the sim will have rezzed already and therefore this is not likely going
1382 // to cause any additional issues with lost packets, objects or terrain patches.
1383
1384 // m_justEditedTerrain is volatile, so test once and duplicate two affected statements so we
1385 // only have one cache miss.
1386 private void SendTheLayerPacket(LayerDataPacket layerpack)
1227 { 1387 {
1228 if (map.Length == 65536) 1388 if (m_justEditedTerrain)
1229 return map; 1389 {
1390 layerpack.Header.Reliable = false;
1391 OutPacket(layerpack, ThrottleOutPacketType.Unknown );
1392 }
1230 else 1393 else
1231 { 1394 {
1232 float[] returnmap = new float[65536]; 1395 layerpack.Header.Reliable = true;
1233 1396 OutPacket(layerpack, ThrottleOutPacketType.Land);
1234 if (map.Length < 65535)
1235 {
1236 // rebase the vector stride to 256
1237 for (int i = 0; i < Constants.RegionSize; i++)
1238 Array.Copy(map, i * (int)Constants.RegionSize, returnmap, i * 256, (int)Constants.RegionSize);
1239 }
1240 else
1241 {
1242 for (int i = 0; i < 256; i++)
1243 Array.Copy(map, i * (int)Constants.RegionSize, returnmap, i * 256, 256);
1244 }
1245
1246 //Array.Copy(map,0,returnmap,0,(map.Length < 65536)? map.Length : 65536);
1247
1248 return returnmap;
1249 } 1397 }
1250
1251 } 1398 }
1252 1399
1253 /// <summary> 1400 /// <summary>
@@ -1256,7 +1403,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1256 /// <param name="windSpeeds">16x16 array of wind speeds</param> 1403 /// <param name="windSpeeds">16x16 array of wind speeds</param>
1257 public virtual void SendWindData(Vector2[] windSpeeds) 1404 public virtual void SendWindData(Vector2[] windSpeeds)
1258 { 1405 {
1259 Util.FireAndForget(DoSendWindData, windSpeeds); 1406 Util.FireAndForget(DoSendWindData, windSpeeds, "LLClientView.SendWindData");
1260 } 1407 }
1261 1408
1262 /// <summary> 1409 /// <summary>
@@ -1265,7 +1412,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1265 /// <param name="windSpeeds">16x16 array of cloud densities</param> 1412 /// <param name="windSpeeds">16x16 array of cloud densities</param>
1266 public virtual void SendCloudData(float[] cloudDensity) 1413 public virtual void SendCloudData(float[] cloudDensity)
1267 { 1414 {
1268 Util.FireAndForget(DoSendCloudData, cloudDensity); 1415 Util.FireAndForget(DoSendCloudData, cloudDensity, "LLClientView.SendCloudData");
1269 } 1416 }
1270 1417
1271 /// <summary> 1418 /// <summary>
@@ -1276,21 +1423,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1276 { 1423 {
1277 Vector2[] windSpeeds = (Vector2[])o; 1424 Vector2[] windSpeeds = (Vector2[])o;
1278 TerrainPatch[] patches = new TerrainPatch[2]; 1425 TerrainPatch[] patches = new TerrainPatch[2];
1279 patches[0] = new TerrainPatch(); 1426 patches[0] = new TerrainPatch { Data = new float[16 * 16] };
1280 patches[0].Data = new float[16 * 16]; 1427 patches[1] = new TerrainPatch { Data = new float[16 * 16] };
1281 patches[1] = new TerrainPatch();
1282 patches[1].Data = new float[16 * 16];
1283 1428
1284 for (int y = 0; y < 16; y++) 1429 for (int x = 0; x < 16 * 16; x++)
1285 { 1430 {
1286 for (int x = 0; x < 16; x++) 1431 patches[0].Data[x] = windSpeeds[x].X;
1287 { 1432 patches[1].Data[x] = windSpeeds[x].Y;
1288 patches[0].Data[y * 16 + x] = windSpeeds[y * 16 + x].X;
1289 patches[1].Data[y * 16 + x] = windSpeeds[y * 16 + x].Y;
1290 }
1291 } 1433 }
1292 1434
1293 LayerDataPacket layerpack = TerrainCompressor.CreateLayerDataPacket(patches, TerrainPatch.LayerType.Wind); 1435 byte layerType = (byte)TerrainPatch.LayerType.Wind;
1436 if (m_scene.RegionInfo.RegionSizeX > Constants.RegionSize || m_scene.RegionInfo.RegionSizeY > Constants.RegionSize)
1437 layerType = (byte)TerrainPatch.LayerType.WindExtended;
1438
1439 // LayerDataPacket layerpack = TerrainCompressor.CreateLayerDataPacket(patches, (TerrainPatch.LayerType)layerType);
1440 LayerDataPacket layerpack = OpenSimTerrainCompressor.CreateLayerDataPacket(patches, layerType,
1441 (int)m_scene.RegionInfo.RegionSizeX, (int)m_scene.RegionInfo.RegionSizeY);
1294 layerpack.Header.Zerocoded = true; 1442 layerpack.Header.Zerocoded = true;
1295 OutPacket(layerpack, ThrottleOutPacketType.Wind); 1443 OutPacket(layerpack, ThrottleOutPacketType.Wind);
1296 } 1444 }
@@ -1314,7 +1462,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1314 } 1462 }
1315 } 1463 }
1316 1464
1317 LayerDataPacket layerpack = TerrainCompressor.CreateLayerDataPacket(patches, TerrainPatch.LayerType.Cloud); 1465 byte layerType = (byte)TerrainPatch.LayerType.Cloud;
1466 if (m_scene.RegionInfo.RegionSizeX > Constants.RegionSize || m_scene.RegionInfo.RegionSizeY > Constants.RegionSize)
1467 layerType = (byte)TerrainPatch.LayerType.CloudExtended;
1468
1469 // LayerDataPacket layerpack = TerrainCompressor.CreateLayerDataPacket(patches, (TerrainPatch.LayerType)layerType);
1470 LayerDataPacket layerpack = OpenSimTerrainCompressor.CreateLayerDataPacket(patches, layerType,
1471 (int)m_scene.RegionInfo.RegionSizeX, (int)m_scene.RegionInfo.RegionSizeY);
1318 layerpack.Header.Zerocoded = true; 1472 layerpack.Header.Zerocoded = true;
1319 OutPacket(layerpack, ThrottleOutPacketType.Cloud); 1473 OutPacket(layerpack, ThrottleOutPacketType.Cloud);
1320 } 1474 }
@@ -1403,6 +1557,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1403 1557
1404 mapReply.AgentData.AgentID = AgentId; 1558 mapReply.AgentData.AgentID = AgentId;
1405 mapReply.Data = new MapBlockReplyPacket.DataBlock[mapBlocks2.Length]; 1559 mapReply.Data = new MapBlockReplyPacket.DataBlock[mapBlocks2.Length];
1560 mapReply.Size = new MapBlockReplyPacket.SizeBlock[mapBlocks2.Length];
1406 mapReply.AgentData.Flags = flag; 1561 mapReply.AgentData.Flags = flag;
1407 1562
1408 for (int i = 0; i < mapBlocks2.Length; i++) 1563 for (int i = 0; i < mapBlocks2.Length; i++)
@@ -1417,6 +1572,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1417 mapReply.Data[i].RegionFlags = mapBlocks2[i].RegionFlags; 1572 mapReply.Data[i].RegionFlags = mapBlocks2[i].RegionFlags;
1418 mapReply.Data[i].Access = mapBlocks2[i].Access; 1573 mapReply.Data[i].Access = mapBlocks2[i].Access;
1419 mapReply.Data[i].Agents = mapBlocks2[i].Agents; 1574 mapReply.Data[i].Agents = mapBlocks2[i].Agents;
1575
1576 mapReply.Size[i] = new MapBlockReplyPacket.SizeBlock();
1577 mapReply.Size[i].SizeX = mapBlocks2[i].SizeX;
1578 mapReply.Size[i].SizeY = mapBlocks2[i].SizeY;
1420 } 1579 }
1421 OutPacket(mapReply, ThrottleOutPacketType.Land); 1580 OutPacket(mapReply, ThrottleOutPacketType.Land);
1422 } 1581 }
@@ -1521,7 +1680,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1521 OutPacket(tpProgress, ThrottleOutPacketType.Unknown); 1680 OutPacket(tpProgress, ThrottleOutPacketType.Unknown);
1522 } 1681 }
1523 1682
1524 public void SendMoneyBalance(UUID transaction, bool success, byte[] description, int balance) 1683 public void SendMoneyBalance(UUID transaction, bool success, byte[] description, int balance, int transactionType, UUID sourceID, bool sourceIsGroup, UUID destID, bool destIsGroup, int amount, string item)
1525 { 1684 {
1526 MoneyBalanceReplyPacket money = (MoneyBalanceReplyPacket)PacketPool.Instance.GetPacket(PacketType.MoneyBalanceReply); 1685 MoneyBalanceReplyPacket money = (MoneyBalanceReplyPacket)PacketPool.Instance.GetPacket(PacketType.MoneyBalanceReply);
1527 money.MoneyData.AgentID = AgentId; 1686 money.MoneyData.AgentID = AgentId;
@@ -1529,7 +1688,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1529 money.MoneyData.TransactionSuccess = success; 1688 money.MoneyData.TransactionSuccess = success;
1530 money.MoneyData.Description = description; 1689 money.MoneyData.Description = description;
1531 money.MoneyData.MoneyBalance = balance; 1690 money.MoneyData.MoneyBalance = balance;
1532 money.TransactionInfo.ItemDescription = Util.StringToBytes256("NONE"); 1691 money.TransactionInfo.TransactionType = transactionType;
1692 money.TransactionInfo.SourceID = sourceID;
1693 money.TransactionInfo.IsSourceGroup = sourceIsGroup;
1694 money.TransactionInfo.DestID = destID;
1695 money.TransactionInfo.IsDestGroup = destIsGroup;
1696 money.TransactionInfo.Amount = amount;
1697 money.TransactionInfo.ItemDescription = Util.StringToBytes256(item);
1698
1533 OutPacket(money, ThrottleOutPacketType.Task); 1699 OutPacket(money, ThrottleOutPacketType.Task);
1534 } 1700 }
1535 1701
@@ -1571,7 +1737,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1571 OutPacket(pc, ThrottleOutPacketType.Unknown); 1737 OutPacket(pc, ThrottleOutPacketType.Unknown);
1572 } 1738 }
1573 1739
1574 public void SendKillObject(ulong regionHandle, List<uint> localIDs) 1740 public void SendKillObject(List<uint> localIDs)
1575 { 1741 {
1576// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, localID, regionHandle); 1742// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, localID, regionHandle);
1577 1743
@@ -1588,7 +1754,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1588 1754
1589 if (localIDs.Count == 1 && m_scene.GetScenePresence(localIDs[0]) != null) 1755 if (localIDs.Count == 1 && m_scene.GetScenePresence(localIDs[0]) != null)
1590 { 1756 {
1591 OutPacket(kill, ThrottleOutPacketType.State); 1757 OutPacket(kill, ThrottleOutPacketType.Task);
1592 } 1758 }
1593 else 1759 else
1594 { 1760 {
@@ -1700,6 +1866,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1700 newBlock.Name = Util.StringToBytes256(folder.Name); 1866 newBlock.Name = Util.StringToBytes256(folder.Name);
1701 newBlock.ParentID = folder.ParentID; 1867 newBlock.ParentID = folder.ParentID;
1702 newBlock.Type = (sbyte)folder.Type; 1868 newBlock.Type = (sbyte)folder.Type;
1869 //if (newBlock.Type == InventoryItemBase.SUITCASE_FOLDER_TYPE)
1870 // newBlock.Type = InventoryItemBase.SUITCASE_FOLDER_FAKE_TYPE;
1703 1871
1704 return newBlock; 1872 return newBlock;
1705 } 1873 }
@@ -1807,7 +1975,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1807 1975
1808 public void SendInventoryItemDetails(UUID ownerID, InventoryItemBase item) 1976 public void SendInventoryItemDetails(UUID ownerID, InventoryItemBase item)
1809 { 1977 {
1810 const uint FULL_MASK_PERMISSIONS = (uint)PermissionMask.All; 1978 // Fudge this value. It's only needed to make the CRC anyway
1979 const uint FULL_MASK_PERMISSIONS = (uint)0x7fffffff;
1811 1980
1812 FetchInventoryReplyPacket inventoryReply = (FetchInventoryReplyPacket)PacketPool.Instance.GetPacket(PacketType.FetchInventoryReply); 1981 FetchInventoryReplyPacket inventoryReply = (FetchInventoryReplyPacket)PacketPool.Instance.GetPacket(PacketType.FetchInventoryReply);
1813 // TODO: don't create new blocks if recycling an old packet 1982 // TODO: don't create new blocks if recycling an old packet
@@ -1948,8 +2117,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1948 2117
1949 folderBlock.FolderID = folder.ID; 2118 folderBlock.FolderID = folder.ID;
1950 folderBlock.ParentID = folder.ParentID; 2119 folderBlock.ParentID = folder.ParentID;
1951 //folderBlock.Type = -1;
1952 folderBlock.Type = (sbyte)folder.Type; 2120 folderBlock.Type = (sbyte)folder.Type;
2121 // Leaving this here for now, just in case we need to do this for a while
2122 //if (folderBlock.Type == InventoryItemBase.SUITCASE_FOLDER_TYPE)
2123 // folderBlock.Type = InventoryItemBase.SUITCASE_FOLDER_FAKE_TYPE;
1953 folderBlock.Name = Util.StringToBytes256(folder.Name); 2124 folderBlock.Name = Util.StringToBytes256(folder.Name);
1954 2125
1955 return folderBlock; 2126 return folderBlock;
@@ -2012,7 +2183,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2012 2183
2013 protected void SendBulkUpdateInventoryItem(InventoryItemBase item) 2184 protected void SendBulkUpdateInventoryItem(InventoryItemBase item)
2014 { 2185 {
2015 const uint FULL_MASK_PERMISSIONS = (uint)PermissionMask.All; 2186 const uint FULL_MASK_PERMISSIONS = (uint)0x7ffffff;
2016 2187
2017 BulkUpdateInventoryPacket bulkUpdate 2188 BulkUpdateInventoryPacket bulkUpdate
2018 = (BulkUpdateInventoryPacket)PacketPool.Instance.GetPacket(PacketType.BulkUpdateInventory); 2189 = (BulkUpdateInventoryPacket)PacketPool.Instance.GetPacket(PacketType.BulkUpdateInventory);
@@ -2066,7 +2237,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2066 /// <see>IClientAPI.SendInventoryItemCreateUpdate(InventoryItemBase)</see> 2237 /// <see>IClientAPI.SendInventoryItemCreateUpdate(InventoryItemBase)</see>
2067 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, uint callbackId) 2238 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, uint callbackId)
2068 { 2239 {
2069 const uint FULL_MASK_PERMISSIONS = (uint)PermissionMask.All; 2240 const uint FULL_MASK_PERMISSIONS = (uint)0x7fffffff;
2070 2241
2071 UpdateCreateInventoryItemPacket InventoryReply 2242 UpdateCreateInventoryItemPacket InventoryReply
2072 = (UpdateCreateInventoryItemPacket)PacketPool.Instance.GetPacket( 2243 = (UpdateCreateInventoryItemPacket)PacketPool.Instance.GetPacket(
@@ -2212,9 +2383,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2212 2383
2213 public void SendAgentDataUpdate(UUID agentid, UUID activegroupid, string firstname, string lastname, ulong grouppowers, string groupname, string grouptitle) 2384 public void SendAgentDataUpdate(UUID agentid, UUID activegroupid, string firstname, string lastname, ulong grouppowers, string groupname, string grouptitle)
2214 { 2385 {
2215 m_activeGroupID = activegroupid; 2386 if (agentid == AgentId)
2216 m_activeGroupName = groupname; 2387 {
2217 m_activeGroupPowers = grouppowers; 2388 ActiveGroupId = activegroupid;
2389 ActiveGroupName = groupname;
2390 ActiveGroupPowers = grouppowers;
2391 }
2218 2392
2219 AgentDataUpdatePacket sendAgentDataUpdate = (AgentDataUpdatePacket)PacketPool.Instance.GetPacket(PacketType.AgentDataUpdate); 2393 AgentDataUpdatePacket sendAgentDataUpdate = (AgentDataUpdatePacket)PacketPool.Instance.GetPacket(PacketType.AgentDataUpdate);
2220 sendAgentDataUpdate.AgentData.ActiveGroupID = activegroupid; 2394 sendAgentDataUpdate.AgentData.ActiveGroupID = activegroupid;
@@ -2261,6 +2435,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2261 /// <returns></returns> 2435 /// <returns></returns>
2262 public AgentAlertMessagePacket BuildAgentAlertPacket(string message, bool modal) 2436 public AgentAlertMessagePacket BuildAgentAlertPacket(string message, bool modal)
2263 { 2437 {
2438 // Prepend a slash to make the message come up in the top right
2439 // again.
2440 // Allow special formats to be sent from aware modules.
2441 if (!modal && !message.StartsWith("ALERT: ") && !message.StartsWith("NOTIFY: ") && message != "Home position set." && message != "You died and have been teleported to your home location")
2442 message = "/" + message;
2264 AgentAlertMessagePacket alertPack = (AgentAlertMessagePacket)PacketPool.Instance.GetPacket(PacketType.AgentAlertMessage); 2443 AgentAlertMessagePacket alertPack = (AgentAlertMessagePacket)PacketPool.Instance.GetPacket(PacketType.AgentAlertMessage);
2265 alertPack.AgentData.AgentID = AgentId; 2444 alertPack.AgentData.AgentID = AgentId;
2266 alertPack.AlertData.Message = Util.StringToBytes256(message); 2445 alertPack.AlertData.Message = Util.StringToBytes256(message);
@@ -2556,11 +2735,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2556 { 2735 {
2557 AvatarSitResponsePacket avatarSitResponse = new AvatarSitResponsePacket(); 2736 AvatarSitResponsePacket avatarSitResponse = new AvatarSitResponsePacket();
2558 avatarSitResponse.SitObject.ID = TargetID; 2737 avatarSitResponse.SitObject.ID = TargetID;
2559 if (CameraAtOffset != Vector3.Zero) 2738 avatarSitResponse.SitTransform.CameraAtOffset = CameraAtOffset;
2560 { 2739 avatarSitResponse.SitTransform.CameraEyeOffset = CameraEyeOffset;
2561 avatarSitResponse.SitTransform.CameraAtOffset = CameraAtOffset;
2562 avatarSitResponse.SitTransform.CameraEyeOffset = CameraEyeOffset;
2563 }
2564 avatarSitResponse.SitTransform.ForceMouselook = ForceMouseLook; 2740 avatarSitResponse.SitTransform.ForceMouselook = ForceMouseLook;
2565 avatarSitResponse.SitTransform.AutoPilot = autopilot; 2741 avatarSitResponse.SitTransform.AutoPilot = autopilot;
2566 avatarSitResponse.SitTransform.SitPosition = OffsetPos; 2742 avatarSitResponse.SitTransform.SitPosition = OffsetPos;
@@ -2627,6 +2803,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2627 } 2803 }
2628 } 2804 }
2629 2805
2806 public void SendPartPhysicsProprieties(ISceneEntity entity)
2807 {
2808 SceneObjectPart part = (SceneObjectPart)entity;
2809 if (part != null && AgentId != UUID.Zero)
2810 {
2811 try
2812 {
2813 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>();
2814 if (eq != null)
2815 {
2816 uint localid = part.LocalId;
2817 byte physshapetype = part.PhysicsShapeType;
2818 float density = part.Density;
2819 float friction = part.Friction;
2820 float bounce = part.Restitution;
2821 float gravmod = part.GravityModifier;
2822 eq.partPhysicsProperties(localid, physshapetype, density, friction, bounce, gravmod,AgentId);
2823 }
2824 }
2825 catch (Exception ex)
2826 {
2827 m_log.Error("Unable to send part Physics Proprieties - exception: " + ex.ToString());
2828 }
2829 part.UpdatePhysRequired = false;
2830 }
2831 }
2832
2833
2630 2834
2631 public void SendGroupNameReply(UUID groupLLUID, string GroupName) 2835 public void SendGroupNameReply(UUID groupLLUID, string GroupName)
2632 { 2836 {
@@ -2681,8 +2885,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2681 { 2885 {
2682 if (req.AssetInf.Data == null) 2886 if (req.AssetInf.Data == null)
2683 { 2887 {
2684 m_log.ErrorFormat("Cannot send asset {0} ({1}), asset data is null", 2888 m_log.ErrorFormat("{0} Cannot send asset {1} ({2}), asset data is null",
2685 req.AssetInf.ID, req.AssetInf.Metadata.ContentType); 2889 LogHeader, req.AssetInf.ID, req.AssetInf.Metadata.ContentType);
2686 return; 2890 return;
2687 } 2891 }
2688 2892
@@ -3530,7 +3734,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3530 3734
3531 AvatarAppearancePacket avp = (AvatarAppearancePacket)PacketPool.Instance.GetPacket(PacketType.AvatarAppearance); 3735 AvatarAppearancePacket avp = (AvatarAppearancePacket)PacketPool.Instance.GetPacket(PacketType.AvatarAppearance);
3532 // TODO: don't create new blocks if recycling an old packet 3736 // TODO: don't create new blocks if recycling an old packet
3533 avp.VisualParam = new AvatarAppearancePacket.VisualParamBlock[218]; 3737 avp.VisualParam = new AvatarAppearancePacket.VisualParamBlock[visualParams.Length];
3534 avp.ObjectData.TextureEntry = textureEntry; 3738 avp.ObjectData.TextureEntry = textureEntry;
3535 3739
3536 AvatarAppearancePacket.VisualParamBlock avblock = null; 3740 AvatarAppearancePacket.VisualParamBlock avblock = null;
@@ -3543,6 +3747,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3543 3747
3544 avp.Sender.IsTrial = false; 3748 avp.Sender.IsTrial = false;
3545 avp.Sender.ID = agentID; 3749 avp.Sender.ID = agentID;
3750 avp.AppearanceData = new AvatarAppearancePacket.AppearanceDataBlock[0];
3751 avp.AppearanceHover = new AvatarAppearancePacket.AppearanceHoverBlock[0];
3546 //m_log.DebugFormat("[CLIENT]: Sending appearance for {0} to {1}", agentID.ToString(), AgentId.ToString()); 3752 //m_log.DebugFormat("[CLIENT]: Sending appearance for {0} to {1}", agentID.ToString(), AgentId.ToString());
3547 OutPacket(avp, ThrottleOutPacketType.Task); 3753 OutPacket(avp, ThrottleOutPacketType.Task);
3548 } 3754 }
@@ -3660,11 +3866,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3660 /// </summary> 3866 /// </summary>
3661 public void SendEntityUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags) 3867 public void SendEntityUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags)
3662 { 3868 {
3663 //double priority = m_prioritizer.GetUpdatePriority(this, entity); 3869 if (entity.UUID == m_agentId && !updateFlags.HasFlag(PrimUpdateFlags.FullUpdate))
3664 uint priority = m_prioritizer.GetUpdatePriority(this, entity); 3870 {
3871 ImprovedTerseObjectUpdatePacket packet
3872 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate);
3665 3873
3666 lock (m_entityUpdates.SyncRoot) 3874 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3667 m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation)); 3875 packet.RegionData.TimeDilation = Utils.FloatToUInt16(1, 0.0f, 1.0f);
3876 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1];
3877 packet.ObjectData[0] = CreateImprovedTerseBlock(entity, false);
3878 OutPacket(packet, ThrottleOutPacketType.Unknown, true);
3879 }
3880 else
3881 {
3882 //double priority = m_prioritizer.GetUpdatePriority(this, entity);
3883 uint priority = m_prioritizer.GetUpdatePriority(this, entity);
3884
3885 lock (m_entityUpdates.SyncRoot)
3886 m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation));
3887 }
3668 } 3888 }
3669 3889
3670 /// <summary> 3890 /// <summary>
@@ -3699,12 +3919,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3699 m_udpClient.NeedAcks.Remove(oPacket.SequenceNumber); 3919 m_udpClient.NeedAcks.Remove(oPacket.SequenceNumber);
3700 3920
3701 // Count this as a resent packet since we are going to requeue all of the updates contained in it 3921 // Count this as a resent packet since we are going to requeue all of the updates contained in it
3702 Interlocked.Increment(ref m_udpClient.PacketsResent); 3922 Interlocked.Increment(ref m_udpClient.PacketsResent);
3923
3924 // We're not going to worry about interlock yet since its not currently critical that this total count
3925 // is 100% correct
3926 m_udpServer.PacketsResentCount++;
3703 3927
3704 foreach (EntityUpdate update in updates) 3928 foreach (EntityUpdate update in updates)
3705 ResendPrimUpdate(update); 3929 ResendPrimUpdate(update);
3706 } 3930 }
3707 3931
3932// OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>();
3933// OpenSim.Framework.Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>> compressedUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>>();
3934// OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();
3935// OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();
3936//
3937// OpenSim.Framework.Lazy<List<EntityUpdate>> objectUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3938// OpenSim.Framework.Lazy<List<EntityUpdate>> compressedUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3939// OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3940// OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3941
3942
3708 private void ProcessEntityUpdates(int maxUpdates) 3943 private void ProcessEntityUpdates(int maxUpdates)
3709 { 3944 {
3710 OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>(); 3945 OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>();
@@ -3717,6 +3952,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3717 OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); 3952 OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3718 OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); 3953 OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3719 3954
3955// objectUpdateBlocks.Value.Clear();
3956// compressedUpdateBlocks.Value.Clear();
3957// terseUpdateBlocks.Value.Clear();
3958// terseAgentUpdateBlocks.Value.Clear();
3959// objectUpdates.Value.Clear();
3960// compressedUpdates.Value.Clear();
3961// terseUpdates.Value.Clear();
3962// terseAgentUpdates.Value.Clear();
3963
3720 // Check to see if this is a flush 3964 // Check to see if this is a flush
3721 if (maxUpdates <= 0) 3965 if (maxUpdates <= 0)
3722 { 3966 {
@@ -3774,6 +4018,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3774 part.Shape.LightEntry = false; 4018 part.Shape.LightEntry = false;
3775 } 4019 }
3776 } 4020 }
4021
4022 if (part.Shape != null && (part.Shape.SculptType == (byte)SculptType.Mesh))
4023 {
4024 // Ensure that mesh has at least 8 valid faces
4025 part.Shape.ProfileBegin = 12500;
4026 part.Shape.ProfileEnd = 0;
4027 part.Shape.ProfileHollow = 27500;
4028 }
3777 } 4029 }
3778 4030
3779 #region UpdateFlags to packet type conversion 4031 #region UpdateFlags to packet type conversion
@@ -3995,6 +4247,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3995 } 4247 }
3996 } 4248 }
3997 4249
4250// m_log.DebugFormat(
4251// "[LLCLIENTVIEW]: Sent {0} updates in ProcessEntityUpdates() for {1} {2} in {3}",
4252// updatesThisCall, Name, SceneAgent.IsChildAgent ? "child" : "root", Scene.Name);
4253//
3998 #endregion Packet Sending 4254 #endregion Packet Sending
3999 } 4255 }
4000 4256
@@ -4034,8 +4290,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4034 4290
4035 void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories) 4291 void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories)
4036 { 4292 {
4293// if (!m_udpServer.IsRunningOutbound)
4294// return;
4295
4037 if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) 4296 if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
4038 { 4297 {
4298// if (!m_udpServer.IsRunningOutbound)
4299// return;
4300
4039 if (m_maxUpdates == 0 || m_LastQueueFill == 0) 4301 if (m_maxUpdates == 0 || m_LastQueueFill == 0)
4040 { 4302 {
4041 m_maxUpdates = m_udpServer.PrimUpdatesPerCallback; 4303 m_maxUpdates = m_udpServer.PrimUpdatesPerCallback;
@@ -4061,6 +4323,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4061 ImageManager.ProcessImageQueue(m_udpServer.TextureSendLimit); 4323 ImageManager.ProcessImageQueue(m_udpServer.TextureSendLimit);
4062 } 4324 }
4063 4325
4326 internal bool HandleHasUpdates(ThrottleOutPacketTypeFlags categories)
4327 {
4328 bool hasUpdates = false;
4329
4330 if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
4331 {
4332 if (m_entityUpdates.Count > 0)
4333 hasUpdates = true;
4334 else if (m_entityProps.Count > 0)
4335 hasUpdates = true;
4336 }
4337
4338 if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0)
4339 {
4340 if (ImageManager.HasUpdates())
4341 hasUpdates = true;
4342 }
4343
4344 return hasUpdates;
4345 }
4346
4064 public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID) 4347 public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID)
4065 { 4348 {
4066 AssetUploadCompletePacket newPack = new AssetUploadCompletePacket(); 4349 AssetUploadCompletePacket newPack = new AssetUploadCompletePacket();
@@ -4156,7 +4439,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4156 pack.Stat = stats.StatsBlock; 4439 pack.Stat = stats.StatsBlock;
4157 4440
4158 pack.Header.Reliable = false; 4441 pack.Header.Reliable = false;
4159 4442 pack.RegionInfo = new SimStatsPacket.RegionInfoBlock[0];
4160 OutPacket(pack, ThrottleOutPacketType.Task); 4443 OutPacket(pack, ThrottleOutPacketType.Task);
4161 } 4444 }
4162 4445
@@ -4206,6 +4489,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4206 // Count this as a resent packet since we are going to requeue all of the updates contained in it 4489 // Count this as a resent packet since we are going to requeue all of the updates contained in it
4207 Interlocked.Increment(ref m_udpClient.PacketsResent); 4490 Interlocked.Increment(ref m_udpClient.PacketsResent);
4208 4491
4492 // We're not going to worry about interlock yet since its not currently critical that this total count
4493 // is 100% correct
4494 m_udpServer.PacketsResentCount++;
4495
4209 foreach (ObjectPropertyUpdate update in updates) 4496 foreach (ObjectPropertyUpdate update in updates)
4210 ResendPropertyUpdate(update); 4497 ResendPropertyUpdate(update);
4211 } 4498 }
@@ -4389,6 +4676,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4389 SceneObjectPart root = sop.ParentGroup.RootPart; 4676 SceneObjectPart root = sop.ParentGroup.RootPart;
4390 4677
4391 block.TouchName = Util.StringToBytes256(root.TouchName); 4678 block.TouchName = Util.StringToBytes256(root.TouchName);
4679
4680 // SL 3.3.4, at least, appears to read this information as a concatenated byte[] stream of UUIDs but
4681 // it's not yet clear whether this is actually used. If this is done in the future then a pre-cached
4682 // copy is really needed since it's less efficient to be constantly recreating this byte array.
4683// using (MemoryStream memStream = new MemoryStream())
4684// {
4685// using (BinaryWriter binWriter = new BinaryWriter(memStream))
4686// {
4687// for (int i = 0; i < sop.GetNumberOfSides(); i++)
4688// {
4689// Primitive.TextureEntryFace teFace = sop.Shape.Textures.FaceTextures[i];
4690//
4691// UUID textureID;
4692//
4693// if (teFace != null)
4694// textureID = teFace.TextureID;
4695// else
4696// textureID = sop.Shape.Textures.DefaultTexture.TextureID;
4697//
4698// binWriter.Write(textureID.GetBytes());
4699// }
4700//
4701// block.TextureID = memStream.ToArray();
4702// }
4703// }
4704
4392 block.TextureID = new byte[0]; // TextureID ??? 4705 block.TextureID = new byte[0]; // TextureID ???
4393 block.SitName = Util.StringToBytes256(root.SitName); 4706 block.SitName = Util.StringToBytes256(root.SitName);
4394 block.OwnerMask = root.OwnerMask; 4707 block.OwnerMask = root.OwnerMask;
@@ -4543,7 +4856,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4543 rinfopack.AgentData = new RegionInfoPacket.AgentDataBlock(); 4856 rinfopack.AgentData = new RegionInfoPacket.AgentDataBlock();
4544 rinfopack.AgentData.AgentID = AgentId; 4857 rinfopack.AgentData.AgentID = AgentId;
4545 rinfopack.AgentData.SessionID = SessionId; 4858 rinfopack.AgentData.SessionID = SessionId;
4546 4859 rinfopack.RegionInfo3 = new RegionInfoPacket.RegionInfo3Block[0];
4547 4860
4548 OutPacket(rinfopack, ThrottleOutPacketType.Task); 4861 OutPacket(rinfopack, ThrottleOutPacketType.Task);
4549 } 4862 }
@@ -4764,7 +5077,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4764 5077
4765 public void SendForceClientSelectObjects(List<uint> ObjectIDs) 5078 public void SendForceClientSelectObjects(List<uint> ObjectIDs)
4766 { 5079 {
4767 m_log.WarnFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count); 5080// m_log.DebugFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count);
4768 5081
4769 bool firstCall = true; 5082 bool firstCall = true;
4770 const int MAX_OBJECTS_PER_PACKET = 251; 5083 const int MAX_OBJECTS_PER_PACKET = 251;
@@ -4882,7 +5195,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4882 { 5195 {
4883 ScenePresence presence = (ScenePresence)entity; 5196 ScenePresence presence = (ScenePresence)entity;
4884 5197
4885 attachPoint = 0; 5198// m_log.DebugFormat(
5199// "[LLCLIENTVIEW]: Sending terse update to {0} with pos {1}, vel {2} in {3}",
5200// Name, presence.OffsetPosition, presence.Velocity, m_scene.Name);
5201
5202 attachPoint = presence.State;
4886 collisionPlane = presence.CollisionPlane; 5203 collisionPlane = presence.CollisionPlane;
4887 position = presence.OffsetPosition; 5204 position = presence.OffsetPosition;
4888 velocity = presence.Velocity; 5205 velocity = presence.Velocity;
@@ -4893,9 +5210,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4893 // may improve movement smoothness. 5210 // may improve movement smoothness.
4894// acceleration = new Vector3(1, 0, 0); 5211// acceleration = new Vector3(1, 0, 0);
4895 5212
4896 angularVelocity = Vector3.Zero; 5213 angularVelocity = presence.AngularVelocity;
5214
5215 // Whilst not in mouselook, an avatar will transmit only the Z rotation as this is the only axis
5216 // it rotates around.
5217 // In mouselook, X and Y co-ordinate will also be sent but when used in Rotation, these cause unwanted
5218 // excessive up and down movements of the camera when looking up and down.
5219 // See http://opensimulator.org/mantis/view.php?id=3274
5220 // This does not affect head movement, since this is controlled entirely by camera movement rather than
5221 // body rotation. We still need to transmit X and Y for sitting avatars but mouselook does not change
5222 // the rotation in this case.
4897 rotation = presence.Rotation; 5223 rotation = presence.Rotation;
4898 5224
5225 if (!presence.IsSatOnObject)
5226 {
5227 rotation.X = 0;
5228 rotation.Y = 0;
5229 }
5230
4899 if (sendTexture) 5231 if (sendTexture)
4900 textureEntry = presence.Appearance.Texture.GetBytes(); 5232 textureEntry = presence.Appearance.Texture.GetBytes();
4901 else 5233 else
@@ -4906,7 +5238,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4906 SceneObjectPart part = (SceneObjectPart)entity; 5238 SceneObjectPart part = (SceneObjectPart)entity;
4907 5239
4908 attachPoint = part.ParentGroup.AttachmentPoint; 5240 attachPoint = part.ParentGroup.AttachmentPoint;
4909 5241 attachPoint = ((attachPoint % 16) * 16 + (attachPoint / 16));
4910// m_log.DebugFormat( 5242// m_log.DebugFormat(
4911// "[LLCLIENTVIEW]: Sending attachPoint {0} for {1} {2} to {3}", 5243// "[LLCLIENTVIEW]: Sending attachPoint {0} for {1} {2} to {3}",
4912// attachPoint, part.Name, part.LocalId, Name); 5244// attachPoint, part.Name, part.LocalId, Name);
@@ -4934,7 +5266,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4934 pos += 4; 5266 pos += 4;
4935 5267
4936 // Avatar/CollisionPlane 5268 // Avatar/CollisionPlane
4937 data[pos++] = (byte)((attachPoint % 16) * 16 + (attachPoint / 16)); ; 5269 data[pos++] = (byte) attachPoint;
4938 if (avatar) 5270 if (avatar)
4939 { 5271 {
4940 data[pos++] = 1; 5272 data[pos++] = 1;
@@ -5001,13 +5333,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5001 5333
5002 protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(ScenePresence data) 5334 protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(ScenePresence data)
5003 { 5335 {
5336// m_log.DebugFormat(
5337// "[LLCLIENTVIEW]: Sending full update to {0} with pos {1}, vel {2} in {3}", Name, data.OffsetPosition, data.Velocity, m_scene.Name);
5338
5004 byte[] objectData = new byte[76]; 5339 byte[] objectData = new byte[76];
5005 5340
5006 data.CollisionPlane.ToBytes(objectData, 0); 5341 data.CollisionPlane.ToBytes(objectData, 0);
5007 data.OffsetPosition.ToBytes(objectData, 16); 5342 data.OffsetPosition.ToBytes(objectData, 16);
5008// data.Velocity.ToBytes(objectData, 28); 5343 data.Velocity.ToBytes(objectData, 28);
5009// data.Acceleration.ToBytes(objectData, 40); 5344// data.Acceleration.ToBytes(objectData, 40);
5010 data.Rotation.ToBytes(objectData, 52); 5345
5346 // Whilst not in mouselook, an avatar will transmit only the Z rotation as this is the only axis
5347 // it rotates around.
5348 // In mouselook, X and Y co-ordinate will also be sent but when used in Rotation, these cause unwanted
5349 // excessive up and down movements of the camera when looking up and down.
5350 // See http://opensimulator.org/mantis/view.php?id=3274
5351 // This does not affect head movement, since this is controlled entirely by camera movement rather than
5352 // body rotation. We still need to transmit X and Y for sitting avatars but mouselook does not change
5353 // the rotation in this case.
5354 Quaternion rot = data.Rotation;
5355
5356 if (!data.IsSatOnObject)
5357 {
5358 rot.X = 0;
5359 rot.Y = 0;
5360 }
5361
5362 rot.ToBytes(objectData, 52);
5011 //data.AngularVelocity.ToBytes(objectData, 64); 5363 //data.AngularVelocity.ToBytes(objectData, 64);
5012 5364
5013 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); 5365 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock();
@@ -5021,7 +5373,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5021 update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " + 5373 update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " +
5022 data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle); 5374 data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle);
5023 update.ObjectData = objectData; 5375 update.ObjectData = objectData;
5024 update.ParentID = data.ParentID; 5376
5377 SceneObjectPart parentPart = data.ParentPart;
5378 if (parentPart != null)
5379 update.ParentID = parentPart.ParentGroup.LocalId;
5380 else
5381 update.ParentID = 0;
5382
5025 update.PathCurve = 16; 5383 update.PathCurve = 16;
5026 update.PathScaleX = 100; 5384 update.PathScaleX = 100;
5027 update.PathScaleY = 100; 5385 update.PathScaleY = 100;
@@ -5075,10 +5433,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5075 //update.JointType = 0; 5433 //update.JointType = 0;
5076 update.Material = data.Material; 5434 update.Material = data.Material;
5077 update.MediaURL = Utils.EmptyBytes; // FIXME: Support this in OpenSim 5435 update.MediaURL = Utils.EmptyBytes; // FIXME: Support this in OpenSim
5436
5078 if (data.ParentGroup.IsAttachment) 5437 if (data.ParentGroup.IsAttachment)
5079 { 5438 {
5080 update.NameValue = Util.StringToBytes256("AttachItemID STRING RW SV " + data.ParentGroup.FromItemID); 5439 update.NameValue
5440 = Util.StringToBytes256(
5441 string.Format("AttachItemID STRING RW SV {0}", data.ParentGroup.FromItemID));
5442
5081 update.State = (byte)((data.ParentGroup.AttachmentPoint % 16) * 16 + (data.ParentGroup.AttachmentPoint / 16)); 5443 update.State = (byte)((data.ParentGroup.AttachmentPoint % 16) * 16 + (data.ParentGroup.AttachmentPoint / 16));
5444
5445// m_log.DebugFormat(
5446// "[LLCLIENTVIEW]: Sending NameValue {0} for {1} {2} to {3}",
5447// Util.UTF8.GetString(update.NameValue), data.Name, data.LocalId, Name);
5448//
5449// m_log.DebugFormat(
5450// "[LLCLIENTVIEW]: Sending state {0} for {1} {2} to {3}",
5451// update.State, data.Name, data.LocalId, Name);
5082 } 5452 }
5083 else 5453 else
5084 { 5454 {
@@ -5089,10 +5459,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5089 update.State = data.ParentGroup.RootPart.Shape.State; 5459 update.State = data.ParentGroup.RootPart.Shape.State;
5090 } 5460 }
5091 5461
5092// m_log.DebugFormat(
5093// "[LLCLIENTVIEW]: Sending state {0} for {1} {2} to {3}",
5094// update.State, data.Name, data.LocalId, Name);
5095
5096 update.ObjectData = objectData; 5462 update.ObjectData = objectData;
5097 update.ParentID = data.ParentID; 5463 update.ParentID = data.ParentID;
5098 update.PathBegin = data.Shape.PathBegin; 5464 update.PathBegin = data.Shape.PathBegin;
@@ -5192,8 +5558,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5192 5558
5193 public ulong GetGroupPowers(UUID groupID) 5559 public ulong GetGroupPowers(UUID groupID)
5194 { 5560 {
5195 if (groupID == m_activeGroupID) 5561 if (groupID == ActiveGroupId)
5196 return m_activeGroupPowers; 5562 return ActiveGroupPowers;
5197 5563
5198 if (m_groupPowers.ContainsKey(groupID)) 5564 if (m_groupPowers.ContainsKey(groupID))
5199 return m_groupPowers[groupID]; 5565 return m_groupPowers[groupID];
@@ -5221,10 +5587,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5221 AddLocalPacketHandler(PacketType.ParcelBuy, HandleParcelBuyRequest, false); 5587 AddLocalPacketHandler(PacketType.ParcelBuy, HandleParcelBuyRequest, false);
5222 AddLocalPacketHandler(PacketType.UUIDGroupNameRequest, HandleUUIDGroupNameRequest); 5588 AddLocalPacketHandler(PacketType.UUIDGroupNameRequest, HandleUUIDGroupNameRequest);
5223 AddLocalPacketHandler(PacketType.ObjectGroup, HandleObjectGroupRequest); 5589 AddLocalPacketHandler(PacketType.ObjectGroup, HandleObjectGroupRequest);
5224 AddLocalPacketHandler(PacketType.GenericMessage, HandleGenericMessage); 5590 AddLocalPacketHandler(PacketType.GenericMessage, HandleGenericMessage, true, true);
5225 AddLocalPacketHandler(PacketType.AvatarPropertiesRequest, HandleAvatarPropertiesRequest); 5591 AddLocalPacketHandler(PacketType.AvatarPropertiesRequest, HandleAvatarPropertiesRequest, true, true);
5226 AddLocalPacketHandler(PacketType.ChatFromViewer, HandleChatFromViewer); 5592 AddLocalPacketHandler(PacketType.ChatFromViewer, HandleChatFromViewer);
5227 AddLocalPacketHandler(PacketType.AvatarPropertiesUpdate, HandlerAvatarPropertiesUpdate); 5593 AddLocalPacketHandler(PacketType.AvatarPropertiesUpdate, HandlerAvatarPropertiesUpdate, true, true);
5228 AddLocalPacketHandler(PacketType.ScriptDialogReply, HandlerScriptDialogReply); 5594 AddLocalPacketHandler(PacketType.ScriptDialogReply, HandlerScriptDialogReply);
5229 AddLocalPacketHandler(PacketType.ImprovedInstantMessage, HandlerImprovedInstantMessage); 5595 AddLocalPacketHandler(PacketType.ImprovedInstantMessage, HandlerImprovedInstantMessage);
5230 AddLocalPacketHandler(PacketType.AcceptFriendship, HandlerAcceptFriendship); 5596 AddLocalPacketHandler(PacketType.AcceptFriendship, HandlerAcceptFriendship);
@@ -5233,7 +5599,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5233 AddLocalPacketHandler(PacketType.RezObject, HandlerRezObject); 5599 AddLocalPacketHandler(PacketType.RezObject, HandlerRezObject);
5234 AddLocalPacketHandler(PacketType.DeRezObject, HandlerDeRezObject); 5600 AddLocalPacketHandler(PacketType.DeRezObject, HandlerDeRezObject);
5235 AddLocalPacketHandler(PacketType.ModifyLand, HandlerModifyLand); 5601 AddLocalPacketHandler(PacketType.ModifyLand, HandlerModifyLand);
5236 AddLocalPacketHandler(PacketType.RegionHandshakeReply, HandlerRegionHandshakeReply); 5602 AddLocalPacketHandler(PacketType.RegionHandshakeReply, HandlerRegionHandshakeReply, false);
5237 AddLocalPacketHandler(PacketType.AgentWearablesRequest, HandlerAgentWearablesRequest); 5603 AddLocalPacketHandler(PacketType.AgentWearablesRequest, HandlerAgentWearablesRequest);
5238 AddLocalPacketHandler(PacketType.AgentSetAppearance, HandlerAgentSetAppearance); 5604 AddLocalPacketHandler(PacketType.AgentSetAppearance, HandlerAgentSetAppearance);
5239 AddLocalPacketHandler(PacketType.AgentIsNowWearing, HandlerAgentIsNowWearing); 5605 AddLocalPacketHandler(PacketType.AgentIsNowWearing, HandlerAgentIsNowWearing);
@@ -5294,8 +5660,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5294 AddLocalPacketHandler(PacketType.ScriptAnswerYes, HandleScriptAnswerYes, false); 5660 AddLocalPacketHandler(PacketType.ScriptAnswerYes, HandleScriptAnswerYes, false);
5295 AddLocalPacketHandler(PacketType.ObjectClickAction, HandleObjectClickAction, false); 5661 AddLocalPacketHandler(PacketType.ObjectClickAction, HandleObjectClickAction, false);
5296 AddLocalPacketHandler(PacketType.ObjectMaterial, HandleObjectMaterial, false); 5662 AddLocalPacketHandler(PacketType.ObjectMaterial, HandleObjectMaterial, false);
5297 AddLocalPacketHandler(PacketType.RequestImage, HandleRequestImage); 5663 AddLocalPacketHandler(PacketType.RequestImage, HandleRequestImage, false);
5298 AddLocalPacketHandler(PacketType.TransferRequest, HandleTransferRequest); 5664 AddLocalPacketHandler(PacketType.TransferRequest, HandleTransferRequest, false);
5299 AddLocalPacketHandler(PacketType.AssetUploadRequest, HandleAssetUploadRequest); 5665 AddLocalPacketHandler(PacketType.AssetUploadRequest, HandleAssetUploadRequest);
5300 AddLocalPacketHandler(PacketType.RequestXfer, HandleRequestXfer); 5666 AddLocalPacketHandler(PacketType.RequestXfer, HandleRequestXfer);
5301 AddLocalPacketHandler(PacketType.SendXferPacket, HandleSendXferPacket); 5667 AddLocalPacketHandler(PacketType.SendXferPacket, HandleSendXferPacket);
@@ -5327,7 +5693,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5327 AddLocalPacketHandler(PacketType.TeleportCancel, HandleTeleportCancel); 5693 AddLocalPacketHandler(PacketType.TeleportCancel, HandleTeleportCancel);
5328 AddLocalPacketHandler(PacketType.TeleportLocationRequest, HandleTeleportLocationRequest); 5694 AddLocalPacketHandler(PacketType.TeleportLocationRequest, HandleTeleportLocationRequest);
5329 AddLocalPacketHandler(PacketType.UUIDNameRequest, HandleUUIDNameRequest, false); 5695 AddLocalPacketHandler(PacketType.UUIDNameRequest, HandleUUIDNameRequest, false);
5330 AddLocalPacketHandler(PacketType.RegionHandleRequest, HandleRegionHandleRequest); 5696 AddLocalPacketHandler(PacketType.RegionHandleRequest, HandleRegionHandleRequest, false);
5331 AddLocalPacketHandler(PacketType.ParcelInfoRequest, HandleParcelInfoRequest); 5697 AddLocalPacketHandler(PacketType.ParcelInfoRequest, HandleParcelInfoRequest);
5332 AddLocalPacketHandler(PacketType.ParcelAccessListRequest, HandleParcelAccessListRequest, false); 5698 AddLocalPacketHandler(PacketType.ParcelAccessListRequest, HandleParcelAccessListRequest, false);
5333 AddLocalPacketHandler(PacketType.ParcelAccessListUpdate, HandleParcelAccessListUpdate, false); 5699 AddLocalPacketHandler(PacketType.ParcelAccessListUpdate, HandleParcelAccessListUpdate, false);
@@ -5409,8 +5775,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5409 AddLocalPacketHandler(PacketType.PickDelete, HandlePickDelete); 5775 AddLocalPacketHandler(PacketType.PickDelete, HandlePickDelete);
5410 AddLocalPacketHandler(PacketType.PickGodDelete, HandlePickGodDelete); 5776 AddLocalPacketHandler(PacketType.PickGodDelete, HandlePickGodDelete);
5411 AddLocalPacketHandler(PacketType.PickInfoUpdate, HandlePickInfoUpdate); 5777 AddLocalPacketHandler(PacketType.PickInfoUpdate, HandlePickInfoUpdate);
5412 AddLocalPacketHandler(PacketType.AvatarNotesUpdate, HandleAvatarNotesUpdate); 5778 AddLocalPacketHandler(PacketType.AvatarNotesUpdate, HandleAvatarNotesUpdate, true, true);
5413 AddLocalPacketHandler(PacketType.AvatarInterestsUpdate, HandleAvatarInterestsUpdate); 5779 AddLocalPacketHandler(PacketType.AvatarInterestsUpdate, HandleAvatarInterestsUpdate, true, true);
5414 AddLocalPacketHandler(PacketType.GrantUserRights, HandleGrantUserRights); 5780 AddLocalPacketHandler(PacketType.GrantUserRights, HandleGrantUserRights);
5415 AddLocalPacketHandler(PacketType.PlacesQuery, HandlePlacesQuery); 5781 AddLocalPacketHandler(PacketType.PlacesQuery, HandlePlacesQuery);
5416 AddLocalPacketHandler(PacketType.UpdateMuteListEntry, HandleUpdateMuteListEntry); 5782 AddLocalPacketHandler(PacketType.UpdateMuteListEntry, HandleUpdateMuteListEntry);
@@ -5438,82 +5804,137 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5438 5804
5439 #region Packet Handlers 5805 #region Packet Handlers
5440 5806
5807 public int TotalAgentUpdates { get; set; }
5808
5441 #region Scene/Avatar 5809 #region Scene/Avatar
5442 5810
5443 private bool HandleAgentUpdate(IClientAPI sener, Packet packet) 5811 // Threshold for body rotation to be a significant agent update
5812 private const float QDELTA = 0.000001f;
5813 // Threshold for camera rotation to be a significant agent update
5814 private const float VDELTA = 0.01f;
5815
5816 /// <summary>
5817 /// This checks the update significance against the last update made.
5818 /// </summary>
5819 /// <remarks>Can only be called by one thread at a time</remarks>
5820 /// <returns></returns>
5821 /// <param name='x'></param>
5822 public bool CheckAgentUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
5444 { 5823 {
5445 if (OnAgentUpdate != null) 5824 return CheckAgentMovementUpdateSignificance(x) || CheckAgentCameraUpdateSignificance(x);
5446 { 5825 }
5447 AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
5448 5826
5449 #region Packet Session and User Check 5827 /// <summary>
5450 if (agentUpdate.AgentData.SessionID != SessionId || agentUpdate.AgentData.AgentID != AgentId) 5828 /// This checks the movement/state update significance against the last update made.
5451 { 5829 /// </summary>
5452 PacketPool.Instance.ReturnPacket(packet); 5830 /// <remarks>Can only be called by one thread at a time</remarks>
5453 return false; 5831 /// <returns></returns>
5454 } 5832 /// <param name='x'></param>
5455 #endregion 5833 private bool CheckAgentMovementUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
5834 {
5835 float qdelta1 = 1 - (float)Math.Pow(Quaternion.Dot(x.BodyRotation, m_thisAgentUpdateArgs.BodyRotation), 2);
5836 //qdelta2 = 1 - (float)Math.Pow(Quaternion.Dot(x.HeadRotation, m_thisAgentUpdateArgs.HeadRotation), 2);
5837
5838 bool movementSignificant =
5839 (qdelta1 > QDELTA) // significant if body rotation above threshold
5840 // Ignoring head rotation altogether, because it's not being used for anything interesting up the stack
5841 // || (qdelta2 > QDELTA * 10) // significant if head rotation above threshold
5842 || (x.ControlFlags != m_thisAgentUpdateArgs.ControlFlags) // significant if control flags changed
5843 || (x.ControlFlags != (byte)AgentManager.ControlFlags.NONE) // significant if user supplying any movement update commands
5844 || (x.Far != m_thisAgentUpdateArgs.Far) // significant if far distance changed
5845 || (x.Flags != m_thisAgentUpdateArgs.Flags) // significant if Flags changed
5846 || (x.State != m_thisAgentUpdateArgs.State) // significant if Stats changed
5847 ;
5848 //if (movementSignificant)
5849 //{
5850 //m_log.DebugFormat("[LLCLIENTVIEW]: Bod {0} {1}",
5851 // qdelta1, qdelta2);
5852 //m_log.DebugFormat("[LLCLIENTVIEW]: St {0} {1} {2} {3}",
5853 // x.ControlFlags, x.Flags, x.Far, x.State);
5854 //}
5855 return movementSignificant;
5856 }
5456 5857
5457 bool update = false; 5858 /// <summary>
5458 AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData; 5859 /// This checks the camera update significance against the last update made.
5459 5860 /// </summary>
5460 if (m_lastAgentUpdateArgs != null) 5861 /// <remarks>Can only be called by one thread at a time</remarks>
5461 { 5862 /// <returns></returns>
5462 // These should be ordered from most-likely to 5863 /// <param name='x'></param>
5463 // least likely to change. I've made an initial 5864 private bool CheckAgentCameraUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
5464 // guess at that. 5865 {
5465 update = 5866 float vdelta1 = Vector3.Distance(x.CameraAtAxis, m_thisAgentUpdateArgs.CameraAtAxis);
5466 ( 5867 float vdelta2 = Vector3.Distance(x.CameraCenter, m_thisAgentUpdateArgs.CameraCenter);
5467 (x.BodyRotation != m_lastAgentUpdateArgs.BodyRotation) || 5868 float vdelta3 = Vector3.Distance(x.CameraLeftAxis, m_thisAgentUpdateArgs.CameraLeftAxis);
5468 (x.CameraAtAxis != m_lastAgentUpdateArgs.CameraAtAxis) || 5869 float vdelta4 = Vector3.Distance(x.CameraUpAxis, m_thisAgentUpdateArgs.CameraUpAxis);
5469 (x.CameraCenter != m_lastAgentUpdateArgs.CameraCenter) ||
5470 (x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) ||
5471 (x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) ||
5472 (x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) ||
5473 (x.Far != m_lastAgentUpdateArgs.Far) ||
5474 (x.Flags != m_lastAgentUpdateArgs.Flags) ||
5475 (x.State != m_lastAgentUpdateArgs.State) ||
5476 (x.HeadRotation != m_lastAgentUpdateArgs.HeadRotation) ||
5477 (x.SessionID != m_lastAgentUpdateArgs.SessionID) ||
5478 (x.AgentID != m_lastAgentUpdateArgs.AgentID)
5479 );
5480 }
5481 else
5482 {
5483 m_lastAgentUpdateArgs = new AgentUpdateArgs();
5484 update = true;
5485 }
5486 5870
5487 if (update) 5871 bool cameraSignificant =
5488 { 5872 (vdelta1 > VDELTA) ||
5489// m_log.DebugFormat("[LLCLIENTVIEW]: Triggered AgentUpdate for {0}", sener.Name); 5873 (vdelta2 > VDELTA) ||
5874 (vdelta3 > VDELTA) ||
5875 (vdelta4 > VDELTA)
5876 ;
5490 5877
5491 m_lastAgentUpdateArgs.AgentID = x.AgentID; 5878 //if (cameraSignificant)
5492 m_lastAgentUpdateArgs.BodyRotation = x.BodyRotation; 5879 //{
5493 m_lastAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis; 5880 //m_log.DebugFormat("[LLCLIENTVIEW]: Cam1 {0} {1}",
5494 m_lastAgentUpdateArgs.CameraCenter = x.CameraCenter; 5881 // x.CameraAtAxis, x.CameraCenter);
5495 m_lastAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis; 5882 //m_log.DebugFormat("[LLCLIENTVIEW]: Cam2 {0} {1}",
5496 m_lastAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis; 5883 // x.CameraLeftAxis, x.CameraUpAxis);
5497 m_lastAgentUpdateArgs.ControlFlags = x.ControlFlags; 5884 //}
5498 m_lastAgentUpdateArgs.Far = x.Far;
5499 m_lastAgentUpdateArgs.Flags = x.Flags;
5500 m_lastAgentUpdateArgs.HeadRotation = x.HeadRotation;
5501 m_lastAgentUpdateArgs.SessionID = x.SessionID;
5502 m_lastAgentUpdateArgs.State = x.State;
5503 5885
5504 UpdateAgent handlerAgentUpdate = OnAgentUpdate; 5886 return cameraSignificant;
5505 UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate; 5887 }
5506 5888
5507 if (handlerPreAgentUpdate != null) 5889 private bool HandleAgentUpdate(IClientAPI sener, Packet packet)
5508 OnPreAgentUpdate(this, m_lastAgentUpdateArgs); 5890 {
5891 // We got here, which means that something in agent update was significant
5509 5892
5510 if (handlerAgentUpdate != null) 5893 AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
5511 OnAgentUpdate(this, m_lastAgentUpdateArgs); 5894 AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData;
5512 5895
5513 handlerAgentUpdate = null; 5896 if (x.AgentID != AgentId || x.SessionID != SessionId)
5514 handlerPreAgentUpdate = null; 5897 return false;
5515 } 5898
5516 } 5899 // Before we update the current m_thisAgentUpdateArgs, let's check this again
5900 // to see what exactly changed
5901 bool movement = CheckAgentMovementUpdateSignificance(x);
5902 bool camera = CheckAgentCameraUpdateSignificance(x);
5903
5904 m_thisAgentUpdateArgs.AgentID = x.AgentID;
5905 m_thisAgentUpdateArgs.BodyRotation = x.BodyRotation;
5906 m_thisAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis;
5907 m_thisAgentUpdateArgs.CameraCenter = x.CameraCenter;
5908 m_thisAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis;
5909 m_thisAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis;
5910 m_thisAgentUpdateArgs.ControlFlags = x.ControlFlags;
5911 m_thisAgentUpdateArgs.Far = x.Far;
5912 m_thisAgentUpdateArgs.Flags = x.Flags;
5913 m_thisAgentUpdateArgs.HeadRotation = x.HeadRotation;
5914 m_thisAgentUpdateArgs.SessionID = x.SessionID;
5915 m_thisAgentUpdateArgs.State = x.State;
5916
5917 UpdateAgent handlerAgentUpdate = OnAgentUpdate;
5918 UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate;
5919 UpdateAgent handlerAgentCameraUpdate = OnAgentCameraUpdate;
5920
5921 // Was there a significant movement/state change?
5922 if (movement)
5923 {
5924 if (handlerPreAgentUpdate != null)
5925 OnPreAgentUpdate(this, m_thisAgentUpdateArgs);
5926
5927 if (handlerAgentUpdate != null)
5928 OnAgentUpdate(this, m_thisAgentUpdateArgs);
5929 }
5930 // Was there a significant camera(s) change?
5931 if (camera)
5932 if (handlerAgentCameraUpdate != null)
5933 handlerAgentCameraUpdate(this, m_thisAgentUpdateArgs);
5934
5935 handlerAgentUpdate = null;
5936 handlerPreAgentUpdate = null;
5937 handlerAgentCameraUpdate = null;
5517 5938
5518 PacketPool.Instance.ReturnPacket(packet); 5939 PacketPool.Instance.ReturnPacket(packet);
5519 5940
@@ -6080,6 +6501,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6080 //m_log.Info("[LAND]: LAND:" + modify.ToString()); 6501 //m_log.Info("[LAND]: LAND:" + modify.ToString());
6081 if (modify.ParcelData.Length > 0) 6502 if (modify.ParcelData.Length > 0)
6082 { 6503 {
6504 // Note: the ModifyTerrain event handler sends out updated packets before the end of this event. Therefore,
6505 // a simple boolean value should work and perhaps queue up just a few terrain patch packets at the end of the edit.
6506 m_justEditedTerrain = true; // Prevent terrain packet (Land layer) from being queued, make it unreliable
6083 if (OnModifyTerrain != null) 6507 if (OnModifyTerrain != null)
6084 { 6508 {
6085 for (int i = 0; i < modify.ParcelData.Length; i++) 6509 for (int i = 0; i < modify.ParcelData.Length; i++)
@@ -6095,6 +6519,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6095 } 6519 }
6096 } 6520 }
6097 } 6521 }
6522 m_justEditedTerrain = false; // Queue terrain packet (Land layer) if necessary, make it reliable again
6098 } 6523 }
6099 6524
6100 return true; 6525 return true;
@@ -6149,17 +6574,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6149 // Temporarily protect ourselves from the mantis #951 failure. 6574 // Temporarily protect ourselves from the mantis #951 failure.
6150 // However, we could do this for several other handlers where a failure isn't terminal 6575 // However, we could do this for several other handlers where a failure isn't terminal
6151 // for the client session anyway, in order to protect ourselves against bad code in plugins 6576 // for the client session anyway, in order to protect ourselves against bad code in plugins
6577 Vector3 avSize = appear.AgentData.Size;
6152 try 6578 try
6153 { 6579 {
6154 byte[] visualparams = new byte[appear.VisualParam.Length]; 6580 byte[] visualparams = new byte[appear.VisualParam.Length];
6155 for (int i = 0; i < appear.VisualParam.Length; i++) 6581 for (int i = 0; i < appear.VisualParam.Length; i++)
6156 visualparams[i] = appear.VisualParam[i].ParamValue; 6582 visualparams[i] = appear.VisualParam[i].ParamValue;
6583 //var b = appear.WearableData[0];
6157 6584
6158 Primitive.TextureEntry te = null; 6585 Primitive.TextureEntry te = null;
6159 if (appear.ObjectData.TextureEntry.Length > 1) 6586 if (appear.ObjectData.TextureEntry.Length > 1)
6160 te = new Primitive.TextureEntry(appear.ObjectData.TextureEntry, 0, appear.ObjectData.TextureEntry.Length); 6587 te = new Primitive.TextureEntry(appear.ObjectData.TextureEntry, 0, appear.ObjectData.TextureEntry.Length);
6161 6588
6162 handlerSetAppearance(sender, te, visualparams); 6589 WearableCacheItem[] cacheitems = new WearableCacheItem[appear.WearableData.Length];
6590 for (int i=0; i<appear.WearableData.Length;i++)
6591 cacheitems[i] = new WearableCacheItem(){CacheId = appear.WearableData[i].CacheID,TextureIndex=Convert.ToUInt32(appear.WearableData[i].TextureIndex)};
6592
6593
6594
6595 handlerSetAppearance(sender, te, visualparams,avSize, cacheitems);
6163 } 6596 }
6164 catch (Exception e) 6597 catch (Exception e)
6165 { 6598 {
@@ -6426,6 +6859,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6426 } 6859 }
6427 #endregion 6860 #endregion
6428 6861
6862 if (SceneAgent.IsChildAgent)
6863 {
6864 SendCantSitBecauseChildAgentResponse();
6865 return true;
6866 }
6867
6429 AgentRequestSit handlerAgentRequestSit = OnAgentRequestSit; 6868 AgentRequestSit handlerAgentRequestSit = OnAgentRequestSit;
6430 6869
6431 if (handlerAgentRequestSit != null) 6870 if (handlerAgentRequestSit != null)
@@ -6450,6 +6889,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6450 } 6889 }
6451 #endregion 6890 #endregion
6452 6891
6892 if (SceneAgent.IsChildAgent)
6893 {
6894 SendCantSitBecauseChildAgentResponse();
6895 return true;
6896 }
6897
6453 AgentSit handlerAgentSit = OnAgentSit; 6898 AgentSit handlerAgentSit = OnAgentSit;
6454 if (handlerAgentSit != null) 6899 if (handlerAgentSit != null)
6455 { 6900 {
@@ -6459,6 +6904,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6459 return true; 6904 return true;
6460 } 6905 }
6461 6906
6907 /// <summary>
6908 /// Used when a child agent gets a sit response which should not be fulfilled.
6909 /// </summary>
6910 private void SendCantSitBecauseChildAgentResponse()
6911 {
6912 SendAlertMessage("Try moving closer. Can't sit on object because it is not in the same region as you.");
6913 }
6914
6462 private bool HandleSoundTrigger(IClientAPI sender, Packet Pack) 6915 private bool HandleSoundTrigger(IClientAPI sender, Packet Pack)
6463 { 6916 {
6464 SoundTriggerPacket soundTriggerPacket = (SoundTriggerPacket)Pack; 6917 SoundTriggerPacket soundTriggerPacket = (SoundTriggerPacket)Pack;
@@ -6856,7 +7309,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6856 { 7309 {
6857 handlerObjectDuplicate(dupe.ObjectData[i].ObjectLocalID, dupe.SharedData.Offset, 7310 handlerObjectDuplicate(dupe.ObjectData[i].ObjectLocalID, dupe.SharedData.Offset,
6858 dupe.SharedData.DuplicateFlags, AgentId, 7311 dupe.SharedData.DuplicateFlags, AgentId,
6859 m_activeGroupID); 7312 ActiveGroupId);
6860 } 7313 }
6861 } 7314 }
6862 7315
@@ -7031,14 +7484,37 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7031 7484
7032 if (handlerUpdatePrimFlags != null) 7485 if (handlerUpdatePrimFlags != null)
7033 { 7486 {
7034 byte[] data = Pack.ToBytes(); 7487// byte[] data = Pack.ToBytes();
7035 // 46,47,48 are special positions within the packet 7488 // 46,47,48 are special positions within the packet
7036 // This may change so perhaps we need a better way 7489 // This may change so perhaps we need a better way
7037 // of storing this (OMV.FlagUpdatePacket.UsePhysics,etc?) 7490 // of storing this (OMV.FlagUpdatePacket.UsePhysics,etc?)
7038 bool UsePhysics = (data[46] != 0) ? true : false; 7491 /*
7039 bool IsTemporary = (data[47] != 0) ? true : false; 7492 bool UsePhysics = (data[46] != 0) ? true : false;
7040 bool IsPhantom = (data[48] != 0) ? true : false; 7493 bool IsTemporary = (data[47] != 0) ? true : false;
7041 handlerUpdatePrimFlags(flags.AgentData.ObjectLocalID, UsePhysics, IsTemporary, IsPhantom, this); 7494 bool IsPhantom = (data[48] != 0) ? true : false;
7495 handlerUpdatePrimFlags(flags.AgentData.ObjectLocalID, UsePhysics, IsTemporary, IsPhantom, this);
7496 */
7497 bool UsePhysics = flags.AgentData.UsePhysics;
7498 bool IsPhantom = flags.AgentData.IsPhantom;
7499 bool IsTemporary = flags.AgentData.IsTemporary;
7500 ObjectFlagUpdatePacket.ExtraPhysicsBlock[] blocks = flags.ExtraPhysics;
7501 ExtraPhysicsData physdata = new ExtraPhysicsData();
7502
7503 if (blocks == null || blocks.Length == 0)
7504 {
7505 physdata.PhysShapeType = PhysShapeType.invalid;
7506 }
7507 else
7508 {
7509 ObjectFlagUpdatePacket.ExtraPhysicsBlock phsblock = blocks[0];
7510 physdata.PhysShapeType = (PhysShapeType)phsblock.PhysicsShapeType;
7511 physdata.Bounce = phsblock.Restitution;
7512 physdata.Density = phsblock.Density;
7513 physdata.Friction = phsblock.Friction;
7514 physdata.GravitationModifier = phsblock.GravityMultiplier;
7515 }
7516
7517 handlerUpdatePrimFlags(flags.AgentData.ObjectLocalID, UsePhysics, IsTemporary, IsPhantom, physdata, this);
7042 } 7518 }
7043 return true; 7519 return true;
7044 } 7520 }
@@ -7446,7 +7922,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7446 if (handlerObjectDuplicateOnRay != null) 7922 if (handlerObjectDuplicateOnRay != null)
7447 { 7923 {
7448 handlerObjectDuplicateOnRay(dupeOnRay.ObjectData[i].ObjectLocalID, dupeOnRay.AgentData.DuplicateFlags, 7924 handlerObjectDuplicateOnRay(dupeOnRay.ObjectData[i].ObjectLocalID, dupeOnRay.AgentData.DuplicateFlags,
7449 AgentId, m_activeGroupID, dupeOnRay.AgentData.RayTargetID, dupeOnRay.AgentData.RayEnd, 7925 AgentId, ActiveGroupId, dupeOnRay.AgentData.RayTargetID, dupeOnRay.AgentData.RayEnd,
7450 dupeOnRay.AgentData.RayStart, dupeOnRay.AgentData.BypassRaycast, dupeOnRay.AgentData.RayEndIsIntersection, 7926 dupeOnRay.AgentData.RayStart, dupeOnRay.AgentData.BypassRaycast, dupeOnRay.AgentData.RayEndIsIntersection,
7451 dupeOnRay.AgentData.CopyCenters, dupeOnRay.AgentData.CopyRotates); 7927 dupeOnRay.AgentData.CopyCenters, dupeOnRay.AgentData.CopyRotates);
7452 } 7928 }
@@ -7640,129 +8116,146 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7640 //m_log.Debug("ClientView.ProcessPackets.cs:ProcessInPacket() - Got transfer request"); 8116 //m_log.Debug("ClientView.ProcessPackets.cs:ProcessInPacket() - Got transfer request");
7641 8117
7642 TransferRequestPacket transfer = (TransferRequestPacket)Pack; 8118 TransferRequestPacket transfer = (TransferRequestPacket)Pack;
7643 //m_log.Debug("Transfer Request: " + transfer.ToString());
7644 // Validate inventory transfers
7645 // Has to be done here, because AssetCache can't do it
7646 //
7647 UUID taskID = UUID.Zero; 8119 UUID taskID = UUID.Zero;
7648 if (transfer.TransferInfo.SourceType == (int)SourceType.SimInventoryItem) 8120 if (transfer.TransferInfo.SourceType == (int)SourceType.SimInventoryItem)
7649 { 8121 {
7650 taskID = new UUID(transfer.TransferInfo.Params, 48);
7651 UUID itemID = new UUID(transfer.TransferInfo.Params, 64);
7652 UUID requestID = new UUID(transfer.TransferInfo.Params, 80);
7653
7654// m_log.DebugFormat(
7655// "[CLIENT]: Got request for asset {0} from item {1} in prim {2} by {3}",
7656// requestID, itemID, taskID, Name);
7657
7658 if (!(((Scene)m_scene).Permissions.BypassPermissions())) 8122 if (!(((Scene)m_scene).Permissions.BypassPermissions()))
7659 { 8123 {
7660 if (taskID != UUID.Zero) // Prim 8124 // We're spawning a thread because the permissions check can block this thread
8125 Util.FireAndForget(delegate
7661 { 8126 {
7662 SceneObjectPart part = ((Scene)m_scene).GetSceneObjectPart(taskID); 8127 // This requests the asset if needed
8128 HandleSimInventoryTransferRequestWithPermsCheck(sender, transfer);
8129 }, null, "LLClientView.HandleTransferRequest");
7663 8130
7664 if (part == null) 8131 return true;
7665 { 8132 }
7666 m_log.WarnFormat( 8133 }
7667 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but prim does not exist", 8134 else if (transfer.TransferInfo.SourceType == (int)SourceType.SimEstate)
7668 Name, requestID, itemID, taskID); 8135 {
7669 return true; 8136 //TransferRequestPacket does not include covenant uuid?
7670 } 8137 //get scene covenant uuid
8138 taskID = m_scene.RegionInfo.RegionSettings.Covenant;
8139 }
7671 8140
7672 TaskInventoryItem tii = part.Inventory.GetInventoryItem(itemID); 8141 // This is non-blocking
7673 if (tii == null) 8142 MakeAssetRequest(transfer, taskID);
7674 {
7675 m_log.WarnFormat(
7676 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item does not exist",
7677 Name, requestID, itemID, taskID);
7678 return true;
7679 }
7680 8143
7681 if (tii.Type == (int)AssetType.LSLText) 8144 return true;
7682 { 8145 }
7683 if (!((Scene)m_scene).Permissions.CanEditScript(itemID, taskID, AgentId))
7684 return true;
7685 }
7686 else if (tii.Type == (int)AssetType.Notecard)
7687 {
7688 if (!((Scene)m_scene).Permissions.CanEditNotecard(itemID, taskID, AgentId))
7689 return true;
7690 }
7691 else
7692 {
7693 // TODO: Change this code to allow items other than notecards and scripts to be successfully
7694 // shared with group. In fact, this whole block of permissions checking should move to an IPermissionsModule
7695 if (part.OwnerID != AgentId)
7696 {
7697 m_log.WarnFormat(
7698 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the prim is owned by {4}",
7699 Name, requestID, itemID, taskID, part.OwnerID);
7700 return true;
7701 }
7702 8146
7703 if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0) 8147 private void HandleSimInventoryTransferRequestWithPermsCheck(IClientAPI sender, TransferRequestPacket transfer)
7704 { 8148 {
7705 m_log.WarnFormat( 8149 UUID taskID = new UUID(transfer.TransferInfo.Params, 48);
7706 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but modify permissions are not set", 8150 UUID itemID = new UUID(transfer.TransferInfo.Params, 64);
7707 Name, requestID, itemID, taskID); 8151 UUID requestID = new UUID(transfer.TransferInfo.Params, 80);
7708 return true;
7709 }
7710 8152
7711 if (tii.OwnerID != AgentId) 8153 //m_log.DebugFormat(
7712 { 8154 // "[CLIENT]: Got request for asset {0} from item {1} in prim {2} by {3}",
7713 m_log.WarnFormat( 8155 // requestID, itemID, taskID, Name);
7714 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the item is owned by {4}",
7715 Name, requestID, itemID, taskID, tii.OwnerID);
7716 return true;
7717 }
7718 8156
7719 if (( 8157 //m_log.Debug("Transfer Request: " + transfer.ToString());
7720 tii.CurrentPermissions & ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) 8158 // Validate inventory transfers
7721 != ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) 8159 // Has to be done here, because AssetCache can't do it
7722 { 8160 //
7723 m_log.WarnFormat( 8161 if (taskID != UUID.Zero) // Prim
7724 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item permissions are not modify/copy/transfer", 8162 {
7725 Name, requestID, itemID, taskID); 8163 SceneObjectPart part = ((Scene)m_scene).GetSceneObjectPart(taskID);
7726 return true;
7727 }
7728 8164
7729 if (tii.AssetID != requestID) 8165 if (part == null)
7730 { 8166 {
7731 m_log.WarnFormat( 8167 m_log.WarnFormat(
7732 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but this does not match item's asset {4}", 8168 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but prim does not exist",
7733 Name, requestID, itemID, taskID, tii.AssetID); 8169 Name, requestID, itemID, taskID);
7734 return true; 8170 return;
7735 } 8171 }
7736 } 8172
8173 TaskInventoryItem tii = part.Inventory.GetInventoryItem(itemID);
8174 if (tii == null)
8175 {
8176 m_log.WarnFormat(
8177 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item does not exist",
8178 Name, requestID, itemID, taskID);
8179 return;
8180 }
8181
8182 if (tii.Type == (int)AssetType.LSLText)
8183 {
8184 if (!((Scene)m_scene).Permissions.CanEditScript(itemID, taskID, AgentId))
8185 return;
8186 }
8187 else if (tii.Type == (int)AssetType.Notecard)
8188 {
8189 if (!((Scene)m_scene).Permissions.CanEditNotecard(itemID, taskID, AgentId))
8190 return;
8191 }
8192 else
8193 {
8194 // TODO: Change this code to allow items other than notecards and scripts to be successfully
8195 // shared with group. In fact, this whole block of permissions checking should move to an IPermissionsModule
8196 if (part.OwnerID != AgentId)
8197 {
8198 m_log.WarnFormat(
8199 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the prim is owned by {4}",
8200 Name, requestID, itemID, taskID, part.OwnerID);
8201 return;
7737 } 8202 }
7738 else // Agent 8203
8204 if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0)
7739 { 8205 {
7740 IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>(); 8206 m_log.WarnFormat(
7741 if (invAccess != null) 8207 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but modify permissions are not set",
7742 { 8208 Name, requestID, itemID, taskID);
7743 if (!invAccess.CanGetAgentInventoryItem(this, itemID, requestID)) 8209 return;
7744 return false; 8210 }
7745 } 8211
7746 else 8212 if (tii.OwnerID != AgentId)
7747 { 8213 {
7748 return false; 8214 m_log.WarnFormat(
7749 } 8215 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the item is owned by {4}",
8216 Name, requestID, itemID, taskID, tii.OwnerID);
8217 return;
8218 }
8219
8220 if ((
8221 tii.CurrentPermissions & ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer))
8222 != ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer))
8223 {
8224 m_log.WarnFormat(
8225 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item permissions are not modify/copy/transfer",
8226 Name, requestID, itemID, taskID);
8227 return;
8228 }
8229
8230 if (tii.AssetID != requestID)
8231 {
8232 m_log.WarnFormat(
8233 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but this does not match item's asset {4}",
8234 Name, requestID, itemID, taskID, tii.AssetID);
8235 return;
7750 } 8236 }
7751 } 8237 }
7752 } 8238 }
7753 else 8239 else // Agent
7754 if (transfer.TransferInfo.SourceType == (int)SourceType.SimEstate) 8240 {
8241 IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>();
8242 if (invAccess != null)
7755 { 8243 {
7756 //TransferRequestPacket does not include covenant uuid? 8244 if (!invAccess.CanGetAgentInventoryItem(this, itemID, requestID))
7757 //get scene covenant uuid 8245 return;
7758 taskID = m_scene.RegionInfo.RegionSettings.Covenant;
7759 } 8246 }
8247 else
8248 {
8249 return;
8250 }
8251 }
7760 8252
8253 // Permissions out of the way, let's request the asset
7761 MakeAssetRequest(transfer, taskID); 8254 MakeAssetRequest(transfer, taskID);
7762 8255
7763 return true;
7764 } 8256 }
7765 8257
8258
7766 private bool HandleAssetUploadRequest(IClientAPI sender, Packet Pack) 8259 private bool HandleAssetUploadRequest(IClientAPI sender, Packet Pack)
7767 { 8260 {
7768 AssetUploadRequestPacket request = (AssetUploadRequestPacket)Pack; 8261 AssetUploadRequestPacket request = (AssetUploadRequestPacket)Pack;
@@ -8477,8 +8970,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
8477 return true; 8970 return true;
8478 } 8971 }
8479 #endregion 8972 #endregion
8480 string mapName = Util.UTF8.GetString(map.NameData.Name, 0, 8973 string mapName = (map.NameData.Name.Length == 0) ? m_scene.RegionInfo.RegionName :
8481 map.NameData.Name.Length - 1); 8974 Util.UTF8.GetString(map.NameData.Name, 0, map.NameData.Name.Length - 1);
8482 RequestMapName handlerMapNameRequest = OnMapNameRequest; 8975 RequestMapName handlerMapNameRequest = OnMapNameRequest;
8483 if (handlerMapNameRequest != null) 8976 if (handlerMapNameRequest != null)
8484 { 8977 {
@@ -8583,7 +9076,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
8583 if (aCircuit != null && aCircuit.ServiceURLs != null && aCircuit.ServiceURLs.ContainsKey("AssetServerURI")) 9076 if (aCircuit != null && aCircuit.ServiceURLs != null && aCircuit.ServiceURLs.ContainsKey("AssetServerURI"))
8584 { 9077 {
8585 string assetServer = aCircuit.ServiceURLs["AssetServerURI"].ToString(); 9078 string assetServer = aCircuit.ServiceURLs["AssetServerURI"].ToString();
8586 return ((Scene)Scene).AssetService.Get(assetServer + "/" + id); 9079 if (!string.IsNullOrEmpty(assetServer))
9080 return ((Scene)Scene).AssetService.Get(assetServer + "/" + id);
8587 } 9081 }
8588 9082
8589 return null; 9083 return null;
@@ -8606,6 +9100,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
8606 TeleportLocationRequest handlerTeleportLocationRequest = OnTeleportLocationRequest; 9100 TeleportLocationRequest handlerTeleportLocationRequest = OnTeleportLocationRequest;
8607 if (handlerTeleportLocationRequest != null) 9101 if (handlerTeleportLocationRequest != null)
8608 { 9102 {
9103 // Adjust teleport location to base of a larger region if requested to teleport to a sub-region
9104 uint locX, locY;
9105 Util.RegionHandleToWorldLoc(tpLocReq.Info.RegionHandle, out locX, out locY);
9106 if ((locX >= m_scene.RegionInfo.WorldLocX)
9107 && (locX < (m_scene.RegionInfo.WorldLocX + m_scene.RegionInfo.RegionSizeX))
9108 && (locY >= m_scene.RegionInfo.WorldLocY)
9109 && (locY < (m_scene.RegionInfo.WorldLocY + m_scene.RegionInfo.RegionSizeY)) )
9110 {
9111 tpLocReq.Info.RegionHandle = m_scene.RegionInfo.RegionHandle;
9112 tpLocReq.Info.Position.X += locX - m_scene.RegionInfo.WorldLocX;
9113 tpLocReq.Info.Position.Y += locY - m_scene.RegionInfo.WorldLocY;
9114 }
9115
8609 handlerTeleportLocationRequest(this, tpLocReq.Info.RegionHandle, tpLocReq.Info.Position, 9116 handlerTeleportLocationRequest(this, tpLocReq.Info.RegionHandle, tpLocReq.Info.Position,
8610 tpLocReq.Info.LookAt, 16); 9117 tpLocReq.Info.LookAt, 16);
8611 } 9118 }
@@ -9399,6 +9906,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9399 } 9906 }
9400 return true; 9907 return true;
9401 9908
9909 case "kickestate":
9910
9911 if(((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
9912 {
9913 UUID invoice = messagePacket.MethodData.Invoice;
9914 UUID SenderID = messagePacket.AgentData.AgentID;
9915 UUID Prey;
9916
9917 UUID.TryParse(Utils.BytesToString(messagePacket.ParamList[0].Parameter), out Prey);
9918
9919 OnEstateTeleportOneUserHomeRequest(this, invoice, SenderID, Prey);
9920 }
9921 return true;
9922
9402 default: 9923 default:
9403 m_log.WarnFormat( 9924 m_log.WarnFormat(
9404 "[LLCLIENTVIEW]: EstateOwnerMessage: Unknown method {0} requested for {1} in {2}", 9925 "[LLCLIENTVIEW]: EstateOwnerMessage: Unknown method {0} requested for {1} in {2}",
@@ -9604,7 +10125,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9604 EconomyDataRequest handlerEconomoyDataRequest = OnEconomyDataRequest; 10125 EconomyDataRequest handlerEconomoyDataRequest = OnEconomyDataRequest;
9605 if (handlerEconomoyDataRequest != null) 10126 if (handlerEconomoyDataRequest != null)
9606 { 10127 {
9607 handlerEconomoyDataRequest(AgentId); 10128 handlerEconomoyDataRequest(this);
9608 } 10129 }
9609 return true; 10130 return true;
9610 } 10131 }
@@ -10032,7 +10553,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10032 handlerDirFindQuery(this, 10553 handlerDirFindQuery(this,
10033 dirFindQueryPacket.QueryData.QueryID, 10554 dirFindQueryPacket.QueryData.QueryID,
10034 Utils.BytesToString( 10555 Utils.BytesToString(
10035 dirFindQueryPacket.QueryData.QueryText), 10556 dirFindQueryPacket.QueryData.QueryText).Trim(),
10036 dirFindQueryPacket.QueryData.QueryFlags, 10557 dirFindQueryPacket.QueryData.QueryFlags,
10037 dirFindQueryPacket.QueryData.QueryStart); 10558 dirFindQueryPacket.QueryData.QueryStart);
10038 } 10559 }
@@ -11384,8 +11905,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11384 } 11905 }
11385 11906
11386 /// <summary> 11907 /// <summary>
11387 /// Send a response back to a client when it asks the asset server (via the region server) if it has
11388 /// its appearance texture cached.
11389 /// </summary> 11908 /// </summary>
11390 /// <remarks> 11909 /// <remarks>
11391 /// At the moment, we always reply that there is no cached texture. 11910 /// At the moment, we always reply that there is no cached texture.
@@ -11395,13 +11914,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11395 /// <returns></returns> 11914 /// <returns></returns>
11396 protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet) 11915 protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet)
11397 { 11916 {
11398 //m_log.Debug("texture cached: " + packet.ToString());
11399 AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet; 11917 AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet;
11400 AgentCachedTextureResponsePacket cachedresp = (AgentCachedTextureResponsePacket)PacketPool.Instance.GetPacket(PacketType.AgentCachedTextureResponse); 11918 AgentCachedTextureResponsePacket cachedresp = (AgentCachedTextureResponsePacket)PacketPool.Instance.GetPacket(PacketType.AgentCachedTextureResponse);
11401 11919
11402 if (cachedtex.AgentData.SessionID != SessionId) 11920 if (cachedtex.AgentData.SessionID != SessionId)
11403 return false; 11921 return false;
11404 11922
11923
11405 // TODO: don't create new blocks if recycling an old packet 11924 // TODO: don't create new blocks if recycling an old packet
11406 cachedresp.AgentData.AgentID = AgentId; 11925 cachedresp.AgentData.AgentID = AgentId;
11407 cachedresp.AgentData.SessionID = m_sessionId; 11926 cachedresp.AgentData.SessionID = m_sessionId;
@@ -11410,19 +11929,127 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11410 cachedresp.WearableData = 11929 cachedresp.WearableData =
11411 new AgentCachedTextureResponsePacket.WearableDataBlock[cachedtex.WearableData.Length]; 11930 new AgentCachedTextureResponsePacket.WearableDataBlock[cachedtex.WearableData.Length];
11412 11931
11413 for (int i = 0; i < cachedtex.WearableData.Length; i++) 11932 int maxWearablesLoop = cachedtex.WearableData.Length;
11933 if (maxWearablesLoop > AvatarWearable.MAX_WEARABLES)
11934 maxWearablesLoop = AvatarWearable.MAX_WEARABLES;
11935
11936 // Find the cached baked textures for this user, if they're available
11937
11938 IAssetService cache = m_scene.AssetService;
11939 IBakedTextureModule bakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
11940
11941 WearableCacheItem[] cacheItems = null;
11942
11943 if (bakedTextureModule != null && cache != null)
11414 { 11944 {
11415 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); 11945 ScenePresence p = m_scene.GetScenePresence(AgentId);
11416 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex; 11946 if (p.Appearance != null)
11417 cachedresp.WearableData[i].TextureID = UUID.Zero; 11947 {
11418 cachedresp.WearableData[i].HostName = new byte[0]; 11948 if (p.Appearance.WearableCacheItems == null || p.Appearance.WearableCacheItemsDirty)
11949 {
11950 try
11951 {
11952 cacheItems = bakedTextureModule.Get(AgentId);
11953 p.Appearance.WearableCacheItems = cacheItems;
11954 p.Appearance.WearableCacheItemsDirty = false;
11955 }
11956 catch (Exception)
11957 {
11958 cacheItems = null;
11959 }
11960
11961 }
11962 else if (p.Appearance.WearableCacheItems != null)
11963 {
11964 cacheItems = p.Appearance.WearableCacheItems;
11965 }
11966 }
11419 } 11967 }
11420 11968
11969 if (cacheItems != null)
11970 {
11971 // We need to make sure the asset stored in the bake is available on this server also by its assetid before we map it to a Cacheid.
11972 // Copy the baked textures to the sim's assets cache (local only).
11973 foreach (WearableCacheItem item in cacheItems)
11974 {
11975 if (cache.GetCached(item.TextureID.ToString()) == null)
11976 {
11977 item.TextureAsset.Temporary = true;
11978 item.TextureAsset.Local = true;
11979 cache.Store(item.TextureAsset);
11980 }
11981 }
11982
11983 // Return the cached textures
11984 for (int i = 0; i < maxWearablesLoop; i++)
11985 {
11986 WearableCacheItem item =
11987 WearableCacheItem.SearchTextureIndex(cachedtex.WearableData[i].TextureIndex, cacheItems);
11988
11989 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11990 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
11991 cachedresp.WearableData[i].HostName = new byte[0];
11992 if (item != null && cachedtex.WearableData[i].ID == item.CacheId)
11993 {
11994 cachedresp.WearableData[i].TextureID = item.TextureID;
11995 }
11996 else
11997 {
11998 cachedresp.WearableData[i].TextureID = UUID.Zero;
11999 }
12000 }
12001 }
12002 else
12003 {
12004 // Cached textures not available
12005 for (int i = 0; i < maxWearablesLoop; i++)
12006 {
12007 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
12008 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
12009 cachedresp.WearableData[i].TextureID = UUID.Zero;
12010 cachedresp.WearableData[i].HostName = new byte[0];
12011 }
12012 }
12013
11421 cachedresp.Header.Zerocoded = true; 12014 cachedresp.Header.Zerocoded = true;
11422 OutPacket(cachedresp, ThrottleOutPacketType.Task); 12015 OutPacket(cachedresp, ThrottleOutPacketType.Task);
11423 12016
11424 return true; 12017 return true;
11425 } 12018 }
12019
12020 /// <summary>
12021 /// Send a response back to a client when it asks the asset server (via the region server) if it has
12022 /// its appearance texture cached.
12023 /// </summary>
12024 /// <param name="avatar"></param>
12025 /// <param name="serial"></param>
12026 /// <param name="cachedTextures"></param>
12027 /// <returns></returns>
12028 public void SendCachedTextureResponse(ISceneEntity avatar, int serial, List<CachedTextureResponseArg> cachedTextures)
12029 {
12030 ScenePresence presence = avatar as ScenePresence;
12031 if (presence == null)
12032 return;
12033
12034 AgentCachedTextureResponsePacket cachedresp = (AgentCachedTextureResponsePacket)PacketPool.Instance.GetPacket(PacketType.AgentCachedTextureResponse);
12035
12036 // TODO: don't create new blocks if recycling an old packet
12037 cachedresp.AgentData.AgentID = m_agentId;
12038 cachedresp.AgentData.SessionID = m_sessionId;
12039 cachedresp.AgentData.SerialNum = serial;
12040 cachedresp.WearableData = new AgentCachedTextureResponsePacket.WearableDataBlock[cachedTextures.Count];
12041
12042 for (int i = 0; i < cachedTextures.Count; i++)
12043 {
12044 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
12045 cachedresp.WearableData[i].TextureIndex = (byte)cachedTextures[i].BakedTextureIndex;
12046 cachedresp.WearableData[i].TextureID = cachedTextures[i].BakedTextureID;
12047 cachedresp.WearableData[i].HostName = new byte[0];
12048 }
12049
12050 cachedresp.Header.Zerocoded = true;
12051 OutPacket(cachedresp, ThrottleOutPacketType.Task);
12052 }
11426 12053
11427 protected bool HandleMultipleObjUpdate(IClientAPI simClient, Packet packet) 12054 protected bool HandleMultipleObjUpdate(IClientAPI simClient, Packet packet)
11428 { 12055 {
@@ -11449,8 +12076,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11449 if (part == null) 12076 if (part == null)
11450 { 12077 {
11451 // It's a ghost! tell the client to delete it from view. 12078 // It's a ghost! tell the client to delete it from view.
11452 simClient.SendKillObject(Scene.RegionInfo.RegionHandle, 12079 simClient.SendKillObject(new List<uint> { localId });
11453 new List<uint> { localId });
11454 } 12080 }
11455 else 12081 else
11456 { 12082 {
@@ -11777,6 +12403,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11777 /// provide your own method.</param> 12403 /// provide your own method.</param>
11778 protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting, UnackedPacketMethod method) 12404 protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting, UnackedPacketMethod method)
11779 { 12405 {
12406 if (m_outPacketsToDrop != null)
12407 if (m_outPacketsToDrop.Contains(packet.Type.ToString()))
12408 return;
12409
11780 if (DebugPacketLevel > 0) 12410 if (DebugPacketLevel > 0)
11781 { 12411 {
11782 bool logPacket = true; 12412 bool logPacket = true;
@@ -11811,17 +12441,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11811 m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting, method); 12441 m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting, method);
11812 } 12442 }
11813 12443
11814 public bool AddMoney(int debit)
11815 {
11816 if (m_moneyBalance + debit >= 0)
11817 {
11818 m_moneyBalance += debit;
11819 SendMoneyBalance(UUID.Zero, true, Util.StringToBytes256("Poof Poof!"), m_moneyBalance);
11820 return true;
11821 }
11822 return false;
11823 }
11824
11825 protected void HandleAutopilot(Object sender, string method, List<String> args) 12444 protected void HandleAutopilot(Object sender, string method, List<String> args)
11826 { 12445 {
11827 float locx = 0; 12446 float locx = 0;
@@ -11846,6 +12465,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11846 /// <param name="Pack">OpenMetaverse.packet</param> 12465 /// <param name="Pack">OpenMetaverse.packet</param>
11847 public void ProcessInPacket(Packet packet) 12466 public void ProcessInPacket(Packet packet)
11848 { 12467 {
12468 if (m_inPacketsToDrop != null)
12469 if (m_inPacketsToDrop.Contains(packet.Type.ToString()))
12470 return;
12471
11849 if (DebugPacketLevel > 0) 12472 if (DebugPacketLevel > 0)
11850 { 12473 {
11851 bool logPacket = true; 12474 bool logPacket = true;
@@ -11880,6 +12503,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11880 12503
11881 shape.PCode = addPacket.ObjectData.PCode; 12504 shape.PCode = addPacket.ObjectData.PCode;
11882 shape.State = addPacket.ObjectData.State; 12505 shape.State = addPacket.ObjectData.State;
12506 shape.LastAttachPoint = addPacket.ObjectData.State;
11883 shape.PathBegin = addPacket.ObjectData.PathBegin; 12507 shape.PathBegin = addPacket.ObjectData.PathBegin;
11884 shape.PathEnd = addPacket.ObjectData.PathEnd; 12508 shape.PathEnd = addPacket.ObjectData.PathEnd;
11885 shape.PathScaleX = addPacket.ObjectData.PathScaleX; 12509 shape.PathScaleX = addPacket.ObjectData.PathScaleX;
@@ -11910,7 +12534,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11910 ClientInfo info = m_udpClient.GetClientInfo(); 12534 ClientInfo info = m_udpClient.GetClientInfo();
11911 12535
11912 info.proxyEP = null; 12536 info.proxyEP = null;
11913 info.agentcircuit = RequestClientInfo(); 12537 if (info.agentcircuit == null)
12538 info.agentcircuit = RequestClientInfo();
11914 12539
11915 return info; 12540 return info;
11916 } 12541 }
@@ -12079,6 +12704,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12079 return String.Empty; 12704 return String.Empty;
12080 } 12705 }
12081 12706
12707 public OSDMap OReport(string uptime, string version)
12708 {
12709 return new OSDMap();
12710 }
12711
12082 /// <summary> 12712 /// <summary>
12083 /// Make an asset request to the asset service in response to a client request. 12713 /// Make an asset request to the asset service in response to a client request.
12084 /// </summary> 12714 /// </summary>
@@ -12126,16 +12756,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12126 12756
12127 if (asset == null) 12757 if (asset == null)
12128 { 12758 {
12129 req.AssetInf = null; 12759 // Try the user's asset server
12130 req.AssetRequestSource = source; 12760 IInventoryAccessModule inventoryAccessModule = Scene.RequestModuleInterface<IInventoryAccessModule>();
12131 req.IsTextureRequest = false; 12761
12132 req.NumPackets = 0; 12762 string assetServerURL = string.Empty;
12133 req.Params = transferRequest.TransferInfo.Params; 12763 if (inventoryAccessModule.IsForeignUser(AgentId, out assetServerURL) && !string.IsNullOrEmpty(assetServerURL))
12134 req.RequestAssetID = requestID; 12764 {
12135 req.TransferRequestID = transferRequest.TransferInfo.TransferID; 12765 if (!assetServerURL.EndsWith("/") && !assetServerURL.EndsWith("="))
12766 assetServerURL = assetServerURL + "/";
12767
12768 //m_log.DebugFormat("[LLCLIENTVIEW]: asset {0} not found in local storage. Trying user's storage.", assetServerURL + id);
12769 asset = m_scene.AssetService.Get(assetServerURL + id);
12770 }
12771
12772 if (asset == null)
12773 {
12774 req.AssetInf = null;
12775 req.AssetRequestSource = source;
12776 req.IsTextureRequest = false;
12777 req.NumPackets = 0;
12778 req.Params = transferRequest.TransferInfo.Params;
12779 req.RequestAssetID = requestID;
12780 req.TransferRequestID = transferRequest.TransferInfo.TransferID;
12781
12782 SendAssetNotFound(req);
12783 return;
12784 }
12136 12785
12137 SendAssetNotFound(req);
12138 return;
12139 } 12786 }
12140 12787
12141 if (transferRequest.TransferInfo.SourceType == (int)SourceType.Asset) 12788 if (transferRequest.TransferInfo.SourceType == (int)SourceType.Asset)
@@ -12201,8 +12848,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12201 12848
12202 public struct PacketProcessor 12849 public struct PacketProcessor
12203 { 12850 {
12204 public PacketMethod method; 12851 /// <summary>
12205 public bool Async; 12852 /// Packet handling method.
12853 /// </summary>
12854 public PacketMethod method { get; set; }
12855
12856 /// <summary>
12857 /// Should this packet be handled asynchronously?
12858 /// </summary>
12859 public bool Async { get; set; }
12860
12861 /// <summary>
12862 /// If async is true, should this packet be handled in the async engine or given directly to a threadpool
12863 /// thread?
12864 /// </summary>
12865 public bool InEngine { get; set; }
12206 } 12866 }
12207 12867
12208 public class AsyncPacketProcess 12868 public class AsyncPacketProcess
@@ -12284,11 +12944,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12284 OutPacket(dialog, ThrottleOutPacketType.Task); 12944 OutPacket(dialog, ThrottleOutPacketType.Task);
12285 } 12945 }
12286 12946
12287 public void StopFlying(ISceneEntity p) 12947 public void SendAgentTerseUpdate(ISceneEntity p)
12288 { 12948 {
12289 if (p is ScenePresence) 12949 if (p is ScenePresence)
12290 { 12950 {
12291 ScenePresence presence = p as ScenePresence; 12951// m_log.DebugFormat(
12952// "[LLCLIENTVIEW]: Immediately sending terse agent update for {0} to {1} in {2}",
12953// p.Name, Name, Scene.Name);
12954
12292 // It turns out to get the agent to stop flying, you have to feed it stop flying velocities 12955 // It turns out to get the agent to stop flying, you have to feed it stop flying velocities
12293 // There's no explicit message to send the client to tell it to stop flying.. it relies on the 12956 // There's no explicit message to send the client to tell it to stop flying.. it relies on the
12294 // velocity, collision plane and avatar height 12957 // velocity, collision plane and avatar height
@@ -12296,34 +12959,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12296 // Add 1/6 the avatar's height to it's position so it doesn't shoot into the air 12959 // Add 1/6 the avatar's height to it's position so it doesn't shoot into the air
12297 // when the avatar stands up 12960 // when the avatar stands up
12298 12961
12299 Vector3 pos = presence.AbsolutePosition;
12300
12301 if (presence.Appearance.AvatarHeight != 127.0f)
12302 pos += new Vector3(0f, 0f, (presence.Appearance.AvatarHeight/6f));
12303 else
12304 pos += new Vector3(0f, 0f, (1.56f/6f));
12305
12306 presence.AbsolutePosition = pos;
12307
12308 // attach a suitable collision plane regardless of the actual situation to force the LLClient to land.
12309 // Collision plane below the avatar's position a 6th of the avatar's height is suitable.
12310 // Mind you, that this method doesn't get called if the avatar's velocity magnitude is greater then a
12311 // certain amount.. because the LLClient wouldn't land in that situation anyway.
12312
12313 // why are we still testing for this really old height value default???
12314 if (presence.Appearance.AvatarHeight != 127.0f)
12315 presence.CollisionPlane = new Vector4(0, 0, 0, pos.Z - presence.Appearance.AvatarHeight/6f);
12316 else
12317 presence.CollisionPlane = new Vector4(0, 0, 0, pos.Z - (1.56f/6f));
12318
12319
12320 ImprovedTerseObjectUpdatePacket.ObjectDataBlock block = 12962 ImprovedTerseObjectUpdatePacket.ObjectDataBlock block =
12321 CreateImprovedTerseBlock(p, false); 12963 CreateImprovedTerseBlock(p, false);
12322 12964
12323 const float TIME_DILATION = 1.0f; 12965 const float TIME_DILATION = 1.0f;
12324 ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f); 12966 ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f);
12325 12967
12326
12327 ImprovedTerseObjectUpdatePacket packet 12968 ImprovedTerseObjectUpdatePacket packet
12328 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket( 12969 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
12329 PacketType.ImprovedTerseObjectUpdate); 12970 PacketType.ImprovedTerseObjectUpdate);
@@ -12565,5 +13206,51 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12565 eq.Enqueue(BuildEvent("BulkUpdateInventory", 13206 eq.Enqueue(BuildEvent("BulkUpdateInventory",
12566 llsd), AgentId); 13207 llsd), AgentId);
12567 } 13208 }
13209
13210 private HashSet<string> m_outPacketsToDrop;
13211
13212 public bool AddOutPacketToDropSet(string packetName)
13213 {
13214 if (m_outPacketsToDrop == null)
13215 m_outPacketsToDrop = new HashSet<string>();
13216
13217 return m_outPacketsToDrop.Add(packetName);
13218 }
13219
13220 public bool RemoveOutPacketFromDropSet(string packetName)
13221 {
13222 if (m_outPacketsToDrop == null)
13223 return false;
13224
13225 return m_outPacketsToDrop.Remove(packetName);
13226 }
13227
13228 public HashSet<string> GetOutPacketDropSet()
13229 {
13230 return new HashSet<string>(m_outPacketsToDrop);
13231 }
13232
13233 private HashSet<string> m_inPacketsToDrop;
13234
13235 public bool AddInPacketToDropSet(string packetName)
13236 {
13237 if (m_inPacketsToDrop == null)
13238 m_inPacketsToDrop = new HashSet<string>();
13239
13240 return m_inPacketsToDrop.Add(packetName);
13241 }
13242
13243 public bool RemoveInPacketFromDropSet(string packetName)
13244 {
13245 if (m_inPacketsToDrop == null)
13246 return false;
13247
13248 return m_inPacketsToDrop.Remove(packetName);
13249 }
13250
13251 public HashSet<string> GetInPacketDropSet()
13252 {
13253 return new HashSet<string>(m_inPacketsToDrop);
13254 }
12568 } 13255 }
12569} 13256}
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 8963756..0394e54 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
@@ -31,6 +31,7 @@ using System.Net;
31using System.Threading; 31using System.Threading;
32using log4net; 32using log4net;
33using OpenSim.Framework; 33using OpenSim.Framework;
34using OpenSim.Framework.Monitoring;
34using OpenMetaverse; 35using OpenMetaverse;
35using OpenMetaverse.Packets; 36using OpenMetaverse.Packets;
36 37
@@ -75,12 +76,41 @@ namespace OpenSim.Region.ClientStack.LindenUDP
75 /// or removed, this number must also change</summary> 76 /// or removed, this number must also change</summary>
76 const int THROTTLE_CATEGORY_COUNT = 8; 77 const int THROTTLE_CATEGORY_COUNT = 8;
77 78
79 /// <summary>
80 /// Controls whether information is logged about each outbound packet immediately before it is sent. For debug purposes.
81 /// </summary>
82 /// <remarks>Any level above 0 will turn on logging.</remarks>
83 public int DebugDataOutLevel { get; set; }
84
85 /// <summary>
86 /// Controls whether information is logged about each outbound packet immediately before it is sent. For debug purposes.
87 /// </summary>
88 /// <remarks>Any level above 0 will turn on logging.</remarks>
89 public int ThrottleDebugLevel
90 {
91 get
92 {
93 return m_throttleDebugLevel;
94 }
95
96 set
97 {
98 m_throttleDebugLevel = value;
99 m_throttleClient.DebugLevel = m_throttleDebugLevel;
100 foreach (TokenBucket tb in m_throttleCategories)
101 tb.DebugLevel = m_throttleDebugLevel;
102 }
103 }
104 private int m_throttleDebugLevel;
105
78 /// <summary>Fired when updated networking stats are produced for this client</summary> 106 /// <summary>Fired when updated networking stats are produced for this client</summary>
79 public event PacketStats OnPacketStats; 107 public event PacketStats OnPacketStats;
80 /// <summary>Fired when the queue for a packet category is empty. This event can be 108 /// <summary>Fired when the queue for a packet category is empty. This event can be
81 /// hooked to put more data on the empty queue</summary> 109 /// hooked to put more data on the empty queue</summary>
82 public event QueueEmpty OnQueueEmpty; 110 public event QueueEmpty OnQueueEmpty;
83 111
112 public event Func<ThrottleOutPacketTypeFlags, bool> HasUpdates;
113
84 /// <summary>AgentID for this client</summary> 114 /// <summary>AgentID for this client</summary>
85 public readonly UUID AgentID; 115 public readonly UUID AgentID;
86 /// <summary>The remote address of the connected client</summary> 116 /// <summary>The remote address of the connected client</summary>
@@ -89,8 +119,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
89 public readonly uint CircuitCode; 119 public readonly uint CircuitCode;
90 /// <summary>Sequence numbers of packets we've received (for duplicate checking)</summary> 120 /// <summary>Sequence numbers of packets we've received (for duplicate checking)</summary>
91 public readonly IncomingPacketHistoryCollection PacketArchive = new IncomingPacketHistoryCollection(200); 121 public readonly IncomingPacketHistoryCollection PacketArchive = new IncomingPacketHistoryCollection(200);
122
123 /// <summary>
124 /// If true then we take action in response to unacked reliably sent packets such as resending the packet.
125 /// </summary>
126 public bool ProcessUnackedSends { get; set; }
127
92 /// <summary>Packets we have sent that need to be ACKed by the client</summary> 128 /// <summary>Packets we have sent that need to be ACKed by the client</summary>
93 public readonly UnackedPacketCollection NeedAcks = new UnackedPacketCollection(); 129 public readonly UnackedPacketCollection NeedAcks = new UnackedPacketCollection();
130
94 /// <summary>ACKs that are queued up, waiting to be sent to the client</summary> 131 /// <summary>ACKs that are queued up, waiting to be sent to the client</summary>
95 public readonly OpenSim.Framework.LocklessQueue<uint> PendingAcks = new OpenSim.Framework.LocklessQueue<uint>(); 132 public readonly OpenSim.Framework.LocklessQueue<uint> PendingAcks = new OpenSim.Framework.LocklessQueue<uint>();
96 133
@@ -141,8 +178,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
141 get { return m_throttleClient; } 178 get { return m_throttleClient; }
142 } 179 }
143 180
144 /// <summary>Throttle bucket for this agent's connection</summary>
145 private readonly TokenBucket m_throttleCategory;
146 /// <summary>Throttle buckets for each packet category</summary> 181 /// <summary>Throttle buckets for each packet category</summary>
147 private readonly TokenBucket[] m_throttleCategories; 182 private readonly TokenBucket[] m_throttleCategories;
148 /// <summary>Outgoing queues for throttled packets</summary> 183 /// <summary>Outgoing queues for throttled packets</summary>
@@ -160,6 +195,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
160 private int m_maxRTO = 60000; 195 private int m_maxRTO = 60000;
161 196
162 /// <summary> 197 /// <summary>
198 /// This is the percentage of the udp texture queue to add to the task queue since
199 /// textures are now generally handled through http.
200 /// </summary>
201 private double m_cannibalrate = 0.0;
202
203 private ClientInfo m_info = new ClientInfo();
204
205 /// <summary>
163 /// Default constructor 206 /// Default constructor
164 /// </summary> 207 /// </summary>
165 /// <param name="server">Reference to the UDP server this client is connected to</param> 208 /// <param name="server">Reference to the UDP server this client is connected to</param>
@@ -189,21 +232,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP
189 if (maxRTO != 0) 232 if (maxRTO != 0)
190 m_maxRTO = maxRTO; 233 m_maxRTO = maxRTO;
191 234
235 ProcessUnackedSends = true;
236
192 // Create a token bucket throttle for this client that has the scene token bucket as a parent 237 // Create a token bucket throttle for this client that has the scene token bucket as a parent
193 m_throttleClient = new AdaptiveTokenBucket(parentThrottle, rates.Total, rates.AdaptiveThrottlesEnabled); 238 m_throttleClient
194 // Create a token bucket throttle for the total categary with the client bucket as a throttle 239 = new AdaptiveTokenBucket(
195 m_throttleCategory = new TokenBucket(m_throttleClient, 0); 240 string.Format("adaptive throttle for {0} in {1}", AgentID, server.Scene.Name),
241 parentThrottle, 0, rates.Total, rates.MinimumAdaptiveThrottleRate, rates.AdaptiveThrottlesEnabled);
242
196 // Create an array of token buckets for this clients different throttle categories 243 // Create an array of token buckets for this clients different throttle categories
197 m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; 244 m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT];
198 245
246 m_cannibalrate = rates.CannibalizeTextureRate;
247
199 for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) 248 for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
200 { 249 {
201 ThrottleOutPacketType type = (ThrottleOutPacketType)i; 250 ThrottleOutPacketType type = (ThrottleOutPacketType)i;
202 251
203 // Initialize the packet outboxes, where packets sit while they are waiting for tokens 252 // Initialize the packet outboxes, where packets sit while they are waiting for tokens
204 m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>(); 253 m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>();
254
205 // Initialize the token buckets that control the throttling for each category 255 // Initialize the token buckets that control the throttling for each category
206 m_throttleCategories[i] = new TokenBucket(m_throttleCategory, rates.GetRate(type)); 256 m_throttleCategories[i]
257 = new TokenBucket(
258 string.Format("{0} throttle for {1} in {2}", type, AgentID, server.Scene.Name),
259 m_throttleClient, rates.GetRate(type), 0);
207 } 260 }
208 261
209 // Default the retransmission timeout to one second 262 // Default the retransmission timeout to one second
@@ -240,20 +293,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
240 // TODO: This data structure is wrong in so many ways. Locking and copying the entire lists 293 // TODO: This data structure is wrong in so many ways. Locking and copying the entire lists
241 // of pending and needed ACKs for every client every time some method wants information about 294 // of pending and needed ACKs for every client every time some method wants information about
242 // this connection is a recipe for poor performance 295 // this connection is a recipe for poor performance
243 ClientInfo info = new ClientInfo(); 296
244 info.pendingAcks = new Dictionary<uint, uint>(); 297 m_info.resendThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate;
245 info.needAck = new Dictionary<uint, byte[]>(); 298 m_info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate;
246 299 m_info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate;
247 info.resendThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate; 300 m_info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate;
248 info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; 301 m_info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate;
249 info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; 302 m_info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate;
250 info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; 303 m_info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate;
251 info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; 304 m_info.totalThrottle = (int)m_throttleClient.DripRate;
252 info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; 305 m_info.targetThrottle = (int)m_throttleClient.TargetDripRate;
253 info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; 306 m_info.maxThrottle = (int)m_throttleClient.MaxDripRate;
254 info.totalThrottle = (int)m_throttleCategory.DripRate; 307
255 308 return m_info;
256 return info;
257 } 309 }
258 310
259 /// <summary> 311 /// <summary>
@@ -269,6 +321,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP
269 } 321 }
270 322
271 /// <summary> 323 /// <summary>
324 /// Get the total number of pakcets queued for this client.
325 /// </summary>
326 /// <returns></returns>
327 public int GetTotalPacketsQueuedCount()
328 {
329 int total = 0;
330
331 for (int i = 0; i <= (int)ThrottleOutPacketType.Asset; i++)
332 total += m_packetOutboxes[i].Count;
333
334 return total;
335 }
336
337 /// <summary>
338 /// Get the number of packets queued for the given throttle type.
339 /// </summary>
340 /// <returns></returns>
341 /// <param name="throttleType"></param>
342 public int GetPacketsQueuedCount(ThrottleOutPacketType throttleType)
343 {
344 if ((int)throttleType > 0)
345 return m_packetOutboxes[(int)throttleType].Count;
346 else
347 return 0;
348 }
349
350 /// <summary>
272 /// Return statistics information about client packet queues. 351 /// Return statistics information about client packet queues.
273 /// </summary> 352 /// </summary>
274 /// <remarks> 353 /// <remarks>
@@ -278,7 +357,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
278 public string GetStats() 357 public string GetStats()
279 { 358 {
280 return string.Format( 359 return string.Format(
281 "{0,7} {1,7} {2,7} {3,9} {4,7} {5,7} {6,7} {7,7} {8,7} {9,8} {10,7} {11,7} {12,7}", 360 "{0,7} {1,7} {2,7} {3,9} {4,7} {5,7} {6,7} {7,7} {8,7} {9,8} {10,7} {11,7}",
282 Util.EnvironmentTickCountSubtract(TickLastPacketReceived), 361 Util.EnvironmentTickCountSubtract(TickLastPacketReceived),
283 PacketsReceived, 362 PacketsReceived,
284 PacketsSent, 363 PacketsSent,
@@ -290,8 +369,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
290 m_packetOutboxes[(int)ThrottleOutPacketType.Cloud].Count, 369 m_packetOutboxes[(int)ThrottleOutPacketType.Cloud].Count,
291 m_packetOutboxes[(int)ThrottleOutPacketType.Task].Count, 370 m_packetOutboxes[(int)ThrottleOutPacketType.Task].Count,
292 m_packetOutboxes[(int)ThrottleOutPacketType.Texture].Count, 371 m_packetOutboxes[(int)ThrottleOutPacketType.Texture].Count,
293 m_packetOutboxes[(int)ThrottleOutPacketType.Asset].Count, 372 m_packetOutboxes[(int)ThrottleOutPacketType.Asset].Count);
294 m_packetOutboxes[(int)ThrottleOutPacketType.State].Count);
295 } 373 }
296 374
297 public void SendPacketStats() 375 public void SendPacketStats()
@@ -337,8 +415,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
337 int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; 415 int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
338 int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; 416 int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
339 int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); 417 int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
340 // State is a subcategory of task that we allocate a percentage to 418
341 int state = 0; 419 if (ThrottleDebugLevel > 0)
420 {
421 long total = resend + land + wind + cloud + task + texture + asset;
422 m_log.DebugFormat(
423 "[LLUDPCLIENT]: {0} is setting throttles in {1} to Resend={2}, Land={3}, Wind={4}, Cloud={5}, Task={6}, Texture={7}, Asset={8}, TOTAL = {9}",
424 AgentID, m_udpServer.Scene.Name, resend, land, wind, cloud, task, texture, asset, total);
425 }
342 426
343 // Make sure none of the throttles are set below our packet MTU, 427 // Make sure none of the throttles are set below our packet MTU,
344 // otherwise a throttle could become permanently clogged 428 // otherwise a throttle could become permanently clogged
@@ -350,11 +434,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP
350 texture = Math.Max(texture, LLUDPServer.MTU); 434 texture = Math.Max(texture, LLUDPServer.MTU);
351 asset = Math.Max(asset, LLUDPServer.MTU); 435 asset = Math.Max(asset, LLUDPServer.MTU);
352 436
437 // Since most textures are now delivered through http, make it possible
438 // to cannibalize some of the bw from the texture throttle to use for
439 // the task queue (e.g. object updates)
440 task = task + (int)(m_cannibalrate * texture);
441 texture = (int)((1 - m_cannibalrate) * texture);
442
353 //int total = resend + land + wind + cloud + task + texture + asset; 443 //int total = resend + land + wind + cloud + task + texture + asset;
354 //m_log.DebugFormat("[LLUDPCLIENT]: {0} is setting throttles. Resend={1}, Land={2}, Wind={3}, Cloud={4}, Task={5}, Texture={6}, Asset={7}, Total={8}", 444
355 // AgentID, resend, land, wind, cloud, task, texture, asset, total); 445 if (ThrottleDebugLevel > 0)
446 {
447 long total = resend + land + wind + cloud + task + texture + asset;
448 m_log.DebugFormat(
449 "[LLUDPCLIENT]: {0} is setting throttles in {1} to Resend={2}, Land={3}, Wind={4}, Cloud={5}, Task={6}, Texture={7}, Asset={8}, TOTAL = {9}",
450 AgentID, m_udpServer.Scene.Name, resend, land, wind, cloud, task, texture, asset, total);
451 }
356 452
357 // Update the token buckets with new throttle values 453 // Update the token buckets with new throttle values
454 if (m_throttleClient.AdaptiveEnabled)
455 {
456 long total = resend + land + wind + cloud + task + texture + asset;
457 m_throttleClient.TargetDripRate = total;
458 }
459
358 TokenBucket bucket; 460 TokenBucket bucket;
359 461
360 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend]; 462 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend];
@@ -375,9 +477,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
375 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task]; 477 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task];
376 bucket.RequestedDripRate = task; 478 bucket.RequestedDripRate = task;
377 479
378 bucket = m_throttleCategories[(int)ThrottleOutPacketType.State];
379 bucket.RequestedDripRate = state;
380
381 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture]; 480 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture];
382 bucket.RequestedDripRate = texture; 481 bucket.RequestedDripRate = texture;
383 482
@@ -620,15 +719,45 @@ namespace OpenSim.Region.ClientStack.LindenUDP
620 /// <param name="categories">Throttle categories to fire the callback for</param> 719 /// <param name="categories">Throttle categories to fire the callback for</param>
621 private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories) 720 private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories)
622 { 721 {
623 if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty) 722// if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty)
723 if (!m_isQueueEmptyRunning && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty)
624 { 724 {
725 m_isQueueEmptyRunning = true;
726
727 int start = Environment.TickCount & Int32.MaxValue;
728 const int MIN_CALLBACK_MS = 30;
729
730 m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
731 if (m_nextOnQueueEmpty == 0)
732 m_nextOnQueueEmpty = 1;
733
625 // Use a value of 0 to signal that FireQueueEmpty is running 734 // Use a value of 0 to signal that FireQueueEmpty is running
626 m_nextOnQueueEmpty = 0; 735// m_nextOnQueueEmpty = 0;
627 // Asynchronously run the callback 736
628 Util.FireAndForget(FireQueueEmpty, categories); 737 m_categories = categories;
738
739 if (HasUpdates(m_categories))
740 {
741 if (!m_udpServer.OqrEngine.IsRunning)
742 {
743 // Asynchronously run the callback
744 Util.FireAndForget(FireQueueEmpty, categories, "LLUDPClient.BeginFireQueueEmpty");
745 }
746 else
747 {
748 m_udpServer.OqrEngine.QueueJob(AgentID.ToString(), () => FireQueueEmpty(categories));
749 }
750 }
751 else
752 {
753 m_isQueueEmptyRunning = false;
754 }
629 } 755 }
630 } 756 }
631 757
758 private bool m_isQueueEmptyRunning;
759 private ThrottleOutPacketTypeFlags m_categories = 0;
760
632 /// <summary> 761 /// <summary>
633 /// Fires the OnQueueEmpty callback and sets the minimum time that it 762 /// Fires the OnQueueEmpty callback and sets the minimum time that it
634 /// can be called again 763 /// can be called again
@@ -636,24 +765,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP
636 /// <param name="o">Throttle categories to fire the callback for, 765 /// <param name="o">Throttle categories to fire the callback for,
637 /// stored as an object to match the WaitCallback delegate 766 /// stored as an object to match the WaitCallback delegate
638 /// signature</param> 767 /// signature</param>
639 private void FireQueueEmpty(object o) 768 public void FireQueueEmpty(object o)
640 { 769 {
641 const int MIN_CALLBACK_MS = 30; 770// m_log.DebugFormat("[LLUDPCLIENT]: FireQueueEmpty for {0} in {1}", AgentID, m_udpServer.Scene.Name);
642 771
643 ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o; 772// int start = Environment.TickCount & Int32.MaxValue;
644 QueueEmpty callback = OnQueueEmpty; 773// const int MIN_CALLBACK_MS = 30;
645
646 int start = Environment.TickCount & Int32.MaxValue;
647 774
648 if (callback != null) 775// if (m_udpServer.IsRunningOutbound)
649 { 776// {
650 try { callback(categories); } 777 ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o;
651 catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); } 778 QueueEmpty callback = OnQueueEmpty;
652 } 779
780 if (callback != null)
781 {
782// if (m_udpServer.IsRunningOutbound)
783// {
784 try { callback(categories); }
785 catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); }
786// }
787 }
788// }
789
790// m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
791// if (m_nextOnQueueEmpty == 0)
792// m_nextOnQueueEmpty = 1;
793
794// }
653 795
654 m_nextOnQueueEmpty = start + MIN_CALLBACK_MS; 796 m_isQueueEmptyRunning = false;
655 if (m_nextOnQueueEmpty == 0)
656 m_nextOnQueueEmpty = 1;
657 } 797 }
658 798
659 /// <summary> 799 /// <summary>
@@ -678,9 +818,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
678 Texture = 5, 818 Texture = 5,
679 /// <summary>Non-texture assets</summary> 819 /// <summary>Non-texture assets</summary>
680 Asset = 6, 820 Asset = 6,
681 /// <summary>Avatar and primitive data</summary>
682 /// <remarks>This is a sub-category of Task</remarks>
683 State = 7,
684 */ 821 */
685 822
686 switch (category) 823 switch (category)
@@ -697,11 +834,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
697 return ThrottleOutPacketTypeFlags.Texture; 834 return ThrottleOutPacketTypeFlags.Texture;
698 case ThrottleOutPacketType.Asset: 835 case ThrottleOutPacketType.Asset:
699 return ThrottleOutPacketTypeFlags.Asset; 836 return ThrottleOutPacketTypeFlags.Asset;
700 case ThrottleOutPacketType.State:
701 return ThrottleOutPacketTypeFlags.State;
702 default: 837 default:
703 return 0; 838 return 0;
704 } 839 }
705 } 840 }
706 } 841 }
707} \ No newline at end of file 842}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
index a7628d2..4528714 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -40,8 +40,9 @@ using OpenSim.Framework;
40using OpenSim.Framework.Console; 40using OpenSim.Framework.Console;
41using OpenSim.Framework.Monitoring; 41using OpenSim.Framework.Monitoring;
42using OpenSim.Region.Framework.Scenes; 42using OpenSim.Region.Framework.Scenes;
43using OpenSim.Region.Framework.Interfaces;
43using OpenMetaverse; 44using OpenMetaverse;
44 45using Mono.Addins;
45using TokenBucket = OpenSim.Region.ClientStack.LindenUDP.TokenBucket; 46using TokenBucket = OpenSim.Region.ClientStack.LindenUDP.TokenBucket;
46 47
47namespace OpenSim.Region.ClientStack.LindenUDP 48namespace OpenSim.Region.ClientStack.LindenUDP
@@ -49,22 +50,58 @@ namespace OpenSim.Region.ClientStack.LindenUDP
49 /// <summary> 50 /// <summary>
50 /// A shim around LLUDPServer that implements the IClientNetworkServer interface 51 /// A shim around LLUDPServer that implements the IClientNetworkServer interface
51 /// </summary> 52 /// </summary>
52 public sealed class LLUDPServerShim : IClientNetworkServer 53 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "LLUDPServerShim")]
54 public sealed class LLUDPServerShim : INonSharedRegionModule
53 { 55 {
56 private bool m_Enabled = true;
57 private IConfigSource m_Config;
54 LLUDPServer m_udpServer; 58 LLUDPServer m_udpServer;
55 59
56 public LLUDPServerShim() 60 #region INonSharedRegionModule
61 public string Name
57 { 62 {
63 get { return "LLUDPServerShim"; }
58 } 64 }
59 65
60 public void Initialise(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) 66 public Type ReplaceableInterface
61 { 67 {
62 m_udpServer = new LLUDPServer(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager); 68 get { return null; }
63 } 69 }
64 70
65 public void NetworkStop() 71 public void Initialise(IConfigSource source)
66 { 72 {
67 m_udpServer.Stop(); 73 m_Config = source;
74 }
75
76 public void Close()
77 {
78 }
79
80 public void AddRegion(Scene scene)
81 {
82 uint port = (uint)scene.RegionInfo.InternalEndPoint.Port;
83
84 IPAddress listenIP = scene.RegionInfo.InternalEndPoint.Address;
85 Initialise(listenIP, ref port, scene.RegionInfo.ProxyOffset, scene.RegionInfo.m_allow_alternate_ports, m_Config, scene.AuthenticateHandler);
86 scene.RegionInfo.InternalEndPoint.Port = (int)port;
87
88 AddScene(scene);
89 }
90
91 public void RemoveRegion(Scene scene)
92 {
93 Stop();
94 }
95
96 public void RegionLoaded(Scene scene)
97 {
98 Start();
99 }
100 #endregion
101
102 public void Initialise(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager)
103 {
104 m_udpServer = new LLUDPServer(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager);
68 } 105 }
69 106
70 public void AddScene(IScene scene) 107 public void AddScene(IScene scene)
@@ -73,9 +110,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP
73 110
74 StatsManager.RegisterStat( 111 StatsManager.RegisterStat(
75 new Stat( 112 new Stat(
113 "ClientLogoutsDueToNoReceives",
114 "Number of times a client has been logged out because no packets were received before the timeout.",
115 "",
116 "",
117 "clientstack",
118 scene.Name,
119 StatType.Pull,
120 MeasuresOfInterest.None,
121 stat => stat.Value = m_udpServer.ClientLogoutsDueToNoReceives,
122 StatVerbosity.Debug));
123
124 StatsManager.RegisterStat(
125 new Stat(
126 "IncomingUDPReceivesCount",
127 "Number of UDP receives performed",
128 "",
129 "",
130 "clientstack",
131 scene.Name,
132 StatType.Pull,
133 MeasuresOfInterest.AverageChangeOverTime,
134 stat => stat.Value = m_udpServer.UdpReceives,
135 StatVerbosity.Debug));
136
137 StatsManager.RegisterStat(
138 new Stat(
76 "IncomingPacketsProcessedCount", 139 "IncomingPacketsProcessedCount",
77 "Number of inbound UDP packets processed", 140 "Number of inbound LL protocol packets processed",
78 "Number of inbound UDP packets processed", 141 "",
79 "", 142 "",
80 "clientstack", 143 "clientstack",
81 scene.Name, 144 scene.Name,
@@ -83,6 +146,86 @@ namespace OpenSim.Region.ClientStack.LindenUDP
83 MeasuresOfInterest.AverageChangeOverTime, 146 MeasuresOfInterest.AverageChangeOverTime,
84 stat => stat.Value = m_udpServer.IncomingPacketsProcessed, 147 stat => stat.Value = m_udpServer.IncomingPacketsProcessed,
85 StatVerbosity.Debug)); 148 StatVerbosity.Debug));
149
150 StatsManager.RegisterStat(
151 new Stat(
152 "IncomingPacketsMalformedCount",
153 "Number of inbound UDP packets that could not be recognized as LL protocol packets.",
154 "",
155 "",
156 "clientstack",
157 scene.Name,
158 StatType.Pull,
159 MeasuresOfInterest.AverageChangeOverTime,
160 stat => stat.Value = m_udpServer.IncomingMalformedPacketCount,
161 StatVerbosity.Info));
162
163 StatsManager.RegisterStat(
164 new Stat(
165 "IncomingPacketsOrphanedCount",
166 "Number of inbound packets that were not initial connections packets and could not be associated with a viewer.",
167 "",
168 "",
169 "clientstack",
170 scene.Name,
171 StatType.Pull,
172 MeasuresOfInterest.AverageChangeOverTime,
173 stat => stat.Value = m_udpServer.IncomingOrphanedPacketCount,
174 StatVerbosity.Info));
175
176 StatsManager.RegisterStat(
177 new Stat(
178 "IncomingPacketsResentCount",
179 "Number of inbound packets that clients indicate are resends.",
180 "",
181 "",
182 "clientstack",
183 scene.Name,
184 StatType.Pull,
185 MeasuresOfInterest.AverageChangeOverTime,
186 stat => stat.Value = m_udpServer.IncomingPacketsResentCount,
187 StatVerbosity.Debug));
188
189 StatsManager.RegisterStat(
190 new Stat(
191 "OutgoingUDPSendsCount",
192 "Number of UDP sends performed",
193 "",
194 "",
195 "clientstack",
196 scene.Name,
197 StatType.Pull,
198 MeasuresOfInterest.AverageChangeOverTime,
199 stat => stat.Value = m_udpServer.UdpSends,
200 StatVerbosity.Debug));
201
202 StatsManager.RegisterStat(
203 new Stat(
204 "OutgoingPacketsResentCount",
205 "Number of packets resent because a client did not acknowledge receipt",
206 "",
207 "",
208 "clientstack",
209 scene.Name,
210 StatType.Pull,
211 MeasuresOfInterest.AverageChangeOverTime,
212 stat => stat.Value = m_udpServer.PacketsResentCount,
213 StatVerbosity.Debug));
214
215 StatsManager.RegisterStat(
216 new Stat(
217 "AverageUDPProcessTime",
218 "Average number of milliseconds taken to process each incoming UDP packet in a sample.",
219 "This is for initial receive processing which is separate from the later client LL packet processing stage.",
220 "ms",
221 "clientstack",
222 scene.Name,
223 StatType.Pull,
224 MeasuresOfInterest.None,
225 stat => stat.Value = m_udpServer.AverageReceiveTicksForLastSamplePeriod,
226// stat =>
227// stat.Value = Math.Round(m_udpServer.AverageReceiveTicksForLastSamplePeriod, 7),
228 StatVerbosity.Debug));
86 } 229 }
87 230
88 public bool HandlesRegion(Location x) 231 public bool HandlesRegion(Location x)
@@ -99,6 +242,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
99 { 242 {
100 m_udpServer.Stop(); 243 m_udpServer.Stop();
101 } 244 }
245
102 } 246 }
103 247
104 /// <summary> 248 /// <summary>
@@ -107,10 +251,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP
107 /// </summary> 251 /// </summary>
108 public class LLUDPServer : OpenSimUDPBase 252 public class LLUDPServer : OpenSimUDPBase
109 { 253 {
254 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
255
110 /// <summary>Maximum transmission unit, or UDP packet size, for the LLUDP protocol</summary> 256 /// <summary>Maximum transmission unit, or UDP packet size, for the LLUDP protocol</summary>
111 public const int MTU = 1400; 257 public const int MTU = 1400;
112 258
113 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 259 /// <summary>Number of forced client logouts due to no receipt of packets before timeout.</summary>
260 public int ClientLogoutsDueToNoReceives { get; private set; }
261
262 /// <summary>
263 /// Default packet debug level given to new clients
264 /// </summary>
265 public int DefaultClientPacketDebugLevel { get; set; }
266
267 /// <summary>
268 /// If set then all inbound agent updates are discarded. For debugging purposes.
269 /// discard agent update.
270 /// </summary>
271 public bool DiscardInboundAgentUpdates { get; set; }
114 272
115 /// <summary>The measured resolution of Environment.TickCount</summary> 273 /// <summary>The measured resolution of Environment.TickCount</summary>
116 public readonly float TickCountResolution; 274 public readonly float TickCountResolution;
@@ -128,19 +286,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
128 /// <summary>Incoming packets that are awaiting handling</summary> 286 /// <summary>Incoming packets that are awaiting handling</summary>
129 private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>(); 287 private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>();
130 288
131 /// <summary></summary>
132 //private UDPClientCollection m_clients = new UDPClientCollection();
133 /// <summary>Bandwidth throttle for this UDP server</summary> 289 /// <summary>Bandwidth throttle for this UDP server</summary>
134 protected TokenBucket m_throttle; 290 public TokenBucket Throttle { get; private set; }
135 291
136 /// <summary>Bandwidth throttle rates for this UDP server</summary> 292 /// <summary>Per client throttle rates enforced by this server</summary>
293 /// <remarks>
294 /// If the total rate is non-zero, then this is the maximum total throttle setting that any client can ever have.
295 /// The other rates (resend, asset, etc.) are the defaults for a new client and can be changed (and usually
296 /// do get changed immediately). They do not need to sum to the total.
297 /// </remarks>
137 public ThrottleRates ThrottleRates { get; private set; } 298 public ThrottleRates ThrottleRates { get; private set; }
138 299
139 /// <summary>Manages authentication for agent circuits</summary> 300 /// <summary>Manages authentication for agent circuits</summary>
140 private AgentCircuitManager m_circuitManager; 301 private AgentCircuitManager m_circuitManager;
141 302
142 /// <summary>Reference to the scene this UDP server is attached to</summary> 303 /// <summary>Reference to the scene this UDP server is attached to</summary>
143 protected Scene m_scene; 304 public Scene Scene { get; private set; }
144 305
145 /// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary> 306 /// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary>
146 private Location m_location; 307 private Location m_location;
@@ -181,6 +342,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
181 /// <summary>Flag to signal when clients should send pings</summary> 342 /// <summary>Flag to signal when clients should send pings</summary>
182 protected bool m_sendPing; 343 protected bool m_sendPing;
183 344
345 /// <summary>
346 /// Event used to signal when queued packets are available for sending.
347 /// </summary>
348 /// <remarks>
349 /// This allows the outbound loop to only operate when there is data to send rather than continuously polling.
350 /// Some data is sent immediately and not queued. That data would not trigger this event.
351 /// </remarks>
352 private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false);
353
184 private Pool<IncomingPacket> m_incomingPacketPool; 354 private Pool<IncomingPacket> m_incomingPacketPool;
185 355
186 /// <summary> 356 /// <summary>
@@ -201,7 +371,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP
201 371
202 public Socket Server { get { return null; } } 372 public Socket Server { get { return null; } }
203 373
204 private int m_malformedCount = 0; // Guard against a spamming attack 374 /// <summary>
375 /// Record how many packets have been resent
376 /// </summary>
377 internal int PacketsResentCount { get; set; }
378
379 /// <summary>
380 /// Record how many packets have been sent
381 /// </summary>
382 internal int PacketsSentCount { get; set; }
383
384 /// <summary>
385 /// Record how many incoming packets are indicated as resends by clients.
386 /// </summary>
387 internal int IncomingPacketsResentCount { get; set; }
388
389 /// <summary>
390 /// Record how many inbound packets could not be recognized as LLUDP packets.
391 /// </summary>
392 public int IncomingMalformedPacketCount { get; private set; }
393
394 /// <summary>
395 /// Record how many inbound packets could not be associated with a simulator circuit.
396 /// </summary>
397 public int IncomingOrphanedPacketCount { get; private set; }
205 398
206 /// <summary> 399 /// <summary>
207 /// Record current outgoing client for monitoring purposes. 400 /// Record current outgoing client for monitoring purposes.
@@ -213,6 +406,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
213 /// </summary> 406 /// </summary>
214 private IClientAPI m_currentIncomingClient; 407 private IClientAPI m_currentIncomingClient;
215 408
409 /// <summary>
410 /// Queue some low priority but potentially high volume async requests so that they don't overwhelm available
411 /// threadpool threads.
412 /// </summary>
413 public JobEngine IpahEngine { get; private set; }
414
415 /// <summary>
416 /// Run queue empty processing within a single persistent thread.
417 /// </summary>
418 /// <remarks>
419 /// This is the alternative to having every
420 /// connection schedule its own job in the threadpool which causes performance problems when there are many
421 /// connections.
422 /// </remarks>
423 public JobEngine OqrEngine { get; private set; }
424
216 public LLUDPServer( 425 public LLUDPServer(
217 IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, 426 IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port,
218 IConfigSource configSource, AgentCircuitManager circuitManager) 427 IConfigSource configSource, AgentCircuitManager circuitManager)
@@ -278,27 +487,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
278 m_shouldCollectStats = false; 487 m_shouldCollectStats = false;
279 if (config != null) 488 if (config != null)
280 { 489 {
281 if (config.Contains("enabled") && config.GetBoolean("enabled")) 490 m_shouldCollectStats = config.GetBoolean("Enabled", false);
282 { 491 binStatsMaxFilesize = TimeSpan.FromSeconds(config.GetInt("packet_headers_period_seconds", 300));
283 if (config.Contains("collect_packet_headers")) 492 binStatsDir = config.GetString("stats_dir", ".");
284 m_shouldCollectStats = config.GetBoolean("collect_packet_headers"); 493 m_aggregatedBWStats = config.GetBoolean("aggregatedBWStats", false);
285 if (config.Contains("packet_headers_period_seconds")) 494 }
286 { 495 #endregion BinaryStats
287 binStatsMaxFilesize = TimeSpan.FromSeconds(config.GetInt("region_stats_period_seconds")); 496
288 } 497 // FIXME: Can't add info here because don't know scene yet.
289 if (config.Contains("stats_dir")) 498// m_throttle
290 { 499// = new TokenBucket(
291 binStatsDir = config.GetString("stats_dir"); 500// string.Format("server throttle bucket for {0}", Scene.Name), null, sceneThrottleBps);
292 } 501
293 } 502 Throttle = new TokenBucket("server throttle bucket", null, 0, sceneThrottleBps);
294 else 503
295 {
296 m_shouldCollectStats = false;
297 }
298 }
299 #endregion BinaryStats
300
301 m_throttle = new TokenBucket(null, sceneThrottleBps);
302 ThrottleRates = new ThrottleRates(configSource); 504 ThrottleRates = new ThrottleRates(configSource);
303 505
304 if (usePools) 506 if (usePools)
@@ -309,11 +511,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
309 { 511 {
310 StartInbound(); 512 StartInbound();
311 StartOutbound(); 513 StartOutbound();
514 IpahEngine.Start();
515 OqrEngine.Start();
312 516
313 m_elapsedMSSinceLastStatReport = Environment.TickCount; 517 m_elapsedMSSinceLastStatReport = Environment.TickCount;
314 } 518 }
315 519
316 private void StartInbound() 520 public void StartInbound()
317 { 521 {
318 m_log.InfoFormat( 522 m_log.InfoFormat(
319 "[LLUDPSERVER]: Starting inbound packet processing for the LLUDP server in {0} mode with UsePools = {1}", 523 "[LLUDPSERVER]: Starting inbound packet processing for the LLUDP server in {0} mode with UsePools = {1}",
@@ -322,9 +526,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
322 base.StartInbound(m_recvBufferSize, m_asyncPacketHandling); 526 base.StartInbound(m_recvBufferSize, m_asyncPacketHandling);
323 527
324 // This thread will process the packets received that are placed on the packetInbox 528 // This thread will process the packets received that are placed on the packetInbox
325 Watchdog.StartThread( 529 WorkManager.StartThread(
326 IncomingPacketHandler, 530 IncomingPacketHandler,
327 string.Format("Incoming Packets ({0})", m_scene.RegionInfo.RegionName), 531 string.Format("Incoming Packets ({0})", Scene.Name),
328 ThreadPriority.Normal, 532 ThreadPriority.Normal,
329 false, 533 false,
330 true, 534 true,
@@ -332,15 +536,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
332 Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS); 536 Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS);
333 } 537 }
334 538
335 private new void StartOutbound() 539 public override void StartOutbound()
336 { 540 {
337 m_log.Info("[LLUDPSERVER]: Starting outbound packet processing for the LLUDP server"); 541 m_log.Info("[LLUDPSERVER]: Starting outbound packet processing for the LLUDP server");
338 542
339 base.StartOutbound(); 543 base.StartOutbound();
340 544
341 Watchdog.StartThread( 545 WorkManager.StartThread(
342 OutgoingPacketHandler, 546 OutgoingPacketHandler,
343 string.Format("Outgoing Packets ({0})", m_scene.RegionInfo.RegionName), 547 string.Format("Outgoing Packets ({0})", Scene.Name),
344 ThreadPriority.Normal, 548 ThreadPriority.Normal,
345 false, 549 false,
346 true, 550 true,
@@ -350,12 +554,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
350 554
351 public void Stop() 555 public void Stop()
352 { 556 {
353 m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + m_scene.RegionInfo.RegionName); 557 m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + Scene.Name);
354 base.StopOutbound(); 558 base.StopOutbound();
355 base.StopInbound(); 559 base.StopInbound();
560 IpahEngine.Stop();
561 OqrEngine.Stop();
356 } 562 }
357 563
358 protected override bool EnablePools() 564 public override bool EnablePools()
359 { 565 {
360 if (!UsePools) 566 if (!UsePools)
361 { 567 {
@@ -369,7 +575,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
369 return false; 575 return false;
370 } 576 }
371 577
372 protected override bool DisablePools() 578 public override bool DisablePools()
373 { 579 {
374 if (UsePools) 580 if (UsePools)
375 { 581 {
@@ -389,7 +595,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
389 /// This is a seperate method so that it can be called once we have an m_scene to distinguish different scene 595 /// This is a seperate method so that it can be called once we have an m_scene to distinguish different scene
390 /// stats. 596 /// stats.
391 /// </summary> 597 /// </summary>
392 private void EnablePoolStats() 598 protected internal void EnablePoolStats()
393 { 599 {
394 m_poolCountStat 600 m_poolCountStat
395 = new Stat( 601 = new Stat(
@@ -398,7 +604,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
398 "The number of objects currently stored within the UDPPacketBuffer pool", 604 "The number of objects currently stored within the UDPPacketBuffer pool",
399 "", 605 "",
400 "clientstack", 606 "clientstack",
401 m_scene.Name, 607 Scene.Name,
402 StatType.Pull, 608 StatType.Pull,
403 stat => stat.Value = Pool.Count, 609 stat => stat.Value = Pool.Count,
404 StatVerbosity.Debug); 610 StatVerbosity.Debug);
@@ -412,7 +618,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
412 "The number of objects currently stored within the incoming packet pool", 618 "The number of objects currently stored within the incoming packet pool",
413 "", 619 "",
414 "clientstack", 620 "clientstack",
415 m_scene.Name, 621 Scene.Name,
416 StatType.Pull, 622 StatType.Pull,
417 stat => stat.Value = m_incomingPacketPool.Count, 623 stat => stat.Value = m_incomingPacketPool.Count,
418 StatVerbosity.Debug); 624 StatVerbosity.Debug);
@@ -423,7 +629,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
423 /// <summary> 629 /// <summary>
424 /// Disables pool stats. 630 /// Disables pool stats.
425 /// </summary> 631 /// </summary>
426 private void DisablePoolStats() 632 protected internal void DisablePoolStats()
427 { 633 {
428 StatsManager.DeregisterStat(m_poolCountStat); 634 StatsManager.DeregisterStat(m_poolCountStat);
429 m_poolCountStat = null; 635 m_poolCountStat = null;
@@ -456,7 +662,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
456 662
457 public void AddScene(IScene scene) 663 public void AddScene(IScene scene)
458 { 664 {
459 if (m_scene != null) 665 if (Scene != null)
460 { 666 {
461 m_log.Error("[LLUDPSERVER]: AddScene() called on an LLUDPServer that already has a scene"); 667 m_log.Error("[LLUDPSERVER]: AddScene() called on an LLUDPServer that already has a scene");
462 return; 668 return;
@@ -468,8 +674,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP
468 return; 674 return;
469 } 675 }
470 676
471 m_scene = (Scene)scene; 677 Scene = (Scene)scene;
472 m_location = new Location(m_scene.RegionInfo.RegionHandle); 678 m_location = new Location(Scene.RegionInfo.RegionHandle);
679
680 IpahEngine
681 = new JobEngine(
682 string.Format("Incoming Packet Async Handling Engine ({0})", Scene.Name),
683 "INCOMING PACKET ASYNC HANDLING ENGINE");
684
685 OqrEngine
686 = new JobEngine(
687 string.Format("Outgoing Queue Refill Engine ({0})", Scene.Name),
688 "OUTGOING QUEUE REFILL ENGINE");
689
690 StatsManager.RegisterStat(
691 new Stat(
692 "InboxPacketsCount",
693 "Number of LL protocol packets waiting for the second stage of processing after initial receive.",
694 "Number of LL protocol packets waiting for the second stage of processing after initial receive.",
695 "",
696 "clientstack",
697 scene.Name,
698 StatType.Pull,
699 MeasuresOfInterest.AverageChangeOverTime,
700 stat => stat.Value = packetInbox.Count,
701 StatVerbosity.Debug));
473 702
474 // XXX: These stats are also pool stats but we register them separately since they are currently not 703 // XXX: These stats are also pool stats but we register them separately since they are currently not
475 // turned on and off by EnablePools()/DisablePools() 704 // turned on and off by EnablePools()/DisablePools()
@@ -479,7 +708,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
479 "Packets reused", 708 "Packets reused",
480 "Number of packets reused out of all requests to the packet pool", 709 "Number of packets reused out of all requests to the packet pool",
481 "clientstack", 710 "clientstack",
482 m_scene.Name, 711 Scene.Name,
483 StatType.Pull, 712 StatType.Pull,
484 stat => 713 stat =>
485 { PercentageStat pstat = (PercentageStat)stat; 714 { PercentageStat pstat = (PercentageStat)stat;
@@ -493,7 +722,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
493 "Packet data blocks reused", 722 "Packet data blocks reused",
494 "Number of data blocks reused out of all requests to the packet pool", 723 "Number of data blocks reused out of all requests to the packet pool",
495 "clientstack", 724 "clientstack",
496 m_scene.Name, 725 Scene.Name,
497 StatType.Pull, 726 StatType.Pull,
498 stat => 727 stat =>
499 { PercentageStat pstat = (PercentageStat)stat; 728 { PercentageStat pstat = (PercentageStat)stat;
@@ -508,7 +737,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
508 "The number of objects currently stored within the packet pool", 737 "The number of objects currently stored within the packet pool",
509 "", 738 "",
510 "clientstack", 739 "clientstack",
511 m_scene.Name, 740 Scene.Name,
512 StatType.Pull, 741 StatType.Pull,
513 stat => stat.Value = PacketPool.Instance.PacketsPooled, 742 stat => stat.Value = PacketPool.Instance.PacketsPooled,
514 StatVerbosity.Debug)); 743 StatVerbosity.Debug));
@@ -520,132 +749,57 @@ namespace OpenSim.Region.ClientStack.LindenUDP
520 "The number of objects currently stored within the packet data block pool", 749 "The number of objects currently stored within the packet data block pool",
521 "", 750 "",
522 "clientstack", 751 "clientstack",
523 m_scene.Name, 752 Scene.Name,
524 StatType.Pull, 753 StatType.Pull,
525 stat => stat.Value = PacketPool.Instance.BlocksPooled, 754 stat => stat.Value = PacketPool.Instance.BlocksPooled,
526 StatVerbosity.Debug)); 755 StatVerbosity.Debug));
756
757 StatsManager.RegisterStat(
758 new Stat(
759 "OutgoingPacketsQueuedCount",
760 "Packets queued for outgoing send",
761 "Number of queued outgoing packets across all connections",
762 "",
763 "clientstack",
764 Scene.Name,
765 StatType.Pull,
766 MeasuresOfInterest.AverageChangeOverTime,
767 stat => stat.Value = GetTotalQueuedOutgoingPackets(),
768 StatVerbosity.Info));
769
770 StatsManager.RegisterStat(
771 new Stat(
772 "IncomingPacketAsyncRequestsWaiting",
773 "Number of incoming packets waiting for async processing in engine.",
774 "",
775 "",
776 "clientstack",
777 Scene.Name,
778 StatType.Pull,
779 MeasuresOfInterest.None,
780 stat => stat.Value = IpahEngine.JobsWaiting,
781 StatVerbosity.Debug));
782
783 StatsManager.RegisterStat(
784 new Stat(
785 "OQRERequestsWaiting",
786 "Number of outgong queue refill requests waiting for processing.",
787 "",
788 "",
789 "clientstack",
790 Scene.Name,
791 StatType.Pull,
792 MeasuresOfInterest.None,
793 stat => stat.Value = OqrEngine.JobsWaiting,
794 StatVerbosity.Debug));
527 795
528 // We delay enabling pool stats to AddScene() instead of Initialize() so that we can distinguish pool stats by 796 // We delay enabling pool stats to AddScene() instead of Initialize() so that we can distinguish pool stats by
529 // scene name 797 // scene name
530 if (UsePools) 798 if (UsePools)
531 EnablePoolStats(); 799 EnablePoolStats();
532 800
533 MainConsole.Instance.Commands.AddCommand( 801 LLUDPServerCommands commands = new LLUDPServerCommands(MainConsole.Instance, this);
534 "Debug", 802 commands.Register();
535 false,
536 "debug lludp start",
537 "debug lludp start <in|out|all>",
538 "Control LLUDP packet processing.",
539 "No effect if packet processing has already started.\n"
540 + "in - start inbound processing.\n"
541 + "out - start outbound processing.\n"
542 + "all - start in and outbound processing.\n",
543 HandleStartCommand);
544
545 MainConsole.Instance.Commands.AddCommand(
546 "Debug",
547 false,
548 "debug lludp stop",
549 "debug lludp stop <in|out|all>",
550 "Stop LLUDP packet processing.",
551 "No effect if packet processing has already stopped.\n"
552 + "in - stop inbound processing.\n"
553 + "out - stop outbound processing.\n"
554 + "all - stop in and outbound processing.\n",
555 HandleStopCommand);
556
557 MainConsole.Instance.Commands.AddCommand(
558 "Debug",
559 false,
560 "debug lludp pool",
561 "debug lludp pool <on|off>",
562 "Turn object pooling within the lludp component on or off.",
563 HandlePoolCommand);
564
565 MainConsole.Instance.Commands.AddCommand(
566 "Debug",
567 false,
568 "debug lludp status",
569 "debug lludp status",
570 "Return status of LLUDP packet processing.",
571 HandleStatusCommand);
572 }
573
574 private void HandleStartCommand(string module, string[] args)
575 {
576 if (args.Length != 4)
577 {
578 MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>");
579 return;
580 }
581
582 string subCommand = args[3];
583
584 if (subCommand == "in" || subCommand == "all")
585 StartInbound();
586
587 if (subCommand == "out" || subCommand == "all")
588 StartOutbound();
589 }
590
591 private void HandleStopCommand(string module, string[] args)
592 {
593 if (args.Length != 4)
594 {
595 MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>");
596 return;
597 }
598
599 string subCommand = args[3];
600
601 if (subCommand == "in" || subCommand == "all")
602 StopInbound();
603
604 if (subCommand == "out" || subCommand == "all")
605 StopOutbound();
606 }
607
608 private void HandlePoolCommand(string module, string[] args)
609 {
610 if (args.Length != 4)
611 {
612 MainConsole.Instance.Output("Usage: debug lludp pool <on|off>");
613 return;
614 }
615
616 string enabled = args[3];
617
618 if (enabled == "on")
619 {
620 if (EnablePools())
621 {
622 EnablePoolStats();
623 MainConsole.Instance.OutputFormat("Packet pools enabled on {0}", m_scene.Name);
624 }
625 }
626 else if (enabled == "off")
627 {
628 if (DisablePools())
629 {
630 DisablePoolStats();
631 MainConsole.Instance.OutputFormat("Packet pools disabled on {0}", m_scene.Name);
632 }
633 }
634 else
635 {
636 MainConsole.Instance.Output("Usage: debug lludp pool <on|off>");
637 }
638 }
639
640 private void HandleStatusCommand(string module, string[] args)
641 {
642 MainConsole.Instance.OutputFormat(
643 "IN LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningInbound ? "enabled" : "disabled");
644
645 MainConsole.Instance.OutputFormat(
646 "OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled");
647
648 MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_scene.Name, UsePools ? "on" : "off");
649 } 803 }
650 804
651 public bool HandlesRegion(Location x) 805 public bool HandlesRegion(Location x)
@@ -653,45 +807,62 @@ namespace OpenSim.Region.ClientStack.LindenUDP
653 return x == m_location; 807 return x == m_location;
654 } 808 }
655 809
656 public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting) 810 public int GetTotalQueuedOutgoingPackets()
657 { 811 {
658 // CoarseLocationUpdate and AvatarGroupsReply packets cannot be split in an automated way 812 int total = 0;
659 if ((packet.Type == PacketType.CoarseLocationUpdate || packet.Type == PacketType.AvatarGroupsReply) && allowSplitting)
660 allowSplitting = false;
661 813
662 if (allowSplitting && packet.HasVariableBlocks) 814 foreach (ScenePresence sp in Scene.GetScenePresences())
663 { 815 {
664 byte[][] datas = packet.ToBytesMultiple(); 816 // XXX: Need a better way to determine which IClientAPIs have UDPClients (NPCs do not, for instance).
665 int packetCount = datas.Length; 817 if (sp.ControllingClient is LLClientView)
666
667 if (packetCount < 1)
668 m_log.Error("[LLUDPSERVER]: Failed to split " + packet.Type + " with estimated length " + packet.Length);
669
670 for (int i = 0; i < packetCount; i++)
671 { 818 {
672 byte[] data = datas[i]; 819 LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
673 m_scene.ForEachClient( 820 total += udpClient.GetTotalPacketsQueuedCount();
674 delegate(IClientAPI client)
675 {
676 if (client is LLClientView)
677 SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null);
678 }
679 );
680 } 821 }
681 } 822 }
682 else 823
683 { 824 return total;
684 byte[] data = packet.ToBytes();
685 m_scene.ForEachClient(
686 delegate(IClientAPI client)
687 {
688 if (client is LLClientView)
689 SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null);
690 }
691 );
692 }
693 } 825 }
694 826
827// public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting)
828// {
829// // CoarseLocationUpdate and AvatarGroupsReply packets cannot be split in an automated way
830// if ((packet.Type == PacketType.CoarseLocationUpdate || packet.Type == PacketType.AvatarGroupsReply) && allowSplitting)
831// allowSplitting = false;
832//
833// if (allowSplitting && packet.HasVariableBlocks)
834// {
835// byte[][] datas = packet.ToBytesMultiple();
836// int packetCount = datas.Length;
837//
838// if (packetCount < 1)
839// m_log.Error("[LLUDPSERVER]: Failed to split " + packet.Type + " with estimated length " + packet.Length);
840//
841// for (int i = 0; i < packetCount; i++)
842// {
843// byte[] data = datas[i];
844// m_scene.ForEachClient(
845// delegate(IClientAPI client)
846// {
847// if (client is LLClientView)
848// SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null);
849// }
850// );
851// }
852// }
853// else
854// {
855// byte[] data = packet.ToBytes();
856// m_scene.ForEachClient(
857// delegate(IClientAPI client)
858// {
859// if (client is LLClientView)
860// SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null);
861// }
862// );
863// }
864// }
865
695 /// <summary> 866 /// <summary>
696 /// Start the process of sending a packet to the client. 867 /// Start the process of sending a packet to the client.
697 /// </summary> 868 /// </summary>
@@ -710,6 +881,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
710 if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting) 881 if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting)
711 allowSplitting = false; 882 allowSplitting = false;
712 883
884 bool packetQueued = false;
885
713 if (allowSplitting && packet.HasVariableBlocks) 886 if (allowSplitting && packet.HasVariableBlocks)
714 { 887 {
715 byte[][] datas = packet.ToBytesMultiple(); 888 byte[][] datas = packet.ToBytesMultiple();
@@ -721,16 +894,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
721 for (int i = 0; i < packetCount; i++) 894 for (int i = 0; i < packetCount; i++)
722 { 895 {
723 byte[] data = datas[i]; 896 byte[] data = datas[i];
724 SendPacketData(udpClient, data, packet.Type, category, method); 897 if (!SendPacketData(udpClient, data, packet.Type, category, method))
898 packetQueued = true;
725 } 899 }
726 } 900 }
727 else 901 else
728 { 902 {
729 byte[] data = packet.ToBytes(); 903 byte[] data = packet.ToBytes();
730 SendPacketData(udpClient, data, packet.Type, category, method); 904 if (!SendPacketData(udpClient, data, packet.Type, category, method))
905 packetQueued = true;
731 } 906 }
732 907
733 PacketPool.Instance.ReturnPacket(packet); 908 PacketPool.Instance.ReturnPacket(packet);
909
910 if (packetQueued)
911 m_dataPresentEvent.Set();
734 } 912 }
735 913
736 /// <summary> 914 /// <summary>
@@ -744,7 +922,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
744 /// The method to call if the packet is not acked by the client. If null, then a standard 922 /// The method to call if the packet is not acked by the client. If null, then a standard
745 /// resend of the packet is done. 923 /// resend of the packet is done.
746 /// </param> 924 /// </param>
747 public void SendPacketData( 925 /// <returns>true if the data was sent immediately, false if it was queued for sending</returns>
926 public bool SendPacketData(
748 LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category, UnackedPacketMethod method) 927 LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category, UnackedPacketMethod method)
749 { 928 {
750 int dataLength = data.Length; 929 int dataLength = data.Length;
@@ -801,15 +980,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP
801 #region Queue or Send 980 #region Queue or Send
802 981
803 OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null); 982 OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null);
983
804 // If we were not provided a method for handling unacked, use the UDPServer default method 984 // If we were not provided a method for handling unacked, use the UDPServer default method
805 outgoingPacket.UnackedMethod = ((method == null) ? delegate(OutgoingPacket oPacket) { ResendUnacked(oPacket); } : method); 985 if ((outgoingPacket.Buffer.Data[0] & Helpers.MSG_RELIABLE) != 0)
986 outgoingPacket.UnackedMethod = ((method == null) ? delegate(OutgoingPacket oPacket) { ResendUnacked(oPacket); } : method);
806 987
807 // If a Linden Lab 1.23.5 client receives an update packet after a kill packet for an object, it will 988 // If a Linden Lab 1.23.5 client receives an update packet after a kill packet for an object, it will
808 // continue to display the deleted object until relog. Therefore, we need to always queue a kill object 989 // continue to display the deleted object until relog. Therefore, we need to always queue a kill object
809 // packet so that it isn't sent before a queued update packet. 990 // packet so that it isn't sent before a queued update packet.
810 bool requestQueue = type == PacketType.KillObject; 991 bool forceQueue = (type == PacketType.KillObject);
811 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue)) 992
993// if (type == PacketType.ImprovedTerseObjectUpdate)
994// {
995// m_log.DebugFormat("Direct send ITOU to {0} in {1}", udpClient.AgentID, Scene.Name);
996// SendPacketFinal(outgoingPacket);
997// return false;
998// }
999// else
1000// {
1001 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, forceQueue))
1002 {
812 SendPacketFinal(outgoingPacket); 1003 SendPacketFinal(outgoingPacket);
1004 return true;
1005 }
1006 else
1007 {
1008 return false;
1009 }
1010// }
813 1011
814 #endregion Queue or Send 1012 #endregion Queue or Send
815 } 1013 }
@@ -885,7 +1083,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
885 // Fire this out on a different thread so that we don't hold up outgoing packet processing for 1083 // Fire this out on a different thread so that we don't hold up outgoing packet processing for
886 // everybody else if this is being called due to an ack timeout. 1084 // everybody else if this is being called due to an ack timeout.
887 // This is the same as processing as the async process of a logout request. 1085 // This is the same as processing as the async process of a logout request.
888 Util.FireAndForget(o => DeactivateClientDueToTimeout(client)); 1086 Util.FireAndForget(
1087 o => DeactivateClientDueToTimeout(client, timeoutTicks), null, "LLUDPServer.DeactivateClientDueToTimeout");
889 1088
890 return; 1089 return;
891 } 1090 }
@@ -981,7 +1180,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
981 Utils.UIntToBytesBig(sequenceNumber, buffer.Data, 1); 1180 Utils.UIntToBytesBig(sequenceNumber, buffer.Data, 1);
982 outgoingPacket.SequenceNumber = sequenceNumber; 1181 outgoingPacket.SequenceNumber = sequenceNumber;
983 1182
984 if (isReliable) 1183 if (udpClient.ProcessUnackedSends && isReliable)
985 { 1184 {
986 // Add this packet to the list of ACK responses we are waiting on from the server 1185 // Add this packet to the list of ACK responses we are waiting on from the server
987 udpClient.NeedAcks.Add(outgoingPacket); 1186 udpClient.NeedAcks.Add(outgoingPacket);
@@ -990,6 +1189,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
990 else 1189 else
991 { 1190 {
992 Interlocked.Increment(ref udpClient.PacketsResent); 1191 Interlocked.Increment(ref udpClient.PacketsResent);
1192
1193 // We're not going to worry about interlock yet since its not currently critical that this total count
1194 // is 100% correct
1195 PacketsResentCount++;
993 } 1196 }
994 1197
995 #endregion Sequence Number Assignment 1198 #endregion Sequence Number Assignment
@@ -997,6 +1200,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
997 // Stats tracking 1200 // Stats tracking
998 Interlocked.Increment(ref udpClient.PacketsSent); 1201 Interlocked.Increment(ref udpClient.PacketsSent);
999 1202
1203 // We're not going to worry about interlock yet since its not currently critical that this total count
1204 // is 100% correct
1205 PacketsSentCount++;
1206
1207 if (udpClient.DebugDataOutLevel > 0)
1208 m_log.DebugFormat(
1209 "[LLUDPSERVER]: Sending packet #{0} (rel: {1}, res: {2}) to {3} from {4}",
1210 outgoingPacket.SequenceNumber, isReliable, isResend, udpClient.AgentID, Scene.Name);
1211
1000 // Put the UDP payload on the wire 1212 // Put the UDP payload on the wire
1001 AsyncBeginSend(buffer); 1213 AsyncBeginSend(buffer);
1002 1214
@@ -1004,6 +1216,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1004 outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue; 1216 outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue;
1005 } 1217 }
1006 1218
1219 private void RecordMalformedInboundPacket(IPEndPoint endPoint)
1220 {
1221// if (m_malformedCount < 100)
1222// m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString());
1223
1224 IncomingMalformedPacketCount++;
1225
1226 if ((IncomingMalformedPacketCount % 10000) == 0)
1227 m_log.WarnFormat(
1228 "[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack. Last was from {1}",
1229 IncomingMalformedPacketCount, endPoint);
1230 }
1231
1007 public override void PacketReceived(UDPPacketBuffer buffer) 1232 public override void PacketReceived(UDPPacketBuffer buffer)
1008 { 1233 {
1009 // Debugging/Profiling 1234 // Debugging/Profiling
@@ -1025,6 +1250,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1025// "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}", 1250// "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}",
1026// buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); 1251// buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
1027 1252
1253 RecordMalformedInboundPacket(endPoint);
1254
1028 return; // Drop undersized packet 1255 return; // Drop undersized packet
1029 } 1256 }
1030 1257
@@ -1043,6 +1270,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1043// "[LLUDPSERVER]: Dropping packet with malformed header received from {0} in {1}", 1270// "[LLUDPSERVER]: Dropping packet with malformed header received from {0} in {1}",
1044// buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); 1271// buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
1045 1272
1273 RecordMalformedInboundPacket(endPoint);
1274
1046 return; // Malformed header 1275 return; // Malformed header
1047 } 1276 }
1048 1277
@@ -1058,34 +1287,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1058 // Only allocate a buffer for zerodecoding if the packet is zerocoded 1287 // Only allocate a buffer for zerodecoding if the packet is zerocoded
1059 ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null); 1288 ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
1060 } 1289 }
1061 catch (MalformedDataException)
1062 {
1063 }
1064 catch (IndexOutOfRangeException)
1065 {
1066// m_log.WarnFormat(
1067// "[LLUDPSERVER]: Dropping short packet received from {0} in {1}",
1068// buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
1069
1070 return; // Drop short packet
1071 }
1072 catch (Exception e) 1290 catch (Exception e)
1073 { 1291 {
1074 if (m_malformedCount < 100) 1292 if (IncomingMalformedPacketCount < 100)
1075 m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString()); 1293 m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString());
1076
1077 m_malformedCount++;
1078
1079 if ((m_malformedCount % 100000) == 0)
1080 m_log.DebugFormat("[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack.", m_malformedCount);
1081 } 1294 }
1082 1295
1083 // Fail-safe check 1296 // Fail-safe check
1084 if (packet == null) 1297 if (packet == null)
1085 { 1298 {
1086 m_log.ErrorFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}:", 1299 if (IncomingMalformedPacketCount < 100)
1087 buffer.DataLength, buffer.RemoteEndPoint); 1300 {
1088 m_log.Error(Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)); 1301 m_log.WarnFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}, data {2}:",
1302 buffer.DataLength, buffer.RemoteEndPoint, Utils.BytesToHexString(buffer.Data, buffer.DataLength, null));
1303 }
1304
1305 RecordMalformedInboundPacket(endPoint);
1306
1089 return; 1307 return;
1090 } 1308 }
1091 1309
@@ -1100,16 +1318,38 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1100 // buffer. 1318 // buffer.
1101 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; 1319 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
1102 1320
1103 Util.FireAndForget(HandleUseCircuitCode, array); 1321 Util.FireAndForget(HandleUseCircuitCode, array, "LLUDPServer.HandleUseCircuitCode");
1322
1323 return;
1324 }
1325 else if (packet.Type == PacketType.CompleteAgentMovement)
1326 {
1327 // Send ack straight away to let the viewer know that we got it.
1328 SendAckImmediate(endPoint, packet.Header.Sequence);
1329
1330 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the
1331 // buffer.
1332 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
1333
1334 Util.FireAndForget(
1335 HandleCompleteMovementIntoRegion, array, "LLUDPServer.HandleCompleteMovementIntoRegion");
1104 1336
1105 return; 1337 return;
1106 } 1338 }
1107 1339
1108 // Determine which agent this packet came from 1340 // Determine which agent this packet came from
1109 IClientAPI client; 1341 IClientAPI client;
1110 if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView)) 1342 if (!Scene.TryGetClient(endPoint, out client) || !(client is LLClientView))
1111 { 1343 {
1112 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); 1344 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName);
1345
1346 IncomingOrphanedPacketCount++;
1347
1348 if ((IncomingOrphanedPacketCount % 10000) == 0)
1349 m_log.WarnFormat(
1350 "[LLUDPSERVER]: Received {0} orphaned packets so far. Last was from {1}",
1351 IncomingOrphanedPacketCount, endPoint);
1352
1113 return; 1353 return;
1114 } 1354 }
1115 1355
@@ -1128,30 +1368,37 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1128 1368
1129 #region ACK Receiving 1369 #region ACK Receiving
1130 1370
1131 // Handle appended ACKs 1371 if (udpClient.ProcessUnackedSends)
1132 if (packet.Header.AppendedAcks && packet.Header.AckList != null)
1133 { 1372 {
1134// m_log.DebugFormat( 1373 // Handle appended ACKs
1135// "[LLUDPSERVER]: Handling {0} appended acks from {1} in {2}", 1374 if (packet.Header.AppendedAcks && packet.Header.AckList != null)
1136// packet.Header.AckList.Length, client.Name, m_scene.Name); 1375 {
1376 // m_log.DebugFormat(
1377 // "[LLUDPSERVER]: Handling {0} appended acks from {1} in {2}",
1378 // packet.Header.AckList.Length, client.Name, m_scene.Name);
1137 1379
1138 for (int i = 0; i < packet.Header.AckList.Length; i++) 1380 for (int i = 0; i < packet.Header.AckList.Length; i++)
1139 udpClient.NeedAcks.Acknowledge(packet.Header.AckList[i], now, packet.Header.Resent); 1381 udpClient.NeedAcks.Acknowledge(packet.Header.AckList[i], now, packet.Header.Resent);
1140 } 1382 }
1141 1383
1142 // Handle PacketAck packets 1384 // Handle PacketAck packets
1143 if (packet.Type == PacketType.PacketAck) 1385 if (packet.Type == PacketType.PacketAck)
1144 { 1386 {
1145 PacketAckPacket ackPacket = (PacketAckPacket)packet; 1387 PacketAckPacket ackPacket = (PacketAckPacket)packet;
1146 1388
1147// m_log.DebugFormat( 1389 // m_log.DebugFormat(
1148// "[LLUDPSERVER]: Handling {0} packet acks for {1} in {2}", 1390 // "[LLUDPSERVER]: Handling {0} packet acks for {1} in {2}",
1149// ackPacket.Packets.Length, client.Name, m_scene.Name); 1391 // ackPacket.Packets.Length, client.Name, m_scene.Name);
1150 1392
1151 for (int i = 0; i < ackPacket.Packets.Length; i++) 1393 for (int i = 0; i < ackPacket.Packets.Length; i++)
1152 udpClient.NeedAcks.Acknowledge(ackPacket.Packets[i].ID, now, packet.Header.Resent); 1394 udpClient.NeedAcks.Acknowledge(ackPacket.Packets[i].ID, now, packet.Header.Resent);
1153 1395
1154 // We don't need to do anything else with PacketAck packets 1396 // We don't need to do anything else with PacketAck packets
1397 return;
1398 }
1399 }
1400 else if (packet.Type == PacketType.PacketAck)
1401 {
1155 return; 1402 return;
1156 } 1403 }
1157 1404
@@ -1185,6 +1432,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1185 1432
1186 #region Incoming Packet Accounting 1433 #region Incoming Packet Accounting
1187 1434
1435 // We're not going to worry about interlock yet since its not currently critical that this total count
1436 // is 100% correct
1437 if (packet.Header.Resent)
1438 IncomingPacketsResentCount++;
1439
1188 // Check the archive of received reliable packet IDs to see whether we already received this packet 1440 // Check the archive of received reliable packet IDs to see whether we already received this packet
1189 if (packet.Header.Reliable && !udpClient.PacketArchive.TryEnqueue(packet.Header.Sequence)) 1441 if (packet.Header.Reliable && !udpClient.PacketArchive.TryEnqueue(packet.Header.Sequence))
1190 { 1442 {
@@ -1207,6 +1459,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1207 LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length); 1459 LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length);
1208 #endregion BinaryStats 1460 #endregion BinaryStats
1209 1461
1462 if (packet.Type == PacketType.AgentUpdate)
1463 {
1464 if (DiscardInboundAgentUpdates)
1465 return;
1466
1467 ((LLClientView)client).TotalAgentUpdates++;
1468
1469 AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
1470
1471 LLClientView llClient = client as LLClientView;
1472 if (agentUpdate.AgentData.SessionID != client.SessionId
1473 || agentUpdate.AgentData.AgentID != client.AgentId
1474 || !(llClient == null || llClient.CheckAgentUpdateSignificance(agentUpdate.AgentData)) )
1475 {
1476 PacketPool.Instance.ReturnPacket(packet);
1477 return;
1478 }
1479 }
1480
1210 #region Ping Check Handling 1481 #region Ping Check Handling
1211 1482
1212 if (packet.Type == PacketType.StartPingCheck) 1483 if (packet.Type == PacketType.StartPingCheck)
@@ -1266,8 +1537,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1266 static object binStatsLogLock = new object(); 1537 static object binStatsLogLock = new object();
1267 static string binStatsDir = ""; 1538 static string binStatsDir = "";
1268 1539
1540 //for Aggregated In/Out BW logging
1541 static bool m_aggregatedBWStats = false;
1542 static long m_aggregatedBytesIn = 0;
1543 static long m_aggregatedByestOut = 0;
1544 static object aggBWStatsLock = new object();
1545
1546 public static long AggregatedLLUDPBytesIn
1547 {
1548 get { return m_aggregatedBytesIn; }
1549 }
1550 public static long AggregatedLLUDPBytesOut
1551 {
1552 get {return m_aggregatedByestOut;}
1553 }
1554
1269 public static void LogPacketHeader(bool incoming, uint circuit, byte flags, PacketType packetType, ushort size) 1555 public static void LogPacketHeader(bool incoming, uint circuit, byte flags, PacketType packetType, ushort size)
1270 { 1556 {
1557 if (m_aggregatedBWStats)
1558 {
1559 lock (aggBWStatsLock)
1560 {
1561 if (incoming)
1562 m_aggregatedBytesIn += size;
1563 else
1564 m_aggregatedByestOut += size;
1565 }
1566 }
1567
1271 if (!m_shouldCollectStats) return; 1568 if (!m_shouldCollectStats) return;
1272 1569
1273 // Binary logging format is TTTTTTTTCCCCFPPPSS, T=Time, C=Circuit, F=Flags, P=PacketType, S=size 1570 // Binary logging format is TTTTTTTTCCCCFPPPSS, T=Time, C=Circuit, F=Flags, P=PacketType, S=size
@@ -1344,7 +1641,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1344 1641
1345 m_log.DebugFormat( 1642 m_log.DebugFormat(
1346 "[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} to {1} from IP {2}", 1643 "[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} to {1} from IP {2}",
1347 uccp.CircuitCode.Code, m_scene.RegionInfo.RegionName, endPoint); 1644 uccp.CircuitCode.Code, Scene.RegionInfo.RegionName, endPoint);
1348 1645
1349 AuthenticateResponse sessionInfo; 1646 AuthenticateResponse sessionInfo;
1350 if (IsClientAuthorized(uccp, out sessionInfo)) 1647 if (IsClientAuthorized(uccp, out sessionInfo))
@@ -1365,14 +1662,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1365 1662
1366 // We only want to send initial data to new clients, not ones which are being converted from child to root. 1663 // We only want to send initial data to new clients, not ones which are being converted from child to root.
1367 if (client != null) 1664 if (client != null)
1368 client.SceneAgent.SendInitialDataToMe(); 1665 {
1666 AgentCircuitData aCircuit = Scene.AuthenticateHandler.GetAgentCircuitData(uccp.CircuitCode.Code);
1667 bool tp = (aCircuit.teleportFlags > 0);
1668 // Let's delay this for TP agents, otherwise the viewer doesn't know where to get resources from
1669 if (!tp && !client.SceneAgent.SentInitialDataToClient)
1670 client.SceneAgent.SendInitialDataToClient();
1671 }
1369 } 1672 }
1370 else 1673 else
1371 { 1674 {
1372 // Don't create clients for unauthorized requesters. 1675 // Don't create clients for unauthorized requesters.
1373 m_log.WarnFormat( 1676 m_log.WarnFormat(
1374 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", 1677 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}",
1375 uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint); 1678 uccp.CircuitCode.ID, Scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint);
1376 } 1679 }
1377 1680
1378 // m_log.DebugFormat( 1681 // m_log.DebugFormat(
@@ -1392,6 +1695,116 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1392 } 1695 }
1393 } 1696 }
1394 1697
1698 private void HandleCompleteMovementIntoRegion(object o)
1699 {
1700 IPEndPoint endPoint = null;
1701 IClientAPI client = null;
1702
1703 try
1704 {
1705 object[] array = (object[])o;
1706 endPoint = (IPEndPoint)array[0];
1707 CompleteAgentMovementPacket packet = (CompleteAgentMovementPacket)array[1];
1708
1709 m_log.DebugFormat(
1710 "[LLUDPSERVER]: Handling CompleteAgentMovement request from {0} in {1}", endPoint, Scene.Name);
1711
1712 // Determine which agent this packet came from
1713 // We need to wait here because in when using the OpenSimulator V2 teleport protocol to travel to a destination
1714 // simulator with no existing child presence, the viewer (at least LL 3.3.4) will send UseCircuitCode
1715 // and then CompleteAgentMovement immediately without waiting for an ack. As we are now handling these
1716 // packets asynchronously, we need to account for this thread proceeding more quickly than the
1717 // UseCircuitCode thread.
1718 int count = 40;
1719 while (count-- > 0)
1720 {
1721 if (Scene.TryGetClient(endPoint, out client))
1722 {
1723 if (!client.IsActive)
1724 {
1725 // This check exists to catch a condition where the client has been closed by another thread
1726 // but has not yet been removed from the client manager (and possibly a new connection has
1727 // not yet been established).
1728 m_log.DebugFormat(
1729 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client is not active yet. Waiting.",
1730 endPoint, client.Name, Scene.Name);
1731 }
1732 else if (client.SceneAgent == null)
1733 {
1734 // This check exists to catch a condition where the new client has been added to the client
1735 // manager but the SceneAgent has not yet been set in Scene.AddNewAgent(). If we are too
1736 // eager, then the new ScenePresence may not have registered a listener for this messsage
1737 // before we try to process it.
1738 // XXX: A better long term fix may be to add the SceneAgent before the client is added to
1739 // the client manager
1740 m_log.DebugFormat(
1741 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client SceneAgent not set yet. Waiting.",
1742 endPoint, client.Name, Scene.Name);
1743 }
1744 else
1745 {
1746 break;
1747 }
1748 }
1749 else
1750 {
1751 m_log.DebugFormat(
1752 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} in {1} but no client exists yet. Waiting.",
1753 endPoint, Scene.Name);
1754 }
1755
1756 Thread.Sleep(200);
1757 }
1758
1759 if (client == null)
1760 {
1761 m_log.DebugFormat(
1762 "[LLUDPSERVER]: No client found for CompleteAgentMovement from {0} in {1} after wait. Dropping.",
1763 endPoint, Scene.Name);
1764
1765 return;
1766 }
1767 else if (!client.IsActive || client.SceneAgent == null)
1768 {
1769 // This check exists to catch a condition where the client has been closed by another thread
1770 // but has not yet been removed from the client manager.
1771 // The packet could be simply ignored but it is useful to know if this condition occurred for other debugging
1772 // purposes.
1773 m_log.DebugFormat(
1774 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client is not active after wait. Dropping.",
1775 endPoint, client.Name, Scene.Name);
1776
1777 return;
1778 }
1779
1780 IncomingPacket incomingPacket1;
1781
1782 // Inbox insertion
1783 if (UsePools)
1784 {
1785 incomingPacket1 = m_incomingPacketPool.GetObject();
1786 incomingPacket1.Client = (LLClientView)client;
1787 incomingPacket1.Packet = packet;
1788 }
1789 else
1790 {
1791 incomingPacket1 = new IncomingPacket((LLClientView)client, packet);
1792 }
1793
1794 packetInbox.Enqueue(incomingPacket1);
1795 }
1796 catch (Exception e)
1797 {
1798 m_log.ErrorFormat(
1799 "[LLUDPSERVER]: CompleteAgentMovement handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}",
1800 endPoint != null ? endPoint.ToString() : "n/a",
1801 client != null ? client.Name : "unknown",
1802 client != null ? client.AgentId.ToString() : "unknown",
1803 e.Message,
1804 e.StackTrace);
1805 }
1806 }
1807
1395 /// <summary> 1808 /// <summary>
1396 /// Send an ack immediately to the given endpoint. 1809 /// Send an ack immediately to the given endpoint.
1397 /// </summary> 1810 /// </summary>
@@ -1454,12 +1867,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1454 // consistently, this lock could probably be removed. 1867 // consistently, this lock could probably be removed.
1455 lock (this) 1868 lock (this)
1456 { 1869 {
1457 if (!m_scene.TryGetClient(agentID, out client)) 1870 if (!Scene.TryGetClient(agentID, out client))
1458 { 1871 {
1459 LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, m_throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO); 1872 LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, Throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO);
1460 1873
1461 client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); 1874 client = new LLClientView(Scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
1462 client.OnLogout += LogoutHandler; 1875 client.OnLogout += LogoutHandler;
1876 client.DebugPacketLevel = DefaultClientPacketDebugLevel;
1463 1877
1464 ((LLClientView)client).DisableFacelights = m_disableFacelights; 1878 ((LLClientView)client).DisableFacelights = m_disableFacelights;
1465 1879
@@ -1478,25 +1892,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1478 /// regular client pings. 1892 /// regular client pings.
1479 /// </remarks> 1893 /// </remarks>
1480 /// <param name='client'></param> 1894 /// <param name='client'></param>
1481 private void DeactivateClientDueToTimeout(LLClientView client) 1895 /// <param name='timeoutTicks'></param>
1896 private void DeactivateClientDueToTimeout(LLClientView client, int timeoutTicks)
1482 { 1897 {
1483 lock (client.CloseSyncLock) 1898 lock (client.CloseSyncLock)
1484 { 1899 {
1900 ClientLogoutsDueToNoReceives++;
1901
1485 m_log.WarnFormat( 1902 m_log.WarnFormat(
1486 "[LLUDPSERVER]: Ack timeout, disconnecting {0} agent for {1} in {2}", 1903 "[LLUDPSERVER]: No packets received from {0} agent of {1} for {2}ms in {3}. Disconnecting.",
1487 client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, m_scene.RegionInfo.RegionName); 1904 client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, timeoutTicks, Scene.Name);
1488
1489 StatsManager.SimExtraStats.AddAbnormalClientThreadTermination();
1490 1905
1491 if (!client.SceneAgent.IsChildAgent) 1906 if (!client.SceneAgent.IsChildAgent)
1492 client.Kick("Simulator logged you out due to connection timeout"); 1907 client.Kick("Simulator logged you out due to connection timeout.");
1493
1494 client.CloseWithoutChecks();
1495 } 1908 }
1909
1910 Scene.CloseAgent(client.AgentId, true);
1496 } 1911 }
1497 1912
1498 private void IncomingPacketHandler() 1913 private void IncomingPacketHandler()
1499 { 1914 {
1915 Thread.CurrentThread.Priority = ThreadPriority.Highest;
1916
1500 // Set this culture for the thread that incoming packets are received 1917 // Set this culture for the thread that incoming packets are received
1501 // on to en-US to avoid number parsing issues 1918 // on to en-US to avoid number parsing issues
1502 Culture.SetCurrentCulture(); 1919 Culture.SetCurrentCulture();
@@ -1507,6 +1924,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1507 { 1924 {
1508 IncomingPacket incomingPacket = null; 1925 IncomingPacket incomingPacket = null;
1509 1926
1927 /*
1510 // HACK: This is a test to try and rate limit packet handling on Mono. 1928 // HACK: This is a test to try and rate limit packet handling on Mono.
1511 // If it works, a more elegant solution can be devised 1929 // If it works, a more elegant solution can be devised
1512 if (Util.FireAndForgetCount() < 2) 1930 if (Util.FireAndForgetCount() < 2)
@@ -1514,6 +1932,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1514 //m_log.Debug("[LLUDPSERVER]: Incoming packet handler is sleeping"); 1932 //m_log.Debug("[LLUDPSERVER]: Incoming packet handler is sleeping");
1515 Thread.Sleep(30); 1933 Thread.Sleep(30);
1516 } 1934 }
1935 */
1517 1936
1518 if (packetInbox.Dequeue(100, ref incomingPacket)) 1937 if (packetInbox.Dequeue(100, ref incomingPacket))
1519 { 1938 {
@@ -1540,6 +1959,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1540 1959
1541 private void OutgoingPacketHandler() 1960 private void OutgoingPacketHandler()
1542 { 1961 {
1962 Thread.CurrentThread.Priority = ThreadPriority.Highest;
1963
1543 // Set this culture for the thread that outgoing packets are sent 1964 // Set this culture for the thread that outgoing packets are sent
1544 // on to en-US to avoid number parsing issues 1965 // on to en-US to avoid number parsing issues
1545 Culture.SetCurrentCulture(); 1966 Culture.SetCurrentCulture();
@@ -1602,14 +2023,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1602 2023
1603 // Handle outgoing packets, resends, acknowledgements, and pings for each 2024 // Handle outgoing packets, resends, acknowledgements, and pings for each
1604 // client. m_packetSent will be set to true if a packet is sent 2025 // client. m_packetSent will be set to true if a packet is sent
1605 m_scene.ForEachClient(clientPacketHandler); 2026 Scene.ForEachClient(clientPacketHandler);
1606 2027
1607 m_currentOutgoingClient = null; 2028 m_currentOutgoingClient = null;
1608 2029
1609 // If nothing was sent, sleep for the minimum amount of time before a 2030 // If nothing was sent, sleep for the minimum amount of time before a
1610 // token bucket could get more tokens 2031 // token bucket could get more tokens
2032 //if (!m_packetSent)
2033 // Thread.Sleep((int)TickCountResolution);
2034 //
2035 // Instead, now wait for data present to be explicitly signalled. Evidence so far is that with
2036 // modern mono it reduces CPU base load since there is no more continuous polling.
1611 if (!m_packetSent) 2037 if (!m_packetSent)
1612 Thread.Sleep((int)TickCountResolution); 2038 m_dataPresentEvent.WaitOne(100);
1613 2039
1614 Watchdog.UpdateThread(); 2040 Watchdog.UpdateThread();
1615 } 2041 }
@@ -1635,7 +2061,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1635 2061
1636 if (udpClient.IsConnected) 2062 if (udpClient.IsConnected)
1637 { 2063 {
1638 if (m_resendUnacked) 2064 if (udpClient.ProcessUnackedSends && m_resendUnacked)
1639 HandleUnacked(llClient); 2065 HandleUnacked(llClient);
1640 2066
1641 if (m_sendAcks) 2067 if (m_sendAcks)
@@ -1764,7 +2190,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1764 watch1.Reset(); 2190 watch1.Reset();
1765 2191
1766 // reuse this -- it's every ~100ms 2192 // reuse this -- it's every ~100ms
1767 if (m_scene.EmergencyMonitoring && nticks % 100 == 0) 2193 if (Scene.EmergencyMonitoring && nticks % 100 == 0)
1768 { 2194 {
1769 m_log.InfoFormat("[LLUDPSERVER]: avg processing ticks: {0} avg unacked: {1} avg acks: {2} avg ping: {3} avg dequeue: {4} (TickCountRes: {5} sent: {6} notsent: {7})", 2195 m_log.InfoFormat("[LLUDPSERVER]: avg processing ticks: {0} avg unacked: {1} avg acks: {2} avg ping: {3} avg dequeue: {4} (TickCountRes: {5} sent: {6} notsent: {7})",
1770 avgProcessingTicks, avgResendUnackedTicks, avgSendAcksTicks, avgSendPingTicks, avgDequeueTicks, TickCountResolution, npacksSent, npackNotSent); 2196 avgProcessingTicks, avgResendUnackedTicks, avgSendAcksTicks, avgSendPingTicks, avgDequeueTicks, TickCountResolution, npacksSent, npackNotSent);
@@ -1813,7 +2239,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1813 { 2239 {
1814 m_log.DebugFormat( 2240 m_log.DebugFormat(
1815 "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}", 2241 "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}",
1816 packet.Type, client.Name, m_scene.RegionInfo.RegionName); 2242 packet.Type, client.Name, Scene.RegionInfo.RegionName);
1817 } 2243 }
1818 2244
1819 IncomingPacketsProcessed++; 2245 IncomingPacketsProcessed++;
@@ -1826,8 +2252,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1826 if (!client.IsLoggingOut) 2252 if (!client.IsLoggingOut)
1827 { 2253 {
1828 client.IsLoggingOut = true; 2254 client.IsLoggingOut = true;
1829 client.Close(); 2255 Scene.CloseAgent(client.AgentId, false);
1830 } 2256 }
1831 } 2257 }
1832 } 2258 }
1833} \ No newline at end of file 2259}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs
new file mode 100644
index 0000000..ac6c0b4
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs
@@ -0,0 +1,901 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Text;
31using NDesk.Options;
32using OpenSim.Framework;
33using OpenSim.Framework.Console;
34using OpenSim.Region.Framework.Scenes;
35
36namespace OpenSim.Region.ClientStack.LindenUDP
37{
38 public class LLUDPServerCommands
39 {
40 private ICommandConsole m_console;
41 private LLUDPServer m_udpServer;
42
43 public LLUDPServerCommands(ICommandConsole console, LLUDPServer udpServer)
44 {
45 m_console = console;
46 m_udpServer = udpServer;
47 }
48
49 public void Register()
50 {
51 m_console.Commands.AddCommand(
52 "Comms", false, "show server throttles",
53 "show server throttles",
54 "Show information about server throttles",
55 HandleShowServerThrottlesCommand);
56
57 m_console.Commands.AddCommand(
58 "Debug", false, "debug lludp packet",
59 "debug lludp packet [--default | --all] <level> [<avatar-first-name> <avatar-last-name>]",
60 "Turn on packet debugging. This logs information when the client stack hands a processed packet off to downstream code or when upstream code first requests that a certain packet be sent.",
61 "If level > 255 then all incoming and outgoing packets are logged.\n"
62 + "If level <= 255 then incoming AgentUpdate and outgoing SimStats and SimulatorViewerTimeMessage packets are not logged.\n"
63 + "If level <= 200 then incoming RequestImage and outgoing ImagePacket, ImageData, LayerData and CoarseLocationUpdate packets are not logged.\n"
64 + "If level <= 100 then incoming ViewerEffect and AgentAnimation and outgoing ViewerEffect and AvatarAnimation packets are not logged.\n"
65 + "If level <= 50 then outgoing ImprovedTerseObjectUpdate packets are not logged.\n"
66 + "If level <= 0 then no packets are logged.\n"
67 + "If --default is specified then the level becomes the default logging level for all subsequent agents.\n"
68 + "If --all is specified then the level becomes the default logging level for all current and subsequent agents.\n"
69 + "In these cases, you cannot also specify an avatar name.\n"
70 + "If an avatar name is given then only packets from that avatar are logged.",
71 HandlePacketCommand);
72
73 m_console.Commands.AddCommand(
74 "Debug", false, "debug lludp data out",
75 "debug lludp data out <level> <avatar-first-name> <avatar-last-name>\"",
76 "Turn on debugging for final outgoing data to the given user's client.",
77 "This operates at a much lower level than the packet command and prints out available details when the data is actually sent.\n"
78 + "If level > 0 then information about all outgoing UDP data for this avatar is logged.\n"
79 + "If level <= 0 then no information about outgoing UDP data for this avatar is logged.",
80 HandleDataCommand);
81
82 m_console.Commands.AddCommand(
83 "Debug", false, "debug lludp drop",
84 "debug lludp drop <in|out> <add|remove> <packet-name>",
85 "Drop all in or outbound packets that match the given name",
86 "For test purposes.",
87 HandleDropCommand);
88
89 m_console.Commands.AddCommand(
90 "Debug",
91 false,
92 "debug lludp start",
93 "debug lludp start <in|out|all>",
94 "Control LLUDP packet processing.",
95 "No effect if packet processing has already started.\n"
96 + "in - start inbound processing.\n"
97 + "out - start outbound processing.\n"
98 + "all - start in and outbound processing.\n",
99 HandleStartCommand);
100
101 m_console.Commands.AddCommand(
102 "Debug",
103 false,
104 "debug lludp stop",
105 "debug lludp stop <in|out|all>",
106 "Stop LLUDP packet processing.",
107 "No effect if packet processing has already stopped.\n"
108 + "in - stop inbound processing.\n"
109 + "out - stop outbound processing.\n"
110 + "all - stop in and outbound processing.\n",
111 HandleStopCommand);
112
113 m_console.Commands.AddCommand(
114 "Debug",
115 false,
116 "debug lludp pool",
117 "debug lludp pool <on|off>",
118 "Turn object pooling within the lludp component on or off.",
119 HandlePoolCommand);
120
121 m_console.Commands.AddCommand(
122 "Debug",
123 false,
124 "debug lludp status",
125 "debug lludp status",
126 "Return status of LLUDP packet processing.",
127 HandleStatusCommand);
128
129 m_console.Commands.AddCommand(
130 "Debug",
131 false,
132 "debug lludp throttles log",
133 "debug lludp throttles log <level> [<avatar-first-name> <avatar-last-name>]",
134 "Change debug logging level for throttles.",
135 "If level >= 0 then throttle debug logging is performed.\n"
136 + "If level <= 0 then no throttle debug logging is performed.",
137 HandleThrottleCommand);
138
139 m_console.Commands.AddCommand(
140 "Debug",
141 false,
142 "debug lludp throttles get",
143 "debug lludp throttles get [<avatar-first-name> <avatar-last-name>]",
144 "Return debug settings for throttles.",
145 "adaptive - true/false, controls adaptive throttle setting.\n"
146 + "request - request drip rate in kbps.\n"
147 + "max - the max kbps throttle allowed for the specified existing clients. Use 'debug lludp get new-client-throttle-max' to see the setting for new clients.\n",
148 HandleThrottleGetCommand);
149
150 m_console.Commands.AddCommand(
151 "Debug",
152 false,
153 "debug lludp throttles set",
154 "debug lludp throttles set <param> <value> [<avatar-first-name> <avatar-last-name>]",
155 "Set a throttle parameter for the given client.",
156 "adaptive - true/false, controls adaptive throttle setting.\n"
157 + "current - current drip rate in kbps.\n"
158 + "request - requested drip rate in kbps.\n"
159 + "max - the max kbps throttle allowed for the specified existing clients. Use 'debug lludp set new-client-throttle-max' to change the settings for new clients.\n",
160 HandleThrottleSetCommand);
161
162 m_console.Commands.AddCommand(
163 "Debug",
164 false,
165 "debug lludp get",
166 "debug lludp get",
167 "Get debug parameters for the server.",
168 "max-scene-throttle - the current max cumulative kbps provided for this scene to clients.\n"
169 + "max-new-client-throttle - the max kbps throttle allowed to new clients. Use 'debug lludp throttles get max' to see the settings for existing clients.",
170 HandleGetCommand);
171
172 m_console.Commands.AddCommand(
173 "Debug",
174 false,
175 "debug lludp set",
176 "debug lludp set <param> <value>",
177 "Set a parameter for the server.",
178 "max-scene-throttle - the current max cumulative kbps provided for this scene to clients.\n"
179 + "max-new-client-throttle - the max kbps throttle allowed to each new client. Use 'debug lludp throttles set max' to set for existing clients.",
180 HandleSetCommand);
181
182 m_console.Commands.AddCommand(
183 "Debug",
184 false,
185 "debug lludp toggle agentupdate",
186 "debug lludp toggle agentupdate",
187 "Toggle whether agentupdate packets are processed or simply discarded.",
188 HandleAgentUpdateCommand);
189
190 MainConsole.Instance.Commands.AddCommand(
191 "Debug",
192 false,
193 "debug lludp oqre",
194 "debug lludp oqre <start|stop|status>",
195 "Start, stop or get status of OutgoingQueueRefillEngine.",
196 "If stopped then refill requests are processed directly via the threadpool.",
197 HandleOqreCommand);
198
199 m_console.Commands.AddCommand(
200 "Debug",
201 false,
202 "debug lludp client get",
203 "debug lludp client get [<avatar-first-name> <avatar-last-name>]",
204 "Get debug parameters for the client. If no name is given then all client information is returned.",
205 "process-unacked-sends - Do we take action if a sent reliable packet has not been acked.",
206 HandleClientGetCommand);
207
208 m_console.Commands.AddCommand(
209 "Debug",
210 false,
211 "debug lludp client set",
212 "debug lludp client set <param> <value> [<avatar-first-name> <avatar-last-name>]",
213 "Set a debug parameter for a particular client. If no name is given then the value is set on all clients.",
214 "process-unacked-sends - Do we take action if a sent reliable packet has not been acked.",
215 HandleClientSetCommand);
216 }
217
218 private void HandleShowServerThrottlesCommand(string module, string[] args)
219 {
220 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
221 return;
222
223 m_console.OutputFormat("Throttles for {0}", m_udpServer.Scene.Name);
224 ConsoleDisplayList cdl = new ConsoleDisplayList();
225 cdl.AddRow("Adaptive throttles", m_udpServer.ThrottleRates.AdaptiveThrottlesEnabled);
226
227 long maxSceneDripRate = m_udpServer.Throttle.MaxDripRate;
228 cdl.AddRow(
229 "Max scene throttle",
230 maxSceneDripRate != 0 ? string.Format("{0} kbps", maxSceneDripRate * 8 / 1000) : "unset");
231
232 int maxClientDripRate = m_udpServer.ThrottleRates.Total;
233 cdl.AddRow(
234 "Max new client throttle",
235 maxClientDripRate != 0 ? string.Format("{0} kbps", maxClientDripRate * 8 / 1000) : "unset");
236
237 m_console.Output(cdl.ToString());
238
239 m_console.OutputFormat("{0}\n", GetServerThrottlesReport(m_udpServer));
240 }
241
242 private string GetServerThrottlesReport(LLUDPServer udpServer)
243 {
244 StringBuilder report = new StringBuilder();
245
246 report.AppendFormat(
247 "{0,7} {1,8} {2,7} {3,7} {4,7} {5,7} {6,9} {7,7}\n",
248 "Total",
249 "Resend",
250 "Land",
251 "Wind",
252 "Cloud",
253 "Task",
254 "Texture",
255 "Asset");
256
257 report.AppendFormat(
258 "{0,7} {1,8} {2,7} {3,7} {4,7} {5,7} {6,9} {7,7}\n",
259 "kb/s",
260 "kb/s",
261 "kb/s",
262 "kb/s",
263 "kb/s",
264 "kb/s",
265 "kb/s",
266 "kb/s");
267
268 ThrottleRates throttleRates = udpServer.ThrottleRates;
269 report.AppendFormat(
270 "{0,7} {1,8} {2,7} {3,7} {4,7} {5,7} {6,9} {7,7}",
271 (throttleRates.Total * 8) / 1000,
272 (throttleRates.Resend * 8) / 1000,
273 (throttleRates.Land * 8) / 1000,
274 (throttleRates.Wind * 8) / 1000,
275 (throttleRates.Cloud * 8) / 1000,
276 (throttleRates.Task * 8) / 1000,
277 (throttleRates.Texture * 8) / 1000,
278 (throttleRates.Asset * 8) / 1000);
279
280 return report.ToString();
281 }
282
283 protected string GetColumnEntry(string entry, int maxLength, int columnPadding)
284 {
285 return string.Format(
286 "{0,-" + maxLength + "}{1,-" + columnPadding + "}",
287 entry.Length > maxLength ? entry.Substring(0, maxLength) : entry,
288 "");
289 }
290
291 private void HandleDataCommand(string module, string[] args)
292 {
293 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
294 return;
295
296 if (args.Length != 7)
297 {
298 MainConsole.Instance.OutputFormat("Usage: debug lludp data out <true|false> <avatar-first-name> <avatar-last-name>");
299 return;
300 }
301
302 int level;
303 if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[4], out level))
304 return;
305
306 string firstName = args[5];
307 string lastName = args[6];
308
309 m_udpServer.Scene.ForEachScenePresence(sp =>
310 {
311 if (sp.Firstname == firstName && sp.Lastname == lastName)
312 {
313 MainConsole.Instance.OutputFormat(
314 "Data debug for {0} ({1}) set to {2} in {3}",
315 sp.Name, sp.IsChildAgent ? "child" : "root", level, m_udpServer.Scene.Name);
316
317 ((LLClientView)sp.ControllingClient).UDPClient.DebugDataOutLevel = level;
318 }
319 });
320 }
321
322 private void HandleThrottleCommand(string module, string[] args)
323 {
324 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
325 return;
326
327 bool all = args.Length == 5;
328 bool one = args.Length == 7;
329
330 if (!all && !one)
331 {
332 MainConsole.Instance.OutputFormat(
333 "Usage: debug lludp throttles log <level> [<avatar-first-name> <avatar-last-name>]");
334 return;
335 }
336
337 int level;
338 if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[4], out level))
339 return;
340
341 string firstName = null;
342 string lastName = null;
343
344 if (one)
345 {
346 firstName = args[5];
347 lastName = args[6];
348 }
349
350 m_udpServer.Scene.ForEachScenePresence(sp =>
351 {
352 if (all || (sp.Firstname == firstName && sp.Lastname == lastName))
353 {
354 MainConsole.Instance.OutputFormat(
355 "Throttle log level for {0} ({1}) set to {2} in {3}",
356 sp.Name, sp.IsChildAgent ? "child" : "root", level, m_udpServer.Scene.Name);
357
358 ((LLClientView)sp.ControllingClient).UDPClient.ThrottleDebugLevel = level;
359 }
360 });
361 }
362
363 private void HandleThrottleSetCommand(string module, string[] args)
364 {
365 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
366 return;
367
368 bool all = args.Length == 6;
369 bool one = args.Length == 8;
370
371 if (!all && !one)
372 {
373 MainConsole.Instance.OutputFormat(
374 "Usage: debug lludp throttles set <param> <value> [<avatar-first-name> <avatar-last-name>]");
375 return;
376 }
377
378 string param = args[4];
379 string rawValue = args[5];
380
381 string firstName = null;
382 string lastName = null;
383
384 if (one)
385 {
386 firstName = args[6];
387 lastName = args[7];
388 }
389
390 if (param == "adaptive")
391 {
392 bool newValue;
393 if (!ConsoleUtil.TryParseConsoleBool(MainConsole.Instance, rawValue, out newValue))
394 return;
395
396 m_udpServer.Scene.ForEachScenePresence(sp =>
397 {
398 if (all || (sp.Firstname == firstName && sp.Lastname == lastName))
399 {
400 MainConsole.Instance.OutputFormat(
401 "Setting param {0} to {1} for {2} ({3}) in {4}",
402 param, newValue, sp.Name, sp.IsChildAgent ? "child" : "root", m_udpServer.Scene.Name);
403
404 LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
405 udpClient.FlowThrottle.AdaptiveEnabled = newValue;
406 // udpClient.FlowThrottle.MaxDripRate = 0;
407 // udpClient.FlowThrottle.AdjustedDripRate = 0;
408 }
409 });
410 }
411 else if (param == "request")
412 {
413 int newValue;
414 if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, rawValue, out newValue))
415 return;
416
417 int newCurrentThrottleKbps = newValue * 1000 / 8;
418
419 m_udpServer.Scene.ForEachScenePresence(sp =>
420 {
421 if (all || (sp.Firstname == firstName && sp.Lastname == lastName))
422 {
423 MainConsole.Instance.OutputFormat(
424 "Setting param {0} to {1} for {2} ({3}) in {4}",
425 param, newValue, sp.Name, sp.IsChildAgent ? "child" : "root", m_udpServer.Scene.Name);
426
427 LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
428 udpClient.FlowThrottle.RequestedDripRate = newCurrentThrottleKbps;
429 }
430 });
431 }
432 else if (param == "max")
433 {
434 int newValue;
435 if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, rawValue, out newValue))
436 return;
437
438 int newThrottleMaxKbps = newValue * 1000 / 8;
439
440 m_udpServer.Scene.ForEachScenePresence(sp =>
441 {
442 if (all || (sp.Firstname == firstName && sp.Lastname == lastName))
443 {
444 MainConsole.Instance.OutputFormat(
445 "Setting param {0} to {1} for {2} ({3}) in {4}",
446 param, newValue, sp.Name, sp.IsChildAgent ? "child" : "root", m_udpServer.Scene.Name);
447
448 LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
449 udpClient.FlowThrottle.MaxDripRate = newThrottleMaxKbps;
450 }
451 });
452 }
453 }
454
455 private void HandleThrottleGetCommand(string module, string[] args)
456 {
457 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
458 return;
459
460 bool all = args.Length == 4;
461 bool one = args.Length == 6;
462
463 if (!all && !one)
464 {
465 MainConsole.Instance.OutputFormat(
466 "Usage: debug lludp throttles get [<avatar-first-name> <avatar-last-name>]");
467 return;
468 }
469
470 string firstName = null;
471 string lastName = null;
472
473 if (one)
474 {
475 firstName = args[4];
476 lastName = args[5];
477 }
478
479 m_udpServer.Scene.ForEachScenePresence(sp =>
480 {
481 if (all || (sp.Firstname == firstName && sp.Lastname == lastName))
482 {
483 m_console.OutputFormat(
484 "Status for {0} ({1}) in {2}",
485 sp.Name, sp.IsChildAgent ? "child" : "root", m_udpServer.Scene.Name);
486
487 LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
488
489 ConsoleDisplayList cdl = new ConsoleDisplayList();
490 cdl.AddRow("adaptive", udpClient.FlowThrottle.AdaptiveEnabled);
491 cdl.AddRow("current", string.Format("{0} kbps", udpClient.FlowThrottle.DripRate * 8 / 1000));
492 cdl.AddRow("request", string.Format("{0} kbps", udpClient.FlowThrottle.RequestedDripRate * 8 / 1000));
493 cdl.AddRow("max", string.Format("{0} kbps", udpClient.FlowThrottle.MaxDripRate * 8 / 1000));
494
495 m_console.Output(cdl.ToString());
496 }
497 });
498 }
499
500 private void HandleGetCommand(string module, string[] args)
501 {
502 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
503 return;
504
505 m_console.OutputFormat("Debug settings for {0}", m_udpServer.Scene.Name);
506 ConsoleDisplayList cdl = new ConsoleDisplayList();
507
508 long maxSceneDripRate = m_udpServer.Throttle.MaxDripRate;
509 cdl.AddRow(
510 "max-scene-throttle",
511 maxSceneDripRate != 0 ? string.Format("{0} kbps", maxSceneDripRate * 8 / 1000) : "unset");
512
513 int maxClientDripRate = m_udpServer.ThrottleRates.Total;
514 cdl.AddRow(
515 "max-new-client-throttle",
516 maxClientDripRate != 0 ? string.Format("{0} kbps", maxClientDripRate * 8 / 1000) : "unset");
517
518 m_console.Output(cdl.ToString());
519 }
520
521 private void HandleSetCommand(string module, string[] args)
522 {
523 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
524 return;
525
526 if (args.Length != 5)
527 {
528 MainConsole.Instance.OutputFormat("Usage: debug lludp set <param> <value>");
529 return;
530 }
531
532 string param = args[3];
533 string rawValue = args[4];
534
535 int newValue;
536
537 if (param == "max-scene-throttle")
538 {
539 if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, rawValue, out newValue))
540 return;
541
542 m_udpServer.Throttle.MaxDripRate = newValue * 1000 / 8;
543 }
544 else if (param == "max-new-client-throttle")
545 {
546 if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, rawValue, out newValue))
547 return;
548
549 m_udpServer.ThrottleRates.Total = newValue * 1000 / 8;
550 }
551 else
552 {
553 return;
554 }
555
556 m_console.OutputFormat("{0} set to {1} in {2}", param, rawValue, m_udpServer.Scene.Name);
557 }
558
559 private void HandleClientGetCommand(string module, string[] args)
560 {
561 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
562 return;
563
564 if (args.Length != 4 && args.Length != 6)
565 {
566 MainConsole.Instance.OutputFormat("Usage: debug lludp client get [<avatar-first-name> <avatar-last-name>]");
567 return;
568 }
569
570 string name = null;
571
572 if (args.Length == 6)
573 name = string.Format("{0} {1}", args[4], args[5]);
574
575 m_udpServer.Scene.ForEachScenePresence(
576 sp =>
577 {
578 if ((name == null || sp.Name == name) && sp.ControllingClient is LLClientView)
579 {
580 LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
581
582 m_console.OutputFormat(
583 "Client debug parameters for {0} ({1}) in {2}",
584 sp.Name, sp.IsChildAgent ? "child" : "root", m_udpServer.Scene.Name);
585
586 ConsoleDisplayList cdl = new ConsoleDisplayList();
587 cdl.AddRow("process-unacked-sends", udpClient.ProcessUnackedSends);
588
589 m_console.Output(cdl.ToString());
590 }
591 });
592 }
593
594 private void HandleClientSetCommand(string module, string[] args)
595 {
596 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
597 return;
598
599 if (args.Length != 6 && args.Length != 8)
600 {
601 MainConsole.Instance.OutputFormat("Usage: debug lludp client set <param> <value> [<avatar-first-name> <avatar-last-name>]");
602 return;
603 }
604
605 string param = args[4];
606 string rawValue = args[5];
607
608 string name = null;
609
610 if (args.Length == 8)
611 name = string.Format("{0} {1}", args[6], args[7]);
612
613 if (param == "process-unacked-sends")
614 {
615 bool newValue;
616
617 if (!ConsoleUtil.TryParseConsoleBool(MainConsole.Instance, rawValue, out newValue))
618 return;
619
620 m_udpServer.Scene.ForEachScenePresence(
621 sp =>
622 {
623 if ((name == null || sp.Name == name) && sp.ControllingClient is LLClientView)
624 {
625 LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
626 udpClient.ProcessUnackedSends = newValue;
627
628 m_console.OutputFormat("{0} set to {1} for {2} in {3}", param, newValue, sp.Name, m_udpServer.Scene.Name);
629 }
630 });
631 }
632 }
633
634 private void HandlePacketCommand(string module, string[] args)
635 {
636 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
637 return;
638
639 bool setAsDefaultLevel = false;
640 bool setAll = false;
641 OptionSet optionSet = new OptionSet()
642 .Add("default", o => setAsDefaultLevel = (o != null))
643 .Add("all", o => setAll = (o != null));
644 List<string> filteredArgs = optionSet.Parse(args);
645
646 string name = null;
647
648 if (filteredArgs.Count == 6)
649 {
650 if (!(setAsDefaultLevel || setAll))
651 {
652 name = string.Format("{0} {1}", filteredArgs[4], filteredArgs[5]);
653 }
654 else
655 {
656 MainConsole.Instance.OutputFormat("ERROR: Cannot specify a user name when setting default/all logging level");
657 return;
658 }
659 }
660
661 if (filteredArgs.Count > 3)
662 {
663 int newDebug;
664 if (int.TryParse(filteredArgs[3], out newDebug))
665 {
666 if (setAsDefaultLevel || setAll)
667 {
668 m_udpServer.DefaultClientPacketDebugLevel = newDebug;
669
670 MainConsole.Instance.OutputFormat(
671 "Packet debug for {0} clients set to {1} in {2}",
672 (setAll ? "all" : "future"), m_udpServer.DefaultClientPacketDebugLevel, m_udpServer.Scene.Name);
673
674 if (setAll)
675 {
676 m_udpServer.Scene.ForEachScenePresence(sp =>
677 {
678 MainConsole.Instance.OutputFormat(
679 "Packet debug for {0} ({1}) set to {2} in {3}",
680 sp.Name, sp.IsChildAgent ? "child" : "root", newDebug, m_udpServer.Scene.Name);
681
682 sp.ControllingClient.DebugPacketLevel = newDebug;
683 });
684 }
685 }
686 else
687 {
688 m_udpServer.Scene.ForEachScenePresence(sp =>
689 {
690 if (name == null || sp.Name == name)
691 {
692 MainConsole.Instance.OutputFormat(
693 "Packet debug for {0} ({1}) set to {2} in {3}",
694 sp.Name, sp.IsChildAgent ? "child" : "root", newDebug, m_udpServer.Scene.Name);
695
696 sp.ControllingClient.DebugPacketLevel = newDebug;
697 }
698 });
699 }
700 }
701 else
702 {
703 MainConsole.Instance.Output("Usage: debug lludp packet [--default | --all] 0..255 [<first-name> <last-name>]");
704 }
705 }
706 }
707
708 private void HandleDropCommand(string module, string[] args)
709 {
710 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
711 return;
712
713 if (args.Length != 6)
714 {
715 MainConsole.Instance.Output("Usage: debug lludp drop <in|out> <add|remove> <packet-name>");
716 return;
717 }
718
719 string direction = args[3];
720 string subCommand = args[4];
721 string packetName = args[5];
722
723 if (subCommand == "add")
724 {
725 MainConsole.Instance.OutputFormat(
726 "Adding packet {0} to {1} drop list for all connections in {2}",
727 direction, packetName, m_udpServer.Scene.Name);
728
729 m_udpServer.Scene.ForEachScenePresence(
730 sp =>
731 {
732 LLClientView llcv = (LLClientView)sp.ControllingClient;
733
734 if (direction == "in")
735 llcv.AddInPacketToDropSet(packetName);
736 else if (direction == "out")
737 llcv.AddOutPacketToDropSet(packetName);
738 }
739 );
740 }
741 else if (subCommand == "remove")
742 {
743 MainConsole.Instance.OutputFormat(
744 "Removing packet {0} from {1} drop list for all connections in {2}",
745 direction, packetName, m_udpServer.Scene.Name);
746
747 m_udpServer.Scene.ForEachScenePresence(
748 sp =>
749 {
750 LLClientView llcv = (LLClientView)sp.ControllingClient;
751
752 if (direction == "in")
753 llcv.RemoveInPacketFromDropSet(packetName);
754 else if (direction == "out")
755 llcv.RemoveOutPacketFromDropSet(packetName);
756 }
757 );
758 }
759 }
760
761 private void HandleStartCommand(string module, string[] args)
762 {
763 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
764 return;
765
766 if (args.Length != 4)
767 {
768 MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>");
769 return;
770 }
771
772 string subCommand = args[3];
773
774 if (subCommand == "in" || subCommand == "all")
775 m_udpServer.StartInbound();
776
777 if (subCommand == "out" || subCommand == "all")
778 m_udpServer.StartOutbound();
779 }
780
781 private void HandleStopCommand(string module, string[] args)
782 {
783 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
784 return;
785
786 if (args.Length != 4)
787 {
788 MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>");
789 return;
790 }
791
792 string subCommand = args[3];
793
794 if (subCommand == "in" || subCommand == "all")
795 m_udpServer.StopInbound();
796
797 if (subCommand == "out" || subCommand == "all")
798 m_udpServer.StopOutbound();
799 }
800
801 private void HandlePoolCommand(string module, string[] args)
802 {
803 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
804 return;
805
806 if (args.Length != 4)
807 {
808 MainConsole.Instance.Output("Usage: debug lludp pool <on|off>");
809 return;
810 }
811
812 string enabled = args[3];
813
814 if (enabled == "on")
815 {
816 if (m_udpServer.EnablePools())
817 {
818 m_udpServer.EnablePoolStats();
819 MainConsole.Instance.OutputFormat("Packet pools enabled on {0}", m_udpServer.Scene.Name);
820 }
821 }
822 else if (enabled == "off")
823 {
824 if (m_udpServer.DisablePools())
825 {
826 m_udpServer.DisablePoolStats();
827 MainConsole.Instance.OutputFormat("Packet pools disabled on {0}", m_udpServer.Scene.Name);
828 }
829 }
830 else
831 {
832 MainConsole.Instance.Output("Usage: debug lludp pool <on|off>");
833 }
834 }
835
836 private void HandleAgentUpdateCommand(string module, string[] args)
837 {
838 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
839 return;
840
841 m_udpServer.DiscardInboundAgentUpdates = !m_udpServer.DiscardInboundAgentUpdates;
842
843 MainConsole.Instance.OutputFormat(
844 "Discard AgentUpdates now {0} for {1}", m_udpServer.DiscardInboundAgentUpdates, m_udpServer.Scene.Name);
845 }
846
847 private void HandleStatusCommand(string module, string[] args)
848 {
849 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
850 return;
851
852 MainConsole.Instance.OutputFormat(
853 "IN LLUDP packet processing for {0} is {1}", m_udpServer.Scene.Name, m_udpServer.IsRunningInbound ? "enabled" : "disabled");
854
855 MainConsole.Instance.OutputFormat(
856 "OUT LLUDP packet processing for {0} is {1}", m_udpServer.Scene.Name, m_udpServer.IsRunningOutbound ? "enabled" : "disabled");
857
858 MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_udpServer.Scene.Name, m_udpServer.UsePools ? "on" : "off");
859
860 MainConsole.Instance.OutputFormat(
861 "Packet debug level for new clients is {0}", m_udpServer.DefaultClientPacketDebugLevel);
862 }
863
864 private void HandleOqreCommand(string module, string[] args)
865 {
866 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
867 return;
868
869 if (args.Length != 4)
870 {
871 MainConsole.Instance.Output("Usage: debug lludp oqre <stop|start|status>");
872 return;
873 }
874
875 string subCommand = args[3];
876
877 if (subCommand == "stop")
878 {
879 m_udpServer.OqrEngine.Stop();
880 MainConsole.Instance.OutputFormat("Stopped OQRE for {0}", m_udpServer.Scene.Name);
881 }
882 else if (subCommand == "start")
883 {
884 m_udpServer.OqrEngine.Start();
885 MainConsole.Instance.OutputFormat("Started OQRE for {0}", m_udpServer.Scene.Name);
886 }
887 else if (subCommand == "status")
888 {
889 MainConsole.Instance.OutputFormat("OQRE in {0}", m_udpServer.Scene.Name);
890 MainConsole.Instance.OutputFormat("Running: {0}", m_udpServer.OqrEngine.IsRunning);
891 MainConsole.Instance.OutputFormat(
892 "Requests waiting: {0}",
893 m_udpServer.OqrEngine.IsRunning ? m_udpServer.OqrEngine.JobsWaiting.ToString() : "n/a");
894 }
895 else
896 {
897 MainConsole.Instance.OutputFormat("Unrecognized OQRE subcommand {0}", subCommand);
898 }
899 }
900 }
901} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
index f143c32..f62dc15 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
@@ -78,6 +78,92 @@ 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 #region PacketDropDebugging
111 /// <summary>
112 /// For debugging purposes only... random number generator for dropping
113 /// outbound packets.
114 /// </summary>
115 private Random m_dropRandomGenerator = new Random();
116
117 /// <summary>
118 /// For debugging purposes only... parameters for a simplified
119 /// model of packet loss with bursts, overall drop rate should
120 /// be roughly 1 - m_dropLengthProbability / (m_dropProbabiliy + m_dropLengthProbability)
121 /// which is about 1% for parameters 0.0015 and 0.15
122 /// </summary>
123 private double m_dropProbability = 0.0030;
124 private double m_dropLengthProbability = 0.15;
125 private bool m_dropState = false;
126
127 /// <summary>
128 /// For debugging purposes only... parameters to control the time
129 /// duration over which packet loss bursts can occur, if no packets
130 /// have been sent for m_dropResetTicks milliseconds, then reset the
131 /// state of the packet dropper to its default.
132 /// </summary>
133 private int m_dropLastTick = 0;
134 private int m_dropResetTicks = 500;
135
136 /// <summary>
137 /// Debugging code used to simulate dropped packets with bursts
138 /// </summary>
139 private bool DropOutgoingPacket()
140 {
141 double rnum = m_dropRandomGenerator.NextDouble();
142
143 // if the connection has been idle for awhile (more than m_dropResetTicks) then
144 // reset the state to the default state, don't continue a burst
145 int curtick = Util.EnvironmentTickCount();
146 if (Util.EnvironmentTickCountSubtract(curtick, m_dropLastTick) > m_dropResetTicks)
147 m_dropState = false;
148
149 m_dropLastTick = curtick;
150
151 // if we are dropping packets, then the probability of dropping
152 // this packet is the probability that we stay in the burst
153 if (m_dropState)
154 {
155 m_dropState = (rnum < (1.0 - m_dropLengthProbability)) ? true : false;
156 }
157 else
158 {
159 m_dropState = (rnum < m_dropProbability) ? true : false;
160 }
161
162 return m_dropState;
163 }
164 #endregion PacketDropDebugging
165
166 /// <summary>
81 /// Default constructor 167 /// Default constructor
82 /// </summary> 168 /// </summary>
83 /// <param name="bindAddress">Local IP address to bind the server to</param> 169 /// <param name="bindAddress">Local IP address to bind the server to</param>
@@ -87,6 +173,10 @@ namespace OpenMetaverse
87 { 173 {
88 m_localBindAddress = bindAddress; 174 m_localBindAddress = bindAddress;
89 m_udpPort = port; 175 m_udpPort = port;
176
177 // for debugging purposes only, initializes the random number generator
178 // used for simulating packet loss
179 // m_dropRandomGenerator = new Random();
90 } 180 }
91 181
92 /// <summary> 182 /// <summary>
@@ -105,12 +195,14 @@ namespace OpenMetaverse
105 /// manner (not throwing an exception when the remote side resets the 195 /// manner (not throwing an exception when the remote side resets the
106 /// connection). This call is ignored on Mono where the flag is not 196 /// connection). This call is ignored on Mono where the flag is not
107 /// necessary</remarks> 197 /// necessary</remarks>
108 public void StartInbound(int recvBufferSize, bool asyncPacketHandling) 198 public virtual void StartInbound(int recvBufferSize, bool asyncPacketHandling)
109 { 199 {
110 m_asyncPacketHandling = asyncPacketHandling; 200 m_asyncPacketHandling = asyncPacketHandling;
111 201
112 if (!IsRunningInbound) 202 if (!IsRunningInbound)
113 { 203 {
204 m_log.DebugFormat("[UDPBASE]: Starting inbound UDP loop");
205
114 const int SIO_UDP_CONNRESET = -1744830452; 206 const int SIO_UDP_CONNRESET = -1744830452;
115 207
116 IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort); 208 IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort);
@@ -126,6 +218,17 @@ namespace OpenMetaverse
126 218
127 try 219 try
128 { 220 {
221 if (m_udpSocket.Ttl < 128)
222 {
223 m_udpSocket.Ttl = 128;
224 }
225 }
226 catch (SocketException)
227 {
228 m_log.Debug("[UDPBASE]: Failed to increase default TTL");
229 }
230 try
231 {
129 // This udp socket flag is not supported under mono, 232 // This udp socket flag is not supported under mono,
130 // so we'll catch the exception and continue 233 // so we'll catch the exception and continue
131 m_udpSocket.IOControl(SIO_UDP_CONNRESET, new byte[] { 0 }, null); 234 m_udpSocket.IOControl(SIO_UDP_CONNRESET, new byte[] { 0 }, null);
@@ -136,6 +239,12 @@ namespace OpenMetaverse
136 m_log.Debug("[UDPBASE]: SIO_UDP_CONNRESET flag not supported on this platform, ignoring"); 239 m_log.Debug("[UDPBASE]: SIO_UDP_CONNRESET flag not supported on this platform, ignoring");
137 } 240 }
138 241
242 // On at least Mono 3.2.8, multiple UDP sockets can bind to the same port by default. At the moment
243 // we never want two regions to listen on the same port as they cannot demultiplex each other's messages,
244 // leading to a confusing bug.
245 // By default, Windows does not allow two sockets to bind to the same port.
246 m_udpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false);
247
139 if (recvBufferSize != 0) 248 if (recvBufferSize != 0)
140 m_udpSocket.ReceiveBufferSize = recvBufferSize; 249 m_udpSocket.ReceiveBufferSize = recvBufferSize;
141 250
@@ -153,30 +262,32 @@ namespace OpenMetaverse
153 /// <summary> 262 /// <summary>
154 /// Start outbound UDP packet handling. 263 /// Start outbound UDP packet handling.
155 /// </summary> 264 /// </summary>
156 public void StartOutbound() 265 public virtual void StartOutbound()
157 { 266 {
267 m_log.DebugFormat("[UDPBASE]: Starting outbound UDP loop");
268
158 IsRunningOutbound = true; 269 IsRunningOutbound = true;
159 } 270 }
160 271
161 public void StopInbound() 272 public virtual void StopInbound()
162 { 273 {
163 if (IsRunningInbound) 274 if (IsRunningInbound)
164 { 275 {
165 // wait indefinitely for a writer lock. Once this is called, the .NET runtime 276 m_log.DebugFormat("[UDPBASE]: Stopping inbound UDP loop");
166 // will deny any more reader locks, in effect blocking all other send/receive 277
167 // threads. Once we have the lock, we set IsRunningInbound = false to inform the other
168 // threads that the socket is closed.
169 IsRunningInbound = false; 278 IsRunningInbound = false;
170 m_udpSocket.Close(); 279 m_udpSocket.Close();
171 } 280 }
172 } 281 }
173 282
174 public void StopOutbound() 283 public virtual void StopOutbound()
175 { 284 {
285 m_log.DebugFormat("[UDPBASE]: Stopping outbound UDP loop");
286
176 IsRunningOutbound = false; 287 IsRunningOutbound = false;
177 } 288 }
178 289
179 protected virtual bool EnablePools() 290 public virtual bool EnablePools()
180 { 291 {
181 if (!UsePools) 292 if (!UsePools)
182 { 293 {
@@ -190,7 +301,7 @@ namespace OpenMetaverse
190 return false; 301 return false;
191 } 302 }
192 303
193 protected virtual bool DisablePools() 304 public virtual bool DisablePools()
194 { 305 {
195 if (UsePools) 306 if (UsePools)
196 { 307 {
@@ -261,7 +372,16 @@ namespace OpenMetaverse
261 m_log.Warn("[UDPBASE]: Salvaged the UDP listener on port " + m_udpPort); 372 m_log.Warn("[UDPBASE]: Salvaged the UDP listener on port " + m_udpPort);
262 } 373 }
263 } 374 }
264 catch (ObjectDisposedException) { } 375 catch (ObjectDisposedException e)
376 {
377 m_log.Error(
378 string.Format("[UDPBASE]: Error processing UDP begin receive {0}. Exception ", UdpReceives), e);
379 }
380 catch (Exception e)
381 {
382 m_log.Error(
383 string.Format("[UDPBASE]: Error processing UDP begin receive {0}. Exception ", UdpReceives), e);
384 }
265 } 385 }
266 } 386 }
267 387
@@ -271,17 +391,21 @@ namespace OpenMetaverse
271 // to AsyncBeginReceive 391 // to AsyncBeginReceive
272 if (IsRunningInbound) 392 if (IsRunningInbound)
273 { 393 {
394 UdpReceives++;
395
274 // Asynchronous mode will start another receive before the 396 // Asynchronous mode will start another receive before the
275 // callback for this packet is even fired. Very parallel :-) 397 // callback for this packet is even fired. Very parallel :-)
276 if (m_asyncPacketHandling) 398 if (m_asyncPacketHandling)
277 AsyncBeginReceive(); 399 AsyncBeginReceive();
278 400
279 // get the buffer that was created in AsyncBeginReceive
280 // this is the received data
281 UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState;
282
283 try 401 try
284 { 402 {
403 // get the buffer that was created in AsyncBeginReceive
404 // this is the received data
405 UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState;
406
407 int startTick = Util.EnvironmentTickCount();
408
285 // get the length of data actually read from the socket, store it with the 409 // get the length of data actually read from the socket, store it with the
286 // buffer 410 // buffer
287 buffer.DataLength = m_udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint); 411 buffer.DataLength = m_udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint);
@@ -289,9 +413,42 @@ namespace OpenMetaverse
289 // call the abstract method PacketReceived(), passing the buffer that 413 // call the abstract method PacketReceived(), passing the buffer that
290 // has just been filled from the socket read. 414 // has just been filled from the socket read.
291 PacketReceived(buffer); 415 PacketReceived(buffer);
416
417 // If more than one thread can be calling AsyncEndReceive() at once (e.g. if m_asyncPacketHandler)
418 // then a particular stat may be inaccurate due to a race condition. We won't worry about this
419 // since this should be rare and won't cause a runtime problem.
420 if (m_currentReceiveTimeSamples >= s_receiveTimeSamples)
421 {
422 AverageReceiveTicksForLastSamplePeriod
423 = (float)m_receiveTicksInCurrentSamplePeriod / s_receiveTimeSamples;
424
425 m_receiveTicksInCurrentSamplePeriod = 0;
426 m_currentReceiveTimeSamples = 0;
427 }
428 else
429 {
430 m_receiveTicksInCurrentSamplePeriod += Util.EnvironmentTickCountSubtract(startTick);
431 m_currentReceiveTimeSamples++;
432 }
433 }
434 catch (SocketException se)
435 {
436 m_log.Error(
437 string.Format(
438 "[UDPBASE]: Error processing UDP end receive {0}, socket error code {1}. Exception ",
439 UdpReceives, se.ErrorCode),
440 se);
441 }
442 catch (ObjectDisposedException e)
443 {
444 m_log.Error(
445 string.Format("[UDPBASE]: Error processing UDP end receive {0}. Exception ", UdpReceives), e);
446 }
447 catch (Exception e)
448 {
449 m_log.Error(
450 string.Format("[UDPBASE]: Error processing UDP end receive {0}. Exception ", UdpReceives), e);
292 } 451 }
293 catch (SocketException) { }
294 catch (ObjectDisposedException) { }
295 finally 452 finally
296 { 453 {
297// if (UsePools) 454// if (UsePools)
@@ -302,14 +459,19 @@ namespace OpenMetaverse
302 if (!m_asyncPacketHandling) 459 if (!m_asyncPacketHandling)
303 AsyncBeginReceive(); 460 AsyncBeginReceive();
304 } 461 }
305
306 } 462 }
307 } 463 }
308 464
309 public void AsyncBeginSend(UDPPacketBuffer buf) 465 public void AsyncBeginSend(UDPPacketBuffer buf)
310 { 466 {
311 if (IsRunningOutbound) 467// if (IsRunningOutbound)
312 { 468// {
469
470 // This is strictly for debugging purposes to simulate dropped
471 // packets when testing throttles & retransmission code
472 // if (DropOutgoingPacket())
473 // return;
474
313 try 475 try
314 { 476 {
315 m_udpSocket.BeginSendTo( 477 m_udpSocket.BeginSendTo(
@@ -323,7 +485,7 @@ namespace OpenMetaverse
323 } 485 }
324 catch (SocketException) { } 486 catch (SocketException) { }
325 catch (ObjectDisposedException) { } 487 catch (ObjectDisposedException) { }
326 } 488// }
327 } 489 }
328 490
329 void AsyncEndSend(IAsyncResult result) 491 void AsyncEndSend(IAsyncResult result)
@@ -332,6 +494,8 @@ namespace OpenMetaverse
332 { 494 {
333// UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState; 495// UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState;
334 m_udpSocket.EndSendTo(result); 496 m_udpSocket.EndSendTo(result);
497
498 UdpSends++;
335 } 499 }
336 catch (SocketException) { } 500 catch (SocketException) { }
337 catch (ObjectDisposedException) { } 501 catch (ObjectDisposedException) { }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
index 1fdc410..5a2bcee 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
@@ -145,39 +145,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
145 return packet; 145 return packet;
146 } 146 }
147 147
148 // private byte[] decoded_header = new byte[10];
149 private static PacketType GetType(byte[] bytes) 148 private static PacketType GetType(byte[] bytes)
150 { 149 {
151 byte[] decoded_header = new byte[10 + 8];
152 ushort id; 150 ushort id;
153 PacketFrequency freq; 151 PacketFrequency freq;
152 bool isZeroCoded = (bytes[0] & Helpers.MSG_ZEROCODED) != 0;
154 153
155 if ((bytes[0] & Helpers.MSG_ZEROCODED) != 0) 154 if (bytes[6] == 0xFF)
156 { 155 {
157 Helpers.ZeroDecode(bytes, 16, decoded_header); 156 if (bytes[7] == 0xFF)
158 }
159 else
160 {
161 Buffer.BlockCopy(bytes, 0, decoded_header, 0, 10);
162 }
163
164 if (decoded_header[6] == 0xFF)
165 {
166 if (decoded_header[7] == 0xFF)
167 { 157 {
168 id = (ushort) ((decoded_header[8] << 8) + decoded_header[9]);
169 freq = PacketFrequency.Low; 158 freq = PacketFrequency.Low;
159 if (isZeroCoded && bytes[8] == 0)
160 id = bytes[10];
161 else
162 id = (ushort)((bytes[8] << 8) + bytes[9]);
170 } 163 }
171 else 164 else
172 { 165 {
173 id = decoded_header[7];
174 freq = PacketFrequency.Medium; 166 freq = PacketFrequency.Medium;
167 id = bytes[7];
175 } 168 }
176 } 169 }
177 else 170 else
178 { 171 {
179 id = decoded_header[6];
180 freq = PacketFrequency.High; 172 freq = PacketFrequency.High;
173 id = bytes[6];
181 } 174 }
182 175
183 return Packet.GetType(id, freq); 176 return Packet.GetType(id, freq);
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs b/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs
index af2f6f8..bf505b4 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs
@@ -1,6 +1,7 @@
1using System.Reflection; 1using System.Reflection;
2using System.Runtime.CompilerServices; 2using System.Runtime.CompilerServices;
3using System.Runtime.InteropServices; 3using System.Runtime.InteropServices;
4using Mono.Addins;
4 5
5// General Information about an assembly is controlled through the following 6// General Information about an assembly is controlled through the following
6// set of attributes. Change these attribute values to modify the information 7// set of attributes. Change these attribute values to modify the information
@@ -29,5 +30,7 @@ using System.Runtime.InteropServices;
29// Build Number 30// Build Number
30// Revision 31// Revision
31// 32//
32[assembly: AssemblyVersion("0.7.5.*")] 33[assembly: AssemblyVersion("0.8.3.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 34
35[assembly: Addin("LindenUDP", OpenSim.VersionInfo.VersionNumber)]
36[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs
index 556df30..a935dd2 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs
@@ -33,9 +33,9 @@ using NUnit.Framework;
33using OpenMetaverse; 33using OpenMetaverse;
34using OpenMetaverse.Packets; 34using OpenMetaverse.Packets;
35using OpenSim.Framework; 35using OpenSim.Framework;
36using OpenSim.Framework.Monitoring;
36using OpenSim.Region.Framework.Scenes; 37using OpenSim.Region.Framework.Scenes;
37using OpenSim.Tests.Common; 38using OpenSim.Tests.Common;
38using OpenSim.Tests.Common.Mock;
39 39
40namespace OpenSim.Region.ClientStack.LindenUDP.Tests 40namespace OpenSim.Region.ClientStack.LindenUDP.Tests
41{ 41{
@@ -46,7 +46,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
46 public class BasicCircuitTests : OpenSimTestCase 46 public class BasicCircuitTests : OpenSimTestCase
47 { 47 {
48 private Scene m_scene; 48 private Scene m_scene;
49 private TestLLUDPServer m_udpServer;
50 49
51 [TestFixtureSetUp] 50 [TestFixtureSetUp]
52 public void FixtureInit() 51 public void FixtureInit()
@@ -69,74 +68,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
69 { 68 {
70 base.SetUp(); 69 base.SetUp();
71 m_scene = new SceneHelpers().SetupScene(); 70 m_scene = new SceneHelpers().SetupScene();
71 StatsManager.SimExtraStats = new SimExtraStatsCollector();
72 } 72 }
73 73
74 /// <summary> 74// /// <summary>
75 /// Build an object name packet for test purposes 75// /// Build an object name packet for test purposes
76 /// </summary> 76// /// </summary>
77 /// <param name="objectLocalId"></param> 77// /// <param name="objectLocalId"></param>
78 /// <param name="objectName"></param> 78// /// <param name="objectName"></param>
79 private ObjectNamePacket BuildTestObjectNamePacket(uint objectLocalId, string objectName) 79// private ObjectNamePacket BuildTestObjectNamePacket(uint objectLocalId, string objectName)
80 { 80// {
81 ObjectNamePacket onp = new ObjectNamePacket(); 81// ObjectNamePacket onp = new ObjectNamePacket();
82 ObjectNamePacket.ObjectDataBlock odb = new ObjectNamePacket.ObjectDataBlock(); 82// ObjectNamePacket.ObjectDataBlock odb = new ObjectNamePacket.ObjectDataBlock();
83 odb.LocalID = objectLocalId; 83// odb.LocalID = objectLocalId;
84 odb.Name = Utils.StringToBytes(objectName); 84// odb.Name = Utils.StringToBytes(objectName);
85 onp.ObjectData = new ObjectNamePacket.ObjectDataBlock[] { odb }; 85// onp.ObjectData = new ObjectNamePacket.ObjectDataBlock[] { odb };
86 onp.Header.Zerocoded = false; 86// onp.Header.Zerocoded = false;
87 87//
88 return onp; 88// return onp;
89 } 89// }
90 90//
91 private void AddUdpServer()
92 {
93 AddUdpServer(new IniConfigSource());
94 }
95
96 private void AddUdpServer(IniConfigSource configSource)
97 {
98 uint port = 0;
99 AgentCircuitManager acm = m_scene.AuthenticateHandler;
100
101 m_udpServer = new TestLLUDPServer(IPAddress.Any, ref port, 0, false, configSource, acm);
102 m_udpServer.AddScene(m_scene);
103 }
104
105 /// <summary>
106 /// Used by tests that aren't testing this stage.
107 /// </summary>
108 private ScenePresence AddClient()
109 {
110 UUID myAgentUuid = TestHelpers.ParseTail(0x1);
111 UUID mySessionUuid = TestHelpers.ParseTail(0x2);
112 uint myCircuitCode = 123456;
113 IPEndPoint testEp = new IPEndPoint(IPAddress.Loopback, 999);
114
115 UseCircuitCodePacket uccp = new UseCircuitCodePacket();
116
117 UseCircuitCodePacket.CircuitCodeBlock uccpCcBlock
118 = new UseCircuitCodePacket.CircuitCodeBlock();
119 uccpCcBlock.Code = myCircuitCode;
120 uccpCcBlock.ID = myAgentUuid;
121 uccpCcBlock.SessionID = mySessionUuid;
122 uccp.CircuitCode = uccpCcBlock;
123
124 byte[] uccpBytes = uccp.ToBytes();
125 UDPPacketBuffer upb = new UDPPacketBuffer(testEp, uccpBytes.Length);
126 upb.DataLength = uccpBytes.Length; // God knows why this isn't set by the constructor.
127 Buffer.BlockCopy(uccpBytes, 0, upb.Data, 0, uccpBytes.Length);
128
129 AgentCircuitData acd = new AgentCircuitData();
130 acd.AgentID = myAgentUuid;
131 acd.SessionID = mySessionUuid;
132
133 m_scene.AuthenticateHandler.AddNewCircuit(myCircuitCode, acd);
134
135 m_udpServer.PacketReceived(upb);
136
137 return m_scene.GetScenePresence(myAgentUuid);
138 }
139
140 /// <summary> 91 /// <summary>
141 /// Test adding a client to the stack 92 /// Test adding a client to the stack
142 /// </summary> 93 /// </summary>
@@ -146,7 +97,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
146 TestHelpers.InMethod(); 97 TestHelpers.InMethod();
147// TestHelpers.EnableLogging(); 98// TestHelpers.EnableLogging();
148 99
149 AddUdpServer(); 100 TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(m_scene);
150 101
151 UUID myAgentUuid = TestHelpers.ParseTail(0x1); 102 UUID myAgentUuid = TestHelpers.ParseTail(0x1);
152 UUID mySessionUuid = TestHelpers.ParseTail(0x2); 103 UUID mySessionUuid = TestHelpers.ParseTail(0x2);
@@ -167,7 +118,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
167 upb.DataLength = uccpBytes.Length; // God knows why this isn't set by the constructor. 118 upb.DataLength = uccpBytes.Length; // God knows why this isn't set by the constructor.
168 Buffer.BlockCopy(uccpBytes, 0, upb.Data, 0, uccpBytes.Length); 119 Buffer.BlockCopy(uccpBytes, 0, upb.Data, 0, uccpBytes.Length);
169 120
170 m_udpServer.PacketReceived(upb); 121 udpServer.PacketReceived(upb);
171 122
172 // Presence shouldn't exist since the circuit manager doesn't know about this circuit for authentication yet 123 // Presence shouldn't exist since the circuit manager doesn't know about this circuit for authentication yet
173 Assert.That(m_scene.GetScenePresence(myAgentUuid), Is.Null); 124 Assert.That(m_scene.GetScenePresence(myAgentUuid), Is.Null);
@@ -178,15 +129,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
178 129
179 m_scene.AuthenticateHandler.AddNewCircuit(myCircuitCode, acd); 130 m_scene.AuthenticateHandler.AddNewCircuit(myCircuitCode, acd);
180 131
181 m_udpServer.PacketReceived(upb); 132 udpServer.PacketReceived(upb);
182 133
183 // Should succeed now 134 // Should succeed now
184 ScenePresence sp = m_scene.GetScenePresence(myAgentUuid); 135 ScenePresence sp = m_scene.GetScenePresence(myAgentUuid);
185 Assert.That(sp.UUID, Is.EqualTo(myAgentUuid)); 136 Assert.That(sp.UUID, Is.EqualTo(myAgentUuid));
186 137
187 Assert.That(m_udpServer.PacketsSent.Count, Is.EqualTo(1)); 138 Assert.That(udpServer.PacketsSent.Count, Is.EqualTo(1));
188 139
189 Packet packet = m_udpServer.PacketsSent[0]; 140 Packet packet = udpServer.PacketsSent[0];
190 Assert.That(packet, Is.InstanceOf(typeof(PacketAckPacket))); 141 Assert.That(packet, Is.InstanceOf(typeof(PacketAckPacket)));
191 142
192 PacketAckPacket ackPacket = packet as PacketAckPacket; 143 PacketAckPacket ackPacket = packet as PacketAckPacket;
@@ -203,15 +154,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
203 IniConfigSource ics = new IniConfigSource(); 154 IniConfigSource ics = new IniConfigSource();
204 IConfig config = ics.AddConfig("ClientStack.LindenUDP"); 155 IConfig config = ics.AddConfig("ClientStack.LindenUDP");
205 config.Set("AckTimeout", -1); 156 config.Set("AckTimeout", -1);
206 AddUdpServer(ics); 157 TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(m_scene, ics);
158
159 ScenePresence sp
160 = ClientStackHelpers.AddChildClient(
161 m_scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456);
207 162
208 ScenePresence sp = AddClient(); 163 udpServer.ClientOutgoingPacketHandler(sp.ControllingClient, true, false, false);
209 m_udpServer.ClientOutgoingPacketHandler(sp.ControllingClient, true, false, false);
210 164
211 ScenePresence spAfterAckTimeout = m_scene.GetScenePresence(sp.UUID); 165 ScenePresence spAfterAckTimeout = m_scene.GetScenePresence(sp.UUID);
212 Assert.That(spAfterAckTimeout, Is.Null); 166 Assert.That(spAfterAckTimeout, Is.Null);
213
214// TestHelpers.DisableLogging();
215 } 167 }
216 168
217// /// <summary> 169// /// <summary>
@@ -233,7 +185,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
233// testLLUDPServer.RemoveClientCircuit(myCircuitCode); 185// testLLUDPServer.RemoveClientCircuit(myCircuitCode);
234// Assert.IsFalse(testLLUDPServer.HasCircuit(myCircuitCode)); 186// Assert.IsFalse(testLLUDPServer.HasCircuit(myCircuitCode));
235// 187//
236// // Check that removing a non-existant circuit doesn't have any bad effects 188// // Check that removing a non-existent circuit doesn't have any bad effects
237// testLLUDPServer.RemoveClientCircuit(101); 189// testLLUDPServer.RemoveClientCircuit(101);
238// Assert.IsFalse(testLLUDPServer.HasCircuit(101)); 190// Assert.IsFalse(testLLUDPServer.HasCircuit(101));
239// } 191// }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs
index 7d9f581..6c57e6d 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs
@@ -29,6 +29,7 @@ using System;
29using System.IO; 29using System.IO;
30using System.Net; 30using System.Net;
31using System.Reflection; 31using System.Reflection;
32using System.Threading;
32using log4net.Config; 33using log4net.Config;
33using Nini.Config; 34using Nini.Config;
34using NUnit.Framework; 35using NUnit.Framework;
@@ -38,7 +39,6 @@ using OpenSim.Framework;
38using OpenSim.Region.CoreModules.Agent.TextureSender; 39using OpenSim.Region.CoreModules.Agent.TextureSender;
39using OpenSim.Region.Framework.Scenes; 40using OpenSim.Region.Framework.Scenes;
40using OpenSim.Tests.Common; 41using OpenSim.Tests.Common;
41using OpenSim.Tests.Common.Mock;
42 42
43namespace OpenSim.Region.ClientStack.LindenUDP.Tests 43namespace OpenSim.Region.ClientStack.LindenUDP.Tests
44{ 44{
@@ -53,6 +53,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
53 [TestFixtureSetUp] 53 [TestFixtureSetUp]
54 public void FixtureInit() 54 public void FixtureInit()
55 { 55 {
56 // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
57 Util.FireAndForgetMethod = FireAndForgetMethod.None;
58
56 using ( 59 using (
57 Stream resource 60 Stream resource
58 = GetType().Assembly.GetManifestResourceStream( 61 = GetType().Assembly.GetManifestResourceStream(
@@ -72,9 +75,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
72 } 75 }
73 } 76 }
74 77
78 [TestFixtureTearDown]
79 public void TearDown()
80 {
81 // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
82 // threads. Possibly, later tests should be rewritten not to worry about such things.
83 Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
84 }
85
75 [SetUp] 86 [SetUp]
76 public void SetUp() 87 public override void SetUp()
77 { 88 {
89 base.SetUp();
90
78 UUID userId = TestHelpers.ParseTail(0x3); 91 UUID userId = TestHelpers.ParseTail(0x3);
79 92
80 J2KDecoderModule j2kdm = new J2KDecoderModule(); 93 J2KDecoderModule j2kdm = new J2KDecoderModule();
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs
deleted file mode 100644
index 119a677..0000000
--- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs
+++ /dev/null
@@ -1,78 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System.Net;
29using OpenMetaverse;
30using OpenSim.Framework;
31using OpenSim.Region.Framework.Scenes;
32using GridRegion = OpenSim.Services.Interfaces.GridRegion;
33
34namespace OpenSim.Region.ClientStack.LindenUDP.Tests
35{
36 /// <summary>
37 /// Mock scene for unit tests
38 /// </summary>
39 public class MockScene : SceneBase
40 {
41 public int ObjectNameCallsReceived
42 {
43 get { return m_objectNameCallsReceived; }
44 }
45 protected int m_objectNameCallsReceived;
46
47 public MockScene() : base(new RegionInfo(1000, 1000, null, null))
48 {
49 m_regStatus = RegionStatus.Up;
50 }
51
52 public override void Update(int frames) {}
53 public override void LoadWorldMap() {}
54
55 public override ISceneAgent AddNewClient(IClientAPI client, PresenceType type)
56 {
57 client.OnObjectName += RecordObjectNameCall;
58
59 // FIXME
60 return null;
61 }
62
63 public override void RemoveClient(UUID agentID, bool someReason) {}
64// public override void CloseAllAgents(uint circuitcode) {}
65 public override bool CheckClient(UUID clientId, IPEndPoint endPoint) { return true; }
66 public override void OtherRegionUp(GridRegion otherRegion) { }
67
68 public override bool TryGetScenePresence(UUID uuid, out ScenePresence sp) { sp = null; return false; }
69
70 /// <summary>
71 /// Doesn't really matter what the call is - we're using this to test that a packet has actually been received
72 /// </summary>
73 protected void RecordObjectNameCall(IClientAPI remoteClient, uint localID, string message)
74 {
75 m_objectNameCallsReceived++;
76 }
77 }
78}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs
index 5f73a94..92f1fc3 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs
@@ -30,7 +30,6 @@ using NUnit.Framework;
30using OpenMetaverse; 30using OpenMetaverse;
31using OpenMetaverse.Packets; 31using OpenMetaverse.Packets;
32using OpenSim.Framework; 32using OpenSim.Framework;
33using OpenSim.Tests.Common.Mock;
34using OpenSim.Tests.Common; 33using OpenSim.Tests.Common;
35 34
36namespace OpenSim.Region.ClientStack.LindenUDP.Tests 35namespace OpenSim.Region.ClientStack.LindenUDP.Tests
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/TestLLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/TestLLUDPServer.cs
deleted file mode 100644
index 27b9e5b..0000000
--- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/TestLLUDPServer.cs
+++ /dev/null
@@ -1,170 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Net;
31using System.Net.Sockets;
32using Nini.Config;
33using OpenMetaverse.Packets;
34using OpenSim.Framework;
35
36namespace OpenSim.Region.ClientStack.LindenUDP.Tests
37{
38 /// <summary>
39 /// This class enables regression testing of the LLUDPServer by allowing us to intercept outgoing data.
40 /// </summary>
41 public class TestLLUDPServer : LLUDPServer
42 {
43 public List<Packet> PacketsSent { get; private set; }
44
45 public TestLLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager)
46 : base(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager)
47 {
48 PacketsSent = new List<Packet>();
49 }
50
51 public override void SendAckImmediate(IPEndPoint remoteEndpoint, PacketAckPacket ack)
52 {
53 PacketsSent.Add(ack);
54 }
55
56 public override void SendPacket(
57 LLUDPClient udpClient, Packet packet, ThrottleOutPacketType category, bool allowSplitting, UnackedPacketMethod method)
58 {
59 PacketsSent.Add(packet);
60 }
61
62 public void ClientOutgoingPacketHandler(IClientAPI client, bool resendUnacked, bool sendAcks, bool sendPing)
63 {
64 m_resendUnacked = resendUnacked;
65 m_sendAcks = sendAcks;
66 m_sendPing = sendPing;
67
68 ClientOutgoingPacketHandler(client);
69 }
70
71//// /// <summary>
72//// /// The chunks of data to pass to the LLUDPServer when it calls EndReceive
73//// /// </summary>
74//// protected Queue<ChunkSenderTuple> m_chunksToLoad = new Queue<ChunkSenderTuple>();
75//
76//// protected override void BeginReceive()
77//// {
78//// if (m_chunksToLoad.Count > 0 && m_chunksToLoad.Peek().BeginReceiveException)
79//// {
80//// ChunkSenderTuple tuple = m_chunksToLoad.Dequeue();
81//// reusedEpSender = tuple.Sender;
82//// throw new SocketException();
83//// }
84//// }
85//
86//// protected override bool EndReceive(out int numBytes, IAsyncResult result, ref EndPoint epSender)
87//// {
88//// numBytes = 0;
89////
90//// //m_log.Debug("Queue size " + m_chunksToLoad.Count);
91////
92//// if (m_chunksToLoad.Count <= 0)
93//// return false;
94////
95//// ChunkSenderTuple tuple = m_chunksToLoad.Dequeue();
96//// RecvBuffer = tuple.Data;
97//// numBytes = tuple.Data.Length;
98//// epSender = tuple.Sender;
99////
100//// return true;
101//// }
102//
103//// public override void SendPacketTo(byte[] buffer, int size, SocketFlags flags, uint circuitcode)
104//// {
105//// // Don't do anything just yet
106//// }
107//
108// /// <summary>
109// /// Signal that this chunk should throw an exception on Socket.BeginReceive()
110// /// </summary>
111// /// <param name="epSender"></param>
112// public void LoadReceiveWithBeginException(EndPoint epSender)
113// {
114// ChunkSenderTuple tuple = new ChunkSenderTuple(epSender);
115// tuple.BeginReceiveException = true;
116// m_chunksToLoad.Enqueue(tuple);
117// }
118//
119// /// <summary>
120// /// Load some data to be received by the LLUDPServer on the next receive call
121// /// </summary>
122// /// <param name="data"></param>
123// /// <param name="epSender"></param>
124// public void LoadReceive(byte[] data, EndPoint epSender)
125// {
126// m_chunksToLoad.Enqueue(new ChunkSenderTuple(data, epSender));
127// }
128//
129// /// <summary>
130// /// Load a packet to be received by the LLUDPServer on the next receive call
131// /// </summary>
132// /// <param name="packet"></param>
133// public void LoadReceive(Packet packet, EndPoint epSender)
134// {
135// LoadReceive(packet.ToBytes(), epSender);
136// }
137//
138// /// <summary>
139// /// Calls the protected asynchronous result method. This fires out all data chunks currently queued for send
140// /// </summary>
141// /// <param name="result"></param>
142// public void ReceiveData(IAsyncResult result)
143// {
144// // Doesn't work the same way anymore
145//// while (m_chunksToLoad.Count > 0)
146//// OnReceivedData(result);
147// }
148 }
149
150 /// <summary>
151 /// Record the data and sender tuple
152 /// </summary>
153 public class ChunkSenderTuple
154 {
155 public byte[] Data;
156 public EndPoint Sender;
157 public bool BeginReceiveException;
158
159 public ChunkSenderTuple(byte[] data, EndPoint sender)
160 {
161 Data = data;
162 Sender = sender;
163 }
164
165 public ChunkSenderTuple(EndPoint sender)
166 {
167 Sender = sender;
168 }
169 }
170}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs
new file mode 100644
index 0000000..3c82a78
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs
@@ -0,0 +1,427 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using Nini.Config;
30using NUnit.Framework;
31using OpenMetaverse.Packets;
32using OpenSim.Framework;
33using OpenSim.Region.Framework.Scenes;
34using OpenSim.Tests.Common;
35
36namespace OpenSim.Region.ClientStack.LindenUDP.Tests
37{
38 [TestFixture]
39 public class ThrottleTests : OpenSimTestCase
40 {
41 [TestFixtureSetUp]
42 public void FixtureInit()
43 {
44 // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
45 Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest;
46 }
47
48 [TestFixtureTearDown]
49 public void TearDown()
50 {
51 // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
52 // threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression
53 // tests really shouldn't).
54 Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
55 }
56
57 [Test]
58 public void TestSetRequestDripRate()
59 {
60 TestHelpers.InMethod();
61
62 TokenBucket tb = new TokenBucket("tb", null, 5000, 0);
63 AssertRates(tb, 5000, 0, 5000, 0);
64
65 tb.RequestedDripRate = 4000;
66 AssertRates(tb, 4000, 0, 4000, 0);
67
68 tb.RequestedDripRate = 6000;
69 AssertRates(tb, 6000, 0, 6000, 0);
70 }
71
72 [Test]
73 public void TestSetRequestDripRateWithMax()
74 {
75 TestHelpers.InMethod();
76
77 TokenBucket tb = new TokenBucket("tb", null, 5000, 10000);
78 AssertRates(tb, 5000, 0, 5000, 10000);
79
80 tb.RequestedDripRate = 4000;
81 AssertRates(tb, 4000, 0, 4000, 10000);
82
83 tb.RequestedDripRate = 6000;
84 AssertRates(tb, 6000, 0, 6000, 10000);
85
86 tb.RequestedDripRate = 12000;
87 AssertRates(tb, 10000, 0, 10000, 10000);
88 }
89
90 [Test]
91 public void TestSetRequestDripRateWithChildren()
92 {
93 TestHelpers.InMethod();
94
95 TokenBucket tbParent = new TokenBucket("tbParent", null, 0, 0);
96 TokenBucket tbChild1 = new TokenBucket("tbChild1", tbParent, 3000, 0);
97 TokenBucket tbChild2 = new TokenBucket("tbChild2", tbParent, 5000, 0);
98
99 AssertRates(tbParent, 8000, 8000, 8000, 0);
100 AssertRates(tbChild1, 3000, 0, 3000, 0);
101 AssertRates(tbChild2, 5000, 0, 5000, 0);
102
103 // Test: Setting a parent request greater than total children requests.
104 tbParent.RequestedDripRate = 10000;
105
106 AssertRates(tbParent, 10000, 8000, 8000, 0);
107 AssertRates(tbChild1, 3000, 0, 3000, 0);
108 AssertRates(tbChild2, 5000, 0, 5000, 0);
109
110 // Test: Setting a parent request lower than total children requests.
111 tbParent.RequestedDripRate = 6000;
112
113 AssertRates(tbParent, 6000, 8000, 6000, 0);
114 AssertRates(tbChild1, 3000, 0, 6000 / 8 * 3, 0);
115 AssertRates(tbChild2, 5000, 0, 6000 / 8 * 5, 0);
116 }
117
118 private void AssertRates(
119 TokenBucket tb, double requestedDripRate, double totalDripRequest, double dripRate, double maxDripRate)
120 {
121 Assert.AreEqual((int)requestedDripRate, tb.RequestedDripRate, "Requested drip rate");
122 Assert.AreEqual((int)totalDripRequest, tb.TotalDripRequest, "Total drip request");
123 Assert.AreEqual((int)dripRate, tb.DripRate, "Drip rate");
124 Assert.AreEqual((int)maxDripRate, tb.MaxDripRate, "Max drip rate");
125 }
126
127 [Test]
128 public void TestClientThrottleSetNoLimit()
129 {
130 TestHelpers.InMethod();
131// TestHelpers.EnableLogging();
132
133 Scene scene = new SceneHelpers().SetupScene();
134 TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene);
135
136 ScenePresence sp
137 = ClientStackHelpers.AddChildClient(
138 scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456);
139
140 LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
141
142 udpServer.Throttle.DebugLevel = 1;
143 udpClient.ThrottleDebugLevel = 1;
144
145 int resendBytes = 1000;
146 int landBytes = 2000;
147 int windBytes = 3000;
148 int cloudBytes = 4000;
149 int taskBytes = 5000;
150 int textureBytes = 6000;
151 int assetBytes = 7000;
152
153 SetThrottles(
154 udpClient, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes);
155
156 // We expect this to be lower because of the minimum bound set by MTU
157 int totalBytes = LLUDPServer.MTU + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes;
158
159 AssertThrottles(
160 udpClient,
161 LLUDPServer.MTU, landBytes, windBytes, cloudBytes, taskBytes,
162 textureBytes, assetBytes, totalBytes, 0, 0);
163 }
164
165 [Test]
166 public void TestClientThrottleAdaptiveNoLimit()
167 {
168 TestHelpers.InMethod();
169// TestHelpers.EnableLogging();
170
171 Scene scene = new SceneHelpers().SetupScene();
172
173 IniConfigSource ics = new IniConfigSource();
174 IConfig config = ics.AddConfig("ClientStack.LindenUDP");
175 config.Set("enable_adaptive_throttles", true);
176 config.Set("adaptive_throttle_min_bps", 32000);
177
178 TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene, ics);
179
180 ScenePresence sp
181 = ClientStackHelpers.AddChildClient(
182 scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456);
183
184 LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
185
186 udpServer.Throttle.DebugLevel = 1;
187 udpClient.ThrottleDebugLevel = 1;
188
189 // Total is 275000
190 int resendBytes = 5000; // this is set low to test the minimum throttle override
191 int landBytes = 20000;
192 int windBytes = 30000;
193 int cloudBytes = 40000;
194 int taskBytes = 50000;
195 int textureBytes = 60000;
196 int assetBytes = 70000;
197 int totalBytes = resendBytes + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes;
198
199 SetThrottles(
200 udpClient, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes);
201
202 // Ratio of current adaptive drip rate to requested bytes, minimum rate is 32000
203 double commitRatio = 32000.0 / totalBytes;
204
205 AssertThrottles(
206 udpClient,
207 LLUDPServer.MTU, landBytes * commitRatio, windBytes * commitRatio, cloudBytes * commitRatio, taskBytes * commitRatio,
208 textureBytes * commitRatio, assetBytes * commitRatio, udpClient.FlowThrottle.AdjustedDripRate, totalBytes, 0);
209
210 // Test an increase in target throttle, ack of 20 packets adds 20 * LLUDPServer.MTU bytes
211 // to the throttle, recompute commitratio from those numbers
212 udpClient.FlowThrottle.AcknowledgePackets(20);
213 commitRatio = (32000.0 + 20.0 * LLUDPServer.MTU) / totalBytes;
214
215 AssertThrottles(
216 udpClient,
217 LLUDPServer.MTU, landBytes * commitRatio, windBytes * commitRatio, cloudBytes * commitRatio, taskBytes * commitRatio,
218 textureBytes * commitRatio, assetBytes * commitRatio, udpClient.FlowThrottle.AdjustedDripRate, totalBytes, 0);
219
220 // Test a decrease in target throttle, adaptive throttle should cut the rate by 50% with a floor
221 // set by the minimum adaptive rate
222 udpClient.FlowThrottle.ExpirePackets(1);
223 commitRatio = (32000.0 + (20.0 * LLUDPServer.MTU)/Math.Pow(2,1)) / totalBytes;
224
225 AssertThrottles(
226 udpClient,
227 LLUDPServer.MTU, landBytes * commitRatio, windBytes * commitRatio, cloudBytes * commitRatio, taskBytes * commitRatio,
228 textureBytes * commitRatio, assetBytes * commitRatio, udpClient.FlowThrottle.AdjustedDripRate, totalBytes, 0);
229 }
230
231 /// <summary>
232 /// Test throttle setttings where max client throttle has been limited server side.
233 /// </summary>
234 [Test]
235 public void TestSingleClientThrottleRegionLimited()
236 {
237 TestHelpers.InMethod();
238 // TestHelpers.EnableLogging();
239
240 int resendBytes = 6000;
241 int landBytes = 8000;
242 int windBytes = 10000;
243 int cloudBytes = 12000;
244 int taskBytes = 14000;
245 int textureBytes = 16000;
246 int assetBytes = 18000;
247 int totalBytes
248 = (int)((resendBytes + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes) / 2);
249
250 Scene scene = new SceneHelpers().SetupScene();
251 TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene);
252 udpServer.Throttle.RequestedDripRate = totalBytes;
253
254 ScenePresence sp1
255 = ClientStackHelpers.AddChildClient(
256 scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456);
257
258 LLUDPClient udpClient1 = ((LLClientView)sp1.ControllingClient).UDPClient;
259
260 SetThrottles(
261 udpClient1, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes);
262
263 AssertThrottles(
264 udpClient1,
265 resendBytes / 2, landBytes / 2, windBytes / 2, cloudBytes / 2, taskBytes / 2,
266 textureBytes / 2, assetBytes / 2, totalBytes, 0, 0);
267
268 // Test: Now add another client
269 ScenePresence sp2
270 = ClientStackHelpers.AddChildClient(
271 scene, udpServer, TestHelpers.ParseTail(0x10), TestHelpers.ParseTail(0x20), 123457);
272
273 LLUDPClient udpClient2 = ((LLClientView)sp2.ControllingClient).UDPClient;
274 // udpClient.ThrottleDebugLevel = 1;
275
276 SetThrottles(
277 udpClient2, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes);
278
279 AssertThrottles(
280 udpClient1,
281 resendBytes / 4, landBytes / 4, windBytes / 4, cloudBytes / 4, taskBytes / 4,
282 textureBytes / 4, assetBytes / 4, totalBytes / 2, 0, 0);
283
284 AssertThrottles(
285 udpClient2,
286 resendBytes / 4, landBytes / 4, windBytes / 4, cloudBytes / 4, taskBytes / 4,
287 textureBytes / 4, assetBytes / 4, totalBytes / 2, 0, 0);
288 }
289
290 /// <summary>
291 /// Test throttle setttings where max client throttle has been limited server side.
292 /// </summary>
293 [Test]
294 public void TestClientThrottlePerClientLimited()
295 {
296 TestHelpers.InMethod();
297 // TestHelpers.EnableLogging();
298
299 int resendBytes = 4000;
300 int landBytes = 6000;
301 int windBytes = 8000;
302 int cloudBytes = 10000;
303 int taskBytes = 12000;
304 int textureBytes = 14000;
305 int assetBytes = 16000;
306 int totalBytes
307 = (int)((resendBytes + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes) / 2);
308
309 Scene scene = new SceneHelpers().SetupScene();
310 TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene);
311 udpServer.ThrottleRates.Total = totalBytes;
312
313 ScenePresence sp
314 = ClientStackHelpers.AddChildClient(
315 scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456);
316
317 LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
318 // udpClient.ThrottleDebugLevel = 1;
319
320 SetThrottles(
321 udpClient, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes);
322
323 AssertThrottles(
324 udpClient,
325 resendBytes / 2, landBytes / 2, windBytes / 2, cloudBytes / 2, taskBytes / 2,
326 textureBytes / 2, assetBytes / 2, totalBytes, 0, totalBytes);
327 }
328
329 [Test]
330 public void TestClientThrottlePerClientAndRegionLimited()
331 {
332 TestHelpers.InMethod();
333 //TestHelpers.EnableLogging();
334
335 int resendBytes = 4000;
336 int landBytes = 6000;
337 int windBytes = 8000;
338 int cloudBytes = 10000;
339 int taskBytes = 12000;
340 int textureBytes = 14000;
341 int assetBytes = 16000;
342
343 // current total 70000
344 int totalBytes = resendBytes + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes;
345
346 Scene scene = new SceneHelpers().SetupScene();
347 TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene);
348 udpServer.ThrottleRates.Total = (int)(totalBytes * 1.1);
349 udpServer.Throttle.RequestedDripRate = (int)(totalBytes * 1.5);
350
351 ScenePresence sp1
352 = ClientStackHelpers.AddChildClient(
353 scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456);
354
355 LLUDPClient udpClient1 = ((LLClientView)sp1.ControllingClient).UDPClient;
356 udpClient1.ThrottleDebugLevel = 1;
357
358 SetThrottles(
359 udpClient1, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes);
360
361 AssertThrottles(
362 udpClient1,
363 resendBytes, landBytes, windBytes, cloudBytes, taskBytes,
364 textureBytes, assetBytes, totalBytes, 0, totalBytes * 1.1);
365
366 // Now add another client
367 ScenePresence sp2
368 = ClientStackHelpers.AddChildClient(
369 scene, udpServer, TestHelpers.ParseTail(0x10), TestHelpers.ParseTail(0x20), 123457);
370
371 LLUDPClient udpClient2 = ((LLClientView)sp2.ControllingClient).UDPClient;
372 udpClient2.ThrottleDebugLevel = 1;
373
374 SetThrottles(
375 udpClient2, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes);
376
377 AssertThrottles(
378 udpClient1,
379 resendBytes * 0.75, landBytes * 0.75, windBytes * 0.75, cloudBytes * 0.75, taskBytes * 0.75,
380 textureBytes * 0.75, assetBytes * 0.75, totalBytes * 0.75, 0, totalBytes * 1.1);
381
382 AssertThrottles(
383 udpClient2,
384 resendBytes * 0.75, landBytes * 0.75, windBytes * 0.75, cloudBytes * 0.75, taskBytes * 0.75,
385 textureBytes * 0.75, assetBytes * 0.75, totalBytes * 0.75, 0, totalBytes * 1.1);
386 }
387
388 private void AssertThrottles(
389 LLUDPClient udpClient,
390 double resendBytes, double landBytes, double windBytes, double cloudBytes, double taskBytes, double textureBytes, double assetBytes,
391 double totalBytes, double targetBytes, double maxBytes)
392 {
393 ClientInfo ci = udpClient.GetClientInfo();
394
395// Console.WriteLine(
396// "Resend={0}, Land={1}, Wind={2}, Cloud={3}, Task={4}, Texture={5}, Asset={6}, TOTAL = {7}",
397// ci.resendThrottle, ci.landThrottle, ci.windThrottle, ci.cloudThrottle, ci.taskThrottle, ci.textureThrottle, ci.assetThrottle, ci.totalThrottle);
398
399 Assert.AreEqual((int)resendBytes, ci.resendThrottle, "Resend");
400 Assert.AreEqual((int)landBytes, ci.landThrottle, "Land");
401 Assert.AreEqual((int)windBytes, ci.windThrottle, "Wind");
402 Assert.AreEqual((int)cloudBytes, ci.cloudThrottle, "Cloud");
403 Assert.AreEqual((int)taskBytes, ci.taskThrottle, "Task");
404 Assert.AreEqual((int)textureBytes, ci.textureThrottle, "Texture");
405 Assert.AreEqual((int)assetBytes, ci.assetThrottle, "Asset");
406 Assert.AreEqual((int)totalBytes, ci.totalThrottle, "Total");
407 Assert.AreEqual((int)targetBytes, ci.targetThrottle, "Target");
408 Assert.AreEqual((int)maxBytes, ci.maxThrottle, "Max");
409 }
410
411 private void SetThrottles(
412 LLUDPClient udpClient, int resendBytes, int landBytes, int windBytes, int cloudBytes, int taskBytes, int textureBytes, int assetBytes)
413 {
414 byte[] throttles = new byte[28];
415
416 Array.Copy(BitConverter.GetBytes((float)resendBytes * 8), 0, throttles, 0, 4);
417 Array.Copy(BitConverter.GetBytes((float)landBytes * 8), 0, throttles, 4, 4);
418 Array.Copy(BitConverter.GetBytes((float)windBytes * 8), 0, throttles, 8, 4);
419 Array.Copy(BitConverter.GetBytes((float)cloudBytes * 8), 0, throttles, 12, 4);
420 Array.Copy(BitConverter.GetBytes((float)taskBytes * 8), 0, throttles, 16, 4);
421 Array.Copy(BitConverter.GetBytes((float)textureBytes * 8), 0, throttles, 20, 4);
422 Array.Copy(BitConverter.GetBytes((float)assetBytes * 8), 0, throttles, 24, 4);
423
424 udpClient.SetThrottles(throttles);
425 }
426 }
427} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs
index c9aac0b..7a2756b 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs
@@ -58,7 +58,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
58 58
59 /// <summary>Flag used to enable adaptive throttles</summary> 59 /// <summary>Flag used to enable adaptive throttles</summary>
60 public bool AdaptiveThrottlesEnabled; 60 public bool AdaptiveThrottlesEnabled;
61 61
62 /// <summary>
63 /// Set the minimum rate that the adaptive throttles can set. The viewer
64 /// can still throttle lower than this, but the adaptive throttles will
65 /// never decrease rates below this no matter how many packets are dropped
66 /// </summary>
67 public Int64 MinimumAdaptiveThrottleRate;
68
69 /// <summary>Amount of the texture throttle to steal for the task throttle</summary>
70 public double CannibalizeTextureRate;
71
62 /// <summary> 72 /// <summary>
63 /// Default constructor 73 /// Default constructor
64 /// </summary> 74 /// </summary>
@@ -69,6 +79,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
69 { 79 {
70 IConfig throttleConfig = config.Configs["ClientStack.LindenUDP"]; 80 IConfig throttleConfig = config.Configs["ClientStack.LindenUDP"];
71 81
82 // Current default total is 66750
72 Resend = throttleConfig.GetInt("resend_default", 6625); 83 Resend = throttleConfig.GetInt("resend_default", 6625);
73 Land = throttleConfig.GetInt("land_default", 9125); 84 Land = throttleConfig.GetInt("land_default", 9125);
74 Wind = throttleConfig.GetInt("wind_default", 1750); 85 Wind = throttleConfig.GetInt("wind_default", 1750);
@@ -80,6 +91,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
80 Total = throttleConfig.GetInt("client_throttle_max_bps", 0); 91 Total = throttleConfig.GetInt("client_throttle_max_bps", 0);
81 92
82 AdaptiveThrottlesEnabled = throttleConfig.GetBoolean("enable_adaptive_throttles", false); 93 AdaptiveThrottlesEnabled = throttleConfig.GetBoolean("enable_adaptive_throttles", false);
94 MinimumAdaptiveThrottleRate = throttleConfig.GetInt("adaptive_throttle_min_bps", 32000);
95
96 CannibalizeTextureRate = (double)throttleConfig.GetFloat("CannibalizeTextureRate", 0.0f);
97 CannibalizeTextureRate = Util.Clamp<double>(CannibalizeTextureRate,0.0, 0.9);
83 } 98 }
84 catch (Exception) { } 99 catch (Exception) { }
85 } 100 }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs
index 4c33db5..4616203 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs
@@ -1,4 +1,4 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
@@ -42,9 +42,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
42 public class TokenBucket 42 public class TokenBucket
43 { 43 {
44 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 44 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
45 private static Int32 m_counter = 0; 45
46 46 public string Identifier { get; private set; }
47// private Int32 m_identifier; 47
48 public int DebugLevel { get; set; }
48 49
49 /// <summary> 50 /// <summary>
50 /// Number of ticks (ms) per quantum, drip rate and max burst 51 /// Number of ticks (ms) per quantum, drip rate and max burst
@@ -60,7 +61,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
60 61
61 /// <summary> 62 /// <summary>
62 /// </summary> 63 /// </summary>
63 protected const Int32 m_minimumDripRate = 1400; 64 protected const Int32 m_minimumDripRate = LLUDPServer.MTU;
64 65
65 /// <summary>Time of the last drip, in system ticks</summary> 66 /// <summary>Time of the last drip, in system ticks</summary>
66 protected Int32 m_lastDrip; 67 protected Int32 m_lastDrip;
@@ -75,20 +76,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
75 /// Map of children buckets and their requested maximum burst rate 76 /// Map of children buckets and their requested maximum burst rate
76 /// </summary> 77 /// </summary>
77 protected Dictionary<TokenBucket,Int64> m_children = new Dictionary<TokenBucket,Int64>(); 78 protected Dictionary<TokenBucket,Int64> m_children = new Dictionary<TokenBucket,Int64>();
78
79#region Properties
80 79
81 /// <summary> 80 /// <summary>
82 /// The parent bucket of this bucket, or null if this bucket has no 81 /// The parent bucket of this bucket, or null if this bucket has no
83 /// parent. The parent bucket will limit the aggregate bandwidth of all 82 /// parent. The parent bucket will limit the aggregate bandwidth of all
84 /// of its children buckets 83 /// of its children buckets
85 /// </summary> 84 /// </summary>
86 protected TokenBucket m_parent; 85 public TokenBucket Parent { get; protected set; }
87 public TokenBucket Parent
88 {
89 get { return m_parent; }
90 set { m_parent = value; }
91 }
92 86
93 /// <summary> 87 /// <summary>
94 /// Maximum burst rate in bytes per second. This is the maximum number 88 /// Maximum burst rate in bytes per second. This is the maximum number
@@ -114,77 +108,106 @@ namespace OpenSim.Region.ClientStack.LindenUDP
114 } 108 }
115 109
116 /// <summary> 110 /// <summary>
117 /// The speed limit of this bucket in bytes per second. This is the 111 /// The requested drip rate for this particular bucket.
118 /// number of tokens that are added to the bucket per quantum
119 /// </summary> 112 /// </summary>
120 /// <remarks>Tokens are added to the bucket any time 113 /// <remarks>
114 /// 0 then TotalDripRequest is used instead.
115 /// Can never be above MaxDripRate.
116 /// Tokens are added to the bucket at any time
121 /// <seealso cref="RemoveTokens"/> is called, at the granularity of 117 /// <seealso cref="RemoveTokens"/> is called, at the granularity of
122 /// the system tick interval (typically around 15-22ms)</remarks> 118 /// the system tick interval (typically around 15-22ms)
123 protected Int64 m_dripRate; 119 /// FIXME: It is extremely confusing to be able to set a RequestedDripRate of 0 and then receive a positive
120 /// number on get if TotalDripRequest is set. This also stops us being able to retrieve the fact that
121 /// RequestedDripRate is set to 0. Really, this should always return m_dripRate and then we can get
122 /// (m_dripRate == 0 ? TotalDripRequest : m_dripRate) on some other properties.
123 /// </remarks>
124 public virtual Int64 RequestedDripRate 124 public virtual Int64 RequestedDripRate
125 { 125 {
126 get { return (m_dripRate == 0 ? m_totalDripRequest : m_dripRate); } 126 get { return (m_dripRate == 0 ? TotalDripRequest : m_dripRate); }
127 set { 127 set
128 m_dripRate = (value < 0 ? 0 : value); 128 {
129 if (value <= 0)
130 m_dripRate = 0;
131 else if (MaxDripRate > 0 && value > MaxDripRate)
132 m_dripRate = MaxDripRate;
133 else
134 m_dripRate = value;
135
129 m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst); 136 m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst);
130 m_totalDripRequest = m_dripRate; 137
131 if (m_parent != null) 138 if (Parent != null)
132 m_parent.RegisterRequest(this,m_dripRate); 139 Parent.RegisterRequest(this, m_dripRate);
133 } 140 }
134 } 141 }
135 142
143 /// <summary>
144 /// Gets the drip rate.
145 /// </summary>
146 /// <value>
147 /// DripRate can never be above max drip rate or below min drip rate.
148 /// If we are a child bucket then the drip rate return is modifed by the total load on the capacity of the
149 /// parent bucket.
150 /// </value>
136 public virtual Int64 DripRate 151 public virtual Int64 DripRate
137 { 152 {
138 get { 153 get
139 if (m_parent == null) 154 {
140 return Math.Min(RequestedDripRate,TotalDripRequest); 155 double rate;
141 156
142 double rate = (double)RequestedDripRate * m_parent.DripRateModifier(); 157 // FIXME: This doesn't properly work if we have a parent and children and a requested drip rate set
158 // on ourselves which is not equal to the child drip rates.
159 if (Parent == null)
160 {
161 if (TotalDripRequest > 0)
162 rate = Math.Min(RequestedDripRate, TotalDripRequest);
163 else
164 rate = RequestedDripRate;
165 }
166 else
167 {
168 rate = (double)RequestedDripRate * Parent.DripRateModifier();
169 }
170
143 if (rate < m_minimumDripRate) 171 if (rate < m_minimumDripRate)
144 rate = m_minimumDripRate; 172 rate = m_minimumDripRate;
173 else if (MaxDripRate > 0 && rate > MaxDripRate)
174 rate = MaxDripRate;
145 175
146 return (Int64)rate; 176 return (Int64)rate;
147 } 177 }
148 } 178 }
179 protected Int64 m_dripRate;
180
181 // <summary>
182 // The maximum rate for flow control. Drip rate can never be greater than this.
183 // </summary>
184 public Int64 MaxDripRate { get; set; }
149 185
150 /// <summary> 186 /// <summary>
151 /// The current total of the requested maximum burst rates of 187 /// The current total of the requested maximum burst rates of children buckets.
152 /// this bucket's children buckets.
153 /// </summary> 188 /// </summary>
154 protected Int64 m_totalDripRequest; 189 public Int64 TotalDripRequest { get; protected set; }
155 public Int64 TotalDripRequest
156 {
157 get { return m_totalDripRequest; }
158 set { m_totalDripRequest = value; }
159 }
160
161#endregion Properties
162
163#region Constructor
164 190
165 /// <summary> 191 /// <summary>
166 /// Default constructor 192 /// Default constructor
167 /// </summary> 193 /// </summary>
194 /// <param name="identifier">Identifier for this token bucket</param>
168 /// <param name="parent">Parent bucket if this is a child bucket, or 195 /// <param name="parent">Parent bucket if this is a child bucket, or
169 /// null if this is a root bucket</param> 196 /// null if this is a root bucket</param>
170 /// <param name="maxBurst">Maximum size of the bucket in bytes, or 197 /// <param name="requestedDripRate">
171 /// zero if this bucket has no maximum capacity</param> 198 /// Requested rate that the bucket fills, in bytes per
172 /// <param name="dripRate">Rate that the bucket fills, in bytes per 199 /// second. If zero, the bucket always remains full.
173 /// second. If zero, the bucket always remains full</param> 200 /// </param>
174 public TokenBucket(TokenBucket parent, Int64 dripRate) 201 public TokenBucket(string identifier, TokenBucket parent, Int64 requestedDripRate, Int64 maxDripRate)
175 { 202 {
176// m_identifier = m_counter++; 203 Identifier = identifier;
177 m_counter++;
178 204
179 Parent = parent; 205 Parent = parent;
180 RequestedDripRate = dripRate; 206 RequestedDripRate = requestedDripRate;
181 // TotalDripRequest = dripRate; // this will be overwritten when a child node registers 207 MaxDripRate = maxDripRate;
182 // MaxBurst = (Int64)((double)dripRate * m_quantumsPerBurst);
183 m_lastDrip = Util.EnvironmentTickCount(); 208 m_lastDrip = Util.EnvironmentTickCount();
184 } 209 }
185 210
186#endregion Constructor
187
188 /// <summary> 211 /// <summary>
189 /// Compute a modifier for the MaxBurst rate. This is 1.0, meaning 212 /// Compute a modifier for the MaxBurst rate. This is 1.0, meaning
190 /// no modification if the requested bandwidth is less than the 213 /// no modification if the requested bandwidth is less than the
@@ -195,7 +218,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
195 protected double DripRateModifier() 218 protected double DripRateModifier()
196 { 219 {
197 Int64 driprate = DripRate; 220 Int64 driprate = DripRate;
198 return driprate >= TotalDripRequest ? 1.0 : (double)driprate / (double)TotalDripRequest; 221 double modifier = driprate >= TotalDripRequest ? 1.0 : (double)driprate / (double)TotalDripRequest;
222
223// if (DebugLevel > 0)
224// m_log.DebugFormat(
225// "[TOKEN BUCKET]: Returning drip modifier {0}/{1} = {2} from {3}",
226// driprate, TotalDripRequest, modifier, Identifier);
227
228 return modifier;
199 } 229 }
200 230
201 /// <summary> 231 /// <summary>
@@ -217,16 +247,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP
217 lock (m_children) 247 lock (m_children)
218 { 248 {
219 m_children[child] = request; 249 m_children[child] = request;
220 // m_totalDripRequest = m_children.Values.Sum();
221 250
222 m_totalDripRequest = 0; 251 TotalDripRequest = 0;
223 foreach (KeyValuePair<TokenBucket, Int64> cref in m_children) 252 foreach (KeyValuePair<TokenBucket, Int64> cref in m_children)
224 m_totalDripRequest += cref.Value; 253 TotalDripRequest += cref.Value;
225 } 254 }
226 255
227 // Pass the new values up to the parent 256 // Pass the new values up to the parent
228 if (m_parent != null) 257 if (Parent != null)
229 m_parent.RegisterRequest(this,Math.Min(RequestedDripRate, TotalDripRequest)); 258 {
259 Int64 effectiveDripRate;
260
261 if (RequestedDripRate > 0)
262 effectiveDripRate = Math.Min(RequestedDripRate, TotalDripRequest);
263 else
264 effectiveDripRate = TotalDripRequest;
265
266 Parent.RegisterRequest(this, effectiveDripRate);
267 }
230 } 268 }
231 269
232 /// <summary> 270 /// <summary>
@@ -238,17 +276,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
238 lock (m_children) 276 lock (m_children)
239 { 277 {
240 m_children.Remove(child); 278 m_children.Remove(child);
241 // m_totalDripRequest = m_children.Values.Sum();
242 279
243 m_totalDripRequest = 0; 280 TotalDripRequest = 0;
244 foreach (KeyValuePair<TokenBucket, Int64> cref in m_children) 281 foreach (KeyValuePair<TokenBucket, Int64> cref in m_children)
245 m_totalDripRequest += cref.Value; 282 TotalDripRequest += cref.Value;
246 } 283 }
247
248 284
249 // Pass the new values up to the parent 285 // Pass the new values up to the parent
250 if (m_parent != null) 286 if (Parent != null)
251 m_parent.RegisterRequest(this,Math.Min(RequestedDripRate, TotalDripRequest)); 287 Parent.RegisterRequest(this,Math.Min(RequestedDripRate, TotalDripRequest));
252 } 288 }
253 289
254 /// <summary> 290 /// <summary>
@@ -301,7 +337,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
301 // with no drip rate... 337 // with no drip rate...
302 if (DripRate == 0) 338 if (DripRate == 0)
303 { 339 {
304 m_log.WarnFormat("[TOKENBUCKET] something odd is happening and drip rate is 0"); 340 m_log.WarnFormat("[TOKENBUCKET] something odd is happening and drip rate is 0 for {0}", Identifier);
305 return; 341 return;
306 } 342 }
307 343
@@ -321,74 +357,108 @@ namespace OpenSim.Region.ClientStack.LindenUDP
321 357
322 public class AdaptiveTokenBucket : TokenBucket 358 public class AdaptiveTokenBucket : TokenBucket
323 { 359 {
324// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 360 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
361
362 public bool AdaptiveEnabled { get; set; }
325 363
326 /// <summary> 364 /// <summary>
327 /// The minimum rate for flow control. Minimum drip rate is one 365 /// Target drip rate for this bucket.
328 /// packet per second. Open the throttle to 15 packets per second
329 /// or about 160kbps.
330 /// </summary> 366 /// </summary>
331 protected const Int64 m_minimumFlow = m_minimumDripRate * 15; 367 /// <remarks>Usually set by the client. If adaptive is enabled then throttles will increase until we reach this.</remarks>
332 368 public Int64 TargetDripRate
333 // <summary> 369 {
334 // The maximum rate for flow control. Drip rate can never be 370 get { return m_targetDripRate; }
335 // greater than this. 371 set
336 // </summary> 372 {
337 protected Int64 m_maxDripRate = 0; 373 m_targetDripRate = Math.Max(value, m_minimumFlow);
338 protected Int64 MaxDripRate 374 }
339 {
340 get { return (m_maxDripRate == 0 ? m_totalDripRequest : m_maxDripRate); }
341 set { m_maxDripRate = (value == 0 ? 0 : Math.Max(value,m_minimumFlow)); }
342 } 375 }
343 376 protected Int64 m_targetDripRate;
344 private bool m_enabled = false; 377
345
346 // <summary> 378 // <summary>
347 // 379 // Adjust drip rate in response to network conditions.
348 // </summary> 380 // </summary>
349 public virtual Int64 AdjustedDripRate 381 public virtual Int64 AdjustedDripRate
350 { 382 {
351 get { return m_dripRate; } 383 get { return m_dripRate; }
352 set { 384 set
353 m_dripRate = OpenSim.Framework.Util.Clamp<Int64>(value,m_minimumFlow,MaxDripRate); 385 {
386 m_dripRate = OpenSim.Framework.Util.Clamp<Int64>(value, m_minimumFlow, TargetDripRate);
354 m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst); 387 m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst);
355 if (m_parent != null) 388
356 m_parent.RegisterRequest(this,m_dripRate); 389 if (Parent != null)
390 Parent.RegisterRequest(this, m_dripRate);
357 } 391 }
358 } 392 }
393
394 /// <summary>
395 /// The minimum rate for adaptive flow control.
396 /// </summary>
397 protected Int64 m_minimumFlow = 32000;
359 398
360 // <summary> 399 /// <summary>
361 // 400 /// Constructor for the AdaptiveTokenBucket class
362 // </summary> 401 /// <param name="identifier">Unique identifier for the client</param>
363 public AdaptiveTokenBucket(TokenBucket parent, Int64 maxDripRate, bool enabled) : base(parent,maxDripRate) 402 /// <param name="parent">Parent bucket in the hierarchy</param>
403 /// <param name="requestedDripRate"></param>
404 /// <param name="maxDripRate">The ceiling rate for adaptation</param>
405 /// <param name="minDripRate">The floor rate for adaptation</param>
406 /// </summary>
407 public AdaptiveTokenBucket(string identifier, TokenBucket parent, Int64 requestedDripRate, Int64 maxDripRate, Int64 minDripRate, bool enabled)
408 : base(identifier, parent, requestedDripRate, maxDripRate)
364 { 409 {
365 m_enabled = enabled; 410 AdaptiveEnabled = enabled;
366 411
367 if (m_enabled) 412 if (AdaptiveEnabled)
368 { 413 {
369 // m_log.DebugFormat("[TOKENBUCKET] Adaptive throttle enabled"); 414// m_log.DebugFormat("[TOKENBUCKET]: Adaptive throttle enabled");
370 MaxDripRate = maxDripRate; 415 m_minimumFlow = minDripRate;
416 TargetDripRate = m_minimumFlow;
371 AdjustedDripRate = m_minimumFlow; 417 AdjustedDripRate = m_minimumFlow;
372 } 418 }
373 } 419 }
374 420
375 // <summary> 421 /// <summary>
376 // 422 /// Reliable packets sent to the client for which we never received an ack adjust the drip rate down.
377 // </summary> 423 /// <param name="packets">Number of packets that expired without successful delivery</param>
378 public void ExpirePackets(Int32 count) 424 /// </summary>
425 public void ExpirePackets(Int32 packets)
379 { 426 {
380 // m_log.WarnFormat("[ADAPTIVEBUCKET] drop {0} by {1} expired packets",AdjustedDripRate,count); 427 if (AdaptiveEnabled)
381 if (m_enabled) 428 {
382 AdjustedDripRate = (Int64) (AdjustedDripRate / Math.Pow(2,count)); 429 if (DebugLevel > 0)
430 m_log.WarnFormat(
431 "[ADAPTIVEBUCKET] drop {0} by {1} expired packets for {2}",
432 AdjustedDripRate, packets, Identifier);
433
434 // AdjustedDripRate = (Int64) (AdjustedDripRate / Math.Pow(2,packets));
435
436 // Compute the fallback solely on the rate allocated beyond the minimum, this
437 // should smooth out the fallback to the minimum rate
438 AdjustedDripRate = m_minimumFlow + (Int64) ((AdjustedDripRate - m_minimumFlow) / Math.Pow(2, packets));
439 }
383 } 440 }
384 441
385 // <summary> 442 /// <summary>
386 // 443 /// Reliable packets acked by the client adjust the drip rate up.
387 // </summary> 444 /// <param name="packets">Number of packets successfully acknowledged</param>
388 public void AcknowledgePackets(Int32 count) 445 /// </summary>
446 public void AcknowledgePackets(Int32 packets)
447 {
448 if (AdaptiveEnabled)
449 AdjustedDripRate = AdjustedDripRate + packets * LLUDPServer.MTU;
450 }
451
452 /// <summary>
453 /// Adjust the minimum flow level for the adaptive throttle, this will drop adjusted
454 /// throttles back to the minimum levels
455 /// <param>minDripRate--the new minimum flow</param>
456 /// </summary>
457 public void ResetMinimumAdaptiveFlow(Int64 minDripRate)
389 { 458 {
390 if (m_enabled) 459 m_minimumFlow = minDripRate;
391 AdjustedDripRate = AdjustedDripRate + count; 460 TargetDripRate = m_minimumFlow;
461 AdjustedDripRate = m_minimumFlow;
392 } 462 }
393 } 463 }
394} 464} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs b/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs
index 9d6c09e..b546a99 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs
@@ -31,6 +31,9 @@ using System.Net;
31using System.Threading; 31using System.Threading;
32using OpenMetaverse; 32using OpenMetaverse;
33 33
34//using System.Reflection;
35//using log4net;
36
34namespace OpenSim.Region.ClientStack.LindenUDP 37namespace OpenSim.Region.ClientStack.LindenUDP
35{ 38{
36 /// <summary> 39 /// <summary>
@@ -60,6 +63,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
60 } 63 }
61 } 64 }
62 65
66 //private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
67
63 /// <summary>Holds the actual unacked packet data, sorted by sequence number</summary> 68 /// <summary>Holds the actual unacked packet data, sorted by sequence number</summary>
64 private Dictionary<uint, OutgoingPacket> m_packets = new Dictionary<uint, OutgoingPacket>(); 69 private Dictionary<uint, OutgoingPacket> m_packets = new Dictionary<uint, OutgoingPacket>();
65 /// <summary>Holds packets that need to be added to the unacknowledged list</summary> 70 /// <summary>Holds packets that need to be added to the unacknowledged list</summary>
@@ -164,8 +169,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
164 } 169 }
165 } 170 }
166 171
167 //if (expiredPackets != null) 172 // if (expiredPackets != null)
168 // m_log.DebugFormat("[UNACKED PACKET COLLECTION]: Found {0} expired packets on timeout of {1}", expiredPackets.Count, timeoutMS); 173 // m_log.DebugFormat("[UNACKED PACKET COLLECTION]: Found {0} expired packets on timeout of {1}", expiredPackets.Count, timeoutMS);
169 174
170 return expiredPackets; 175 return expiredPackets;
171 } 176 }
@@ -192,7 +197,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
192 197
193 // As with other network applications, assume that an acknowledged packet is an 198 // As with other network applications, assume that an acknowledged packet is an
194 // indication that the network can handle a little more load, speed up the transmission 199 // indication that the network can handle a little more load, speed up the transmission
195 ackedPacket.Client.FlowThrottle.AcknowledgePackets(ackedPacket.Buffer.DataLength); 200 ackedPacket.Client.FlowThrottle.AcknowledgePackets(1);
196 201
197 // Update stats 202 // Update stats
198 Interlocked.Add(ref ackedPacket.Client.UnackedBytes, -ackedPacket.Buffer.DataLength); 203 Interlocked.Add(ref ackedPacket.Client.UnackedBytes, -ackedPacket.Buffer.DataLength);
@@ -207,9 +212,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
207 } 212 }
208 else 213 else
209 { 214 {
210 //m_log.WarnFormat("[UNACKED PACKET COLLECTION]: Could not find packet with sequence number {0} to ack", pendingAcknowledgement.SequenceNumber); 215 // m_log.WarnFormat("[UNACKED PACKET COLLECTION]: found null packet for sequence number {0} to ack",
216 // pendingAcknowledgement.SequenceNumber);
211 } 217 }
212 } 218 }
219 else
220 {
221 // m_log.WarnFormat("[UNACKED PACKET COLLECTION]: Could not find packet with sequence number {0} to ack",
222 // pendingAcknowledgement.SequenceNumber);
223 }
213 } 224 }
214 225
215 uint pendingRemove; 226 uint pendingRemove;