aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/Linden
diff options
context:
space:
mode:
authorMelanie2013-07-24 04:45:07 +0100
committerMelanie2013-07-24 04:45:07 +0100
commite82d4154a2e348e4a38f01cb1877878c94569bba (patch)
tree7b27e6d30d04f6089fd17d5779cfb0a81e50d508 /OpenSim/Region/ClientStack/Linden
parentMerge branch 'master' into careminster (diff)
parentFor unknown user issue, bump GUN7 to GUN8 and UMMAU3 to UMMAU4 to assess what... (diff)
downloadopensim-SC-e82d4154a2e348e4a38f01cb1877878c94569bba.zip
opensim-SC-e82d4154a2e348e4a38f01cb1877878c94569bba.tar.gz
opensim-SC-e82d4154a2e348e4a38f01cb1877878c94569bba.tar.bz2
opensim-SC-e82d4154a2e348e4a38f01cb1877878c94569bba.tar.xz
Merge branch 'master' into careminster
Conflicts: OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs OpenSim/Region/Framework/Scenes/ScenePresence.cs OpenSim/Region/Physics/Manager/PhysicsActor.cs OpenSim/Region/Physics/Manager/PhysicsScene.cs
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden')
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs242
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs7
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs69
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs116
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs72
5 files changed, 386 insertions, 120 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
index ac5e77e..0e20e38 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -96,6 +96,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
96 public event Action<IClientAPI, bool> OnCompleteMovementToRegion; 96 public event Action<IClientAPI, bool> OnCompleteMovementToRegion;
97 public event UpdateAgent OnPreAgentUpdate; 97 public event UpdateAgent OnPreAgentUpdate;
98 public event UpdateAgent OnAgentUpdate; 98 public event UpdateAgent OnAgentUpdate;
99 public event UpdateAgent OnAgentCameraUpdate;
99 public event AgentRequestSit OnAgentRequestSit; 100 public event AgentRequestSit OnAgentRequestSit;
100 public event AgentSit OnAgentSit; 101 public event AgentSit OnAgentSit;
101 public event AvatarPickerRequest OnAvatarPickerRequest; 102 public event AvatarPickerRequest OnAvatarPickerRequest;
@@ -368,7 +369,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
368 /// This does mean that agent updates must be processed synchronously, at least for each client, and called methods 369 /// This does mean that agent updates must be processed synchronously, at least for each client, and called methods
369 /// cannot retain a reference to it outside of that method. 370 /// cannot retain a reference to it outside of that method.
370 /// </remarks> 371 /// </remarks>
371 private AgentUpdateArgs m_lastAgentUpdateArgs; 372 private AgentUpdateArgs m_thisAgentUpdateArgs = new AgentUpdateArgs();
372 373
373 protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>(); 374 protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>();
374 protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers 375 protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers
@@ -505,6 +506,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
505 m_udpServer = udpServer; 506 m_udpServer = udpServer;
506 m_udpClient = udpClient; 507 m_udpClient = udpClient;
507 m_udpClient.OnQueueEmpty += HandleQueueEmpty; 508 m_udpClient.OnQueueEmpty += HandleQueueEmpty;
509 m_udpClient.HasUpdates += HandleHasUpdates;
508 m_udpClient.OnPacketStats += PopulateStats; 510 m_udpClient.OnPacketStats += PopulateStats;
509 511
510 m_prioritizer = new Prioritizer(m_scene); 512 m_prioritizer = new Prioritizer(m_scene);
@@ -4164,8 +4166,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4164 4166
4165 void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories) 4167 void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories)
4166 { 4168 {
4169// if (!m_udpServer.IsRunningOutbound)
4170// return;
4171
4167 if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) 4172 if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
4168 { 4173 {
4174// if (!m_udpServer.IsRunningOutbound)
4175// return;
4176
4169 if (m_maxUpdates == 0 || m_LastQueueFill == 0) 4177 if (m_maxUpdates == 0 || m_LastQueueFill == 0)
4170 { 4178 {
4171 m_maxUpdates = m_udpServer.PrimUpdatesPerCallback; 4179 m_maxUpdates = m_udpServer.PrimUpdatesPerCallback;
@@ -4191,6 +4199,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4191 ImageManager.ProcessImageQueue(m_udpServer.TextureSendLimit); 4199 ImageManager.ProcessImageQueue(m_udpServer.TextureSendLimit);
4192 } 4200 }
4193 4201
4202 internal bool HandleHasUpdates(ThrottleOutPacketTypeFlags categories)
4203 {
4204 bool hasUpdates = false;
4205
4206 if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
4207 {
4208 if (m_entityUpdates.Count > 0)
4209 hasUpdates = true;
4210 else if (m_entityProps.Count > 0)
4211 hasUpdates = true;
4212 }
4213
4214 if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0)
4215 {
4216 if (ImageManager.HasUpdates())
4217 hasUpdates = true;
4218 }
4219
4220 return hasUpdates;
4221 }
4222
4194 public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID) 4223 public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID)
4195 { 4224 {
4196 AssetUploadCompletePacket newPack = new AssetUploadCompletePacket(); 4225 AssetUploadCompletePacket newPack = new AssetUploadCompletePacket();
@@ -5058,7 +5087,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5058 SceneObjectPart part = (SceneObjectPart)entity; 5087 SceneObjectPart part = (SceneObjectPart)entity;
5059 5088
5060 attachPoint = part.ParentGroup.AttachmentPoint; 5089 attachPoint = part.ParentGroup.AttachmentPoint;
5061 5090 attachPoint = ((attachPoint % 16) * 16 + (attachPoint / 16));
5062// m_log.DebugFormat( 5091// m_log.DebugFormat(
5063// "[LLCLIENTVIEW]: Sending attachPoint {0} for {1} {2} to {3}", 5092// "[LLCLIENTVIEW]: Sending attachPoint {0} for {1} {2} to {3}",
5064// attachPoint, part.Name, part.LocalId, Name); 5093// attachPoint, part.Name, part.LocalId, Name);
@@ -5086,7 +5115,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5086 pos += 4; 5115 pos += 4;
5087 5116
5088 // Avatar/CollisionPlane 5117 // Avatar/CollisionPlane
5089 data[pos++] = (byte)((attachPoint % 16) * 16 + (attachPoint / 16)); ; 5118 data[pos++] = (byte) attachPoint;
5090 if (avatar) 5119 if (avatar)
5091 { 5120 {
5092 data[pos++] = 1; 5121 data[pos++] = 1;
@@ -5618,83 +5647,137 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5618 5647
5619 #region Packet Handlers 5648 #region Packet Handlers
5620 5649
5650 public int TotalAgentUpdates { get; set; }
5651
5621 #region Scene/Avatar 5652 #region Scene/Avatar
5622 5653
5623 private bool HandleAgentUpdate(IClientAPI sener, Packet packet) 5654 // Threshold for body rotation to be a significant agent update
5655 private const float QDELTA = 0.000001f;
5656 // Threshold for camera rotation to be a significant agent update
5657 private const float VDELTA = 0.01f;
5658
5659 /// <summary>
5660 /// This checks the update significance against the last update made.
5661 /// </summary>
5662 /// <remarks>Can only be called by one thread at a time</remarks>
5663 /// <returns></returns>
5664 /// <param name='x'></param>
5665 public bool CheckAgentUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
5624 { 5666 {
5625 if (OnAgentUpdate != null) 5667 return CheckAgentMovementUpdateSignificance(x) || CheckAgentCameraUpdateSignificance(x);
5626 { 5668 }
5627 AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
5628 5669
5629 #region Packet Session and User Check 5670 /// <summary>
5630 if (agentUpdate.AgentData.SessionID != SessionId || agentUpdate.AgentData.AgentID != AgentId) 5671 /// This checks the movement/state update significance against the last update made.
5631 { 5672 /// </summary>
5632 PacketPool.Instance.ReturnPacket(packet); 5673 /// <remarks>Can only be called by one thread at a time</remarks>
5633 return false; 5674 /// <returns></returns>
5634 } 5675 /// <param name='x'></param>
5635 #endregion 5676 private bool CheckAgentMovementUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
5677 {
5678 float qdelta1 = 1 - (float)Math.Pow(Quaternion.Dot(x.BodyRotation, m_thisAgentUpdateArgs.BodyRotation), 2);
5679 //qdelta2 = 1 - (float)Math.Pow(Quaternion.Dot(x.HeadRotation, m_thisAgentUpdateArgs.HeadRotation), 2);
5680
5681 bool movementSignificant =
5682 (qdelta1 > QDELTA) // significant if body rotation above threshold
5683 // Ignoring head rotation altogether, because it's not being used for anything interesting up the stack
5684 // || (qdelta2 > QDELTA * 10) // significant if head rotation above threshold
5685 || (x.ControlFlags != m_thisAgentUpdateArgs.ControlFlags) // significant if control flags changed
5686 || (x.ControlFlags != (byte)AgentManager.ControlFlags.NONE) // significant if user supplying any movement update commands
5687 || (x.Far != m_thisAgentUpdateArgs.Far) // significant if far distance changed
5688 || (x.Flags != m_thisAgentUpdateArgs.Flags) // significant if Flags changed
5689 || (x.State != m_thisAgentUpdateArgs.State) // significant if Stats changed
5690 ;
5691 //if (movementSignificant)
5692 //{
5693 //m_log.DebugFormat("[LLCLIENTVIEW]: Bod {0} {1}",
5694 // qdelta1, qdelta2);
5695 //m_log.DebugFormat("[LLCLIENTVIEW]: St {0} {1} {2} {3}",
5696 // x.ControlFlags, x.Flags, x.Far, x.State);
5697 //}
5698 return movementSignificant;
5699 }
5636 5700
5637 bool update = false; 5701 /// <summary>
5638 AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData; 5702 /// This checks the camera update significance against the last update made.
5639 5703 /// </summary>
5640 if (m_lastAgentUpdateArgs != null) 5704 /// <remarks>Can only be called by one thread at a time</remarks>
5641 { 5705 /// <returns></returns>
5642 // These should be ordered from most-likely to 5706 /// <param name='x'></param>
5643 // least likely to change. I've made an initial 5707 private bool CheckAgentCameraUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
5644 // guess at that. 5708 {
5645 update = 5709 float vdelta1 = Vector3.Distance(x.CameraAtAxis, m_thisAgentUpdateArgs.CameraAtAxis);
5646 ( 5710 float vdelta2 = Vector3.Distance(x.CameraCenter, m_thisAgentUpdateArgs.CameraCenter);
5647 (x.BodyRotation != m_lastAgentUpdateArgs.BodyRotation) || 5711 float vdelta3 = Vector3.Distance(x.CameraLeftAxis, m_thisAgentUpdateArgs.CameraLeftAxis);
5648 (x.CameraAtAxis != m_lastAgentUpdateArgs.CameraAtAxis) || 5712 float vdelta4 = Vector3.Distance(x.CameraUpAxis, m_thisAgentUpdateArgs.CameraUpAxis);
5649 (x.CameraCenter != m_lastAgentUpdateArgs.CameraCenter) ||
5650 (x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) ||
5651 (x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) ||
5652 (x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) ||
5653 (x.ControlFlags != 0) ||
5654 (x.Far != m_lastAgentUpdateArgs.Far) ||
5655 (x.Flags != m_lastAgentUpdateArgs.Flags) ||
5656 (x.State != m_lastAgentUpdateArgs.State) ||
5657 (x.HeadRotation != m_lastAgentUpdateArgs.HeadRotation) ||
5658 (x.SessionID != m_lastAgentUpdateArgs.SessionID) ||
5659 (x.AgentID != m_lastAgentUpdateArgs.AgentID)
5660 );
5661 }
5662 else
5663 {
5664 m_lastAgentUpdateArgs = new AgentUpdateArgs();
5665 update = true;
5666 }
5667 5713
5668 if (update) 5714 bool cameraSignificant =
5669 { 5715 (vdelta1 > VDELTA) ||
5670// m_log.DebugFormat("[LLCLIENTVIEW]: Triggered AgentUpdate for {0}", sener.Name); 5716 (vdelta2 > VDELTA) ||
5717 (vdelta3 > VDELTA) ||
5718 (vdelta4 > VDELTA)
5719 ;
5671 5720
5672 m_lastAgentUpdateArgs.AgentID = x.AgentID; 5721 //if (cameraSignificant)
5673 m_lastAgentUpdateArgs.BodyRotation = x.BodyRotation; 5722 //{
5674 m_lastAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis; 5723 //m_log.DebugFormat("[LLCLIENTVIEW]: Cam1 {0} {1}",
5675 m_lastAgentUpdateArgs.CameraCenter = x.CameraCenter; 5724 // x.CameraAtAxis, x.CameraCenter);
5676 m_lastAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis; 5725 //m_log.DebugFormat("[LLCLIENTVIEW]: Cam2 {0} {1}",
5677 m_lastAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis; 5726 // x.CameraLeftAxis, x.CameraUpAxis);
5678 m_lastAgentUpdateArgs.ControlFlags = x.ControlFlags; 5727 //}
5679 m_lastAgentUpdateArgs.Far = x.Far;
5680 m_lastAgentUpdateArgs.Flags = x.Flags;
5681 m_lastAgentUpdateArgs.HeadRotation = x.HeadRotation;
5682 m_lastAgentUpdateArgs.SessionID = x.SessionID;
5683 m_lastAgentUpdateArgs.State = x.State;
5684 5728
5685 UpdateAgent handlerAgentUpdate = OnAgentUpdate; 5729 return cameraSignificant;
5686 UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate; 5730 }
5687 5731
5688 if (handlerPreAgentUpdate != null) 5732 private bool HandleAgentUpdate(IClientAPI sener, Packet packet)
5689 OnPreAgentUpdate(this, m_lastAgentUpdateArgs); 5733 {
5734 // We got here, which means that something in agent update was significant
5690 5735
5691 if (handlerAgentUpdate != null) 5736 AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
5692 OnAgentUpdate(this, m_lastAgentUpdateArgs); 5737 AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData;
5693 5738
5694 handlerAgentUpdate = null; 5739 if (x.AgentID != AgentId || x.SessionID != SessionId)
5695 handlerPreAgentUpdate = null; 5740 return false;
5696 } 5741
5697 } 5742 // Before we update the current m_thisAgentUpdateArgs, let's check this again
5743 // to see what exactly changed
5744 bool movement = CheckAgentMovementUpdateSignificance(x);
5745 bool camera = CheckAgentCameraUpdateSignificance(x);
5746
5747 m_thisAgentUpdateArgs.AgentID = x.AgentID;
5748 m_thisAgentUpdateArgs.BodyRotation = x.BodyRotation;
5749 m_thisAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis;
5750 m_thisAgentUpdateArgs.CameraCenter = x.CameraCenter;
5751 m_thisAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis;
5752 m_thisAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis;
5753 m_thisAgentUpdateArgs.ControlFlags = x.ControlFlags;
5754 m_thisAgentUpdateArgs.Far = x.Far;
5755 m_thisAgentUpdateArgs.Flags = x.Flags;
5756 m_thisAgentUpdateArgs.HeadRotation = x.HeadRotation;
5757 m_thisAgentUpdateArgs.SessionID = x.SessionID;
5758 m_thisAgentUpdateArgs.State = x.State;
5759
5760 UpdateAgent handlerAgentUpdate = OnAgentUpdate;
5761 UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate;
5762 UpdateAgent handlerAgentCameraUpdate = OnAgentCameraUpdate;
5763
5764 // Was there a significant movement/state change?
5765 if (movement)
5766 {
5767 if (handlerPreAgentUpdate != null)
5768 OnPreAgentUpdate(this, m_thisAgentUpdateArgs);
5769
5770 if (handlerAgentUpdate != null)
5771 OnAgentUpdate(this, m_thisAgentUpdateArgs);
5772 }
5773 // Was there a significant camera(s) change?
5774 if (camera)
5775 if (handlerAgentCameraUpdate != null)
5776 handlerAgentCameraUpdate(this, m_thisAgentUpdateArgs);
5777
5778 handlerAgentUpdate = null;
5779 handlerPreAgentUpdate = null;
5780 handlerAgentCameraUpdate = null;
5698 5781
5699 PacketPool.Instance.ReturnPacket(packet); 5782 PacketPool.Instance.ReturnPacket(packet);
5700 5783
@@ -12813,7 +12896,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12813 OutPacket(dialog, ThrottleOutPacketType.Task); 12896 OutPacket(dialog, ThrottleOutPacketType.Task);
12814 } 12897 }
12815 12898
12816 public void StopFlying(ISceneEntity p) 12899 public void SendAgentTerseUpdate(ISceneEntity p)
12817 { 12900 {
12818 if (p is ScenePresence) 12901 if (p is ScenePresence)
12819 { 12902 {
@@ -12827,25 +12910,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12827 12910
12828 Vector3 pos = presence.AbsolutePosition; 12911 Vector3 pos = presence.AbsolutePosition;
12829 12912
12830 if (presence.Appearance.AvatarHeight != 127.0f)
12831 pos += new Vector3(0f, 0f, (presence.Appearance.AvatarHeight/6f));
12832 else
12833 pos += new Vector3(0f, 0f, (1.56f/6f));
12834
12835 presence.AbsolutePosition = pos;
12836
12837 // attach a suitable collision plane regardless of the actual situation to force the LLClient to land.
12838 // Collision plane below the avatar's position a 6th of the avatar's height is suitable.
12839 // Mind you, that this method doesn't get called if the avatar's velocity magnitude is greater then a
12840 // certain amount.. because the LLClient wouldn't land in that situation anyway.
12841
12842 // why are we still testing for this really old height value default???
12843 if (presence.Appearance.AvatarHeight != 127.0f)
12844 presence.CollisionPlane = new Vector4(0, 0, 0, pos.Z - presence.Appearance.AvatarHeight/6f);
12845 else
12846 presence.CollisionPlane = new Vector4(0, 0, 0, pos.Z - (1.56f/6f));
12847
12848
12849 ImprovedTerseObjectUpdatePacket.ObjectDataBlock block = 12913 ImprovedTerseObjectUpdatePacket.ObjectDataBlock block =
12850 CreateImprovedTerseBlock(p, false); 12914 CreateImprovedTerseBlock(p, false);
12851 12915
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs
index 073c357..41dd4d1 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs
@@ -206,6 +206,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
206 } 206 }
207 } 207 }
208 208
209 public bool HasUpdates()
210 {
211 J2KImage image = GetHighestPriorityImage();
212
213 return image != null && image.IsDecoded;
214 }
215
209 public bool ProcessImageQueue(int packetsToSend) 216 public bool ProcessImageQueue(int packetsToSend)
210 { 217 {
211 int packetsSent = 0; 218 int packetsSent = 0;
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
index f7ed14d..d52ad7e 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
@@ -31,6 +31,7 @@ using System.Net;
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
@@ -81,6 +82,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
81 /// hooked to put more data on the empty queue</summary> 82 /// hooked to put more data on the empty queue</summary>
82 public event QueueEmpty OnQueueEmpty; 83 public event QueueEmpty OnQueueEmpty;
83 84
85 public event Func<ThrottleOutPacketTypeFlags, bool> HasUpdates;
86
84 /// <summary>AgentID for this client</summary> 87 /// <summary>AgentID for this client</summary>
85 public readonly UUID AgentID; 88 public readonly UUID AgentID;
86 /// <summary>The remote address of the connected client</summary> 89 /// <summary>The remote address of the connected client</summary>
@@ -645,15 +648,38 @@ namespace OpenSim.Region.ClientStack.LindenUDP
645 /// <param name="categories">Throttle categories to fire the callback for</param> 648 /// <param name="categories">Throttle categories to fire the callback for</param>
646 private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories) 649 private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories)
647 { 650 {
648 if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty) 651// if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty)
652 if (!m_isQueueEmptyRunning && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty)
649 { 653 {
654 m_isQueueEmptyRunning = true;
655
656 int start = Environment.TickCount & Int32.MaxValue;
657 const int MIN_CALLBACK_MS = 30;
658
659 m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
660 if (m_nextOnQueueEmpty == 0)
661 m_nextOnQueueEmpty = 1;
662
650 // Use a value of 0 to signal that FireQueueEmpty is running 663 // Use a value of 0 to signal that FireQueueEmpty is running
651 m_nextOnQueueEmpty = 0; 664// m_nextOnQueueEmpty = 0;
652 // Asynchronously run the callback 665
653 Util.FireAndForget(FireQueueEmpty, categories); 666 m_categories = categories;
667
668 if (HasUpdates(m_categories))
669 {
670 // Asynchronously run the callback
671 Util.FireAndForget(FireQueueEmpty, categories);
672 }
673 else
674 {
675 m_isQueueEmptyRunning = false;
676 }
654 } 677 }
655 } 678 }
656 679
680 private bool m_isQueueEmptyRunning;
681 private ThrottleOutPacketTypeFlags m_categories = 0;
682
657 /// <summary> 683 /// <summary>
658 /// Fires the OnQueueEmpty callback and sets the minimum time that it 684 /// Fires the OnQueueEmpty callback and sets the minimum time that it
659 /// can be called again 685 /// can be called again
@@ -663,22 +689,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP
663 /// signature</param> 689 /// signature</param>
664 private void FireQueueEmpty(object o) 690 private void FireQueueEmpty(object o)
665 { 691 {
666 const int MIN_CALLBACK_MS = 30; 692// int start = Environment.TickCount & Int32.MaxValue;
693// const int MIN_CALLBACK_MS = 30;
667 694
668 ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o; 695// if (m_udpServer.IsRunningOutbound)
669 QueueEmpty callback = OnQueueEmpty; 696// {
670 697 ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o;
671 int start = Environment.TickCount & Int32.MaxValue; 698 QueueEmpty callback = OnQueueEmpty;
672 699
673 if (callback != null) 700 if (callback != null)
674 { 701 {
675 try { callback(categories); } 702// if (m_udpServer.IsRunningOutbound)
676 catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); } 703// {
677 } 704 try { callback(categories); }
705 catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); }
706// }
707 }
708// }
709
710// m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
711// if (m_nextOnQueueEmpty == 0)
712// m_nextOnQueueEmpty = 1;
713
714// }
678 715
679 m_nextOnQueueEmpty = start + MIN_CALLBACK_MS; 716 m_isQueueEmptyRunning = false;
680 if (m_nextOnQueueEmpty == 0)
681 m_nextOnQueueEmpty = 1;
682 } 717 }
683 internal void ForceThrottleSetting(int throttle, int setting) 718 internal void ForceThrottleSetting(int throttle, int setting)
684 { 719 {
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
index b4ac021..7a4c6f4 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -69,9 +69,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
69 69
70 StatsManager.RegisterStat( 70 StatsManager.RegisterStat(
71 new Stat( 71 new Stat(
72 "IncomingUDPReceivesCount",
73 "Number of UDP receives performed",
74 "Number of UDP receives performed",
75 "",
76 "clientstack",
77 scene.Name,
78 StatType.Pull,
79 MeasuresOfInterest.AverageChangeOverTime,
80 stat => stat.Value = m_udpServer.UdpReceives,
81 StatVerbosity.Debug));
82
83 StatsManager.RegisterStat(
84 new Stat(
72 "IncomingPacketsProcessedCount", 85 "IncomingPacketsProcessedCount",
73 "Number of inbound UDP packets processed", 86 "Number of inbound LL protocol packets processed",
74 "Number of inbound UDP packets processed", 87 "Number of inbound LL protocol packets processed",
75 "", 88 "",
76 "clientstack", 89 "clientstack",
77 scene.Name, 90 scene.Name,
@@ -79,6 +92,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP
79 MeasuresOfInterest.AverageChangeOverTime, 92 MeasuresOfInterest.AverageChangeOverTime,
80 stat => stat.Value = m_udpServer.IncomingPacketsProcessed, 93 stat => stat.Value = m_udpServer.IncomingPacketsProcessed,
81 StatVerbosity.Debug)); 94 StatVerbosity.Debug));
95
96 StatsManager.RegisterStat(
97 new Stat(
98 "OutgoingUDPSendsCount",
99 "Number of UDP sends performed",
100 "Number of UDP sends performed",
101 "",
102 "clientstack",
103 scene.Name,
104 StatType.Pull,
105 MeasuresOfInterest.AverageChangeOverTime,
106 stat => stat.Value = m_udpServer.UdpSends,
107 StatVerbosity.Debug));
108
109 StatsManager.RegisterStat(
110 new Stat(
111 "AverageUDPProcessTime",
112 "Average number of milliseconds taken to process each incoming UDP packet in a sample.",
113 "This is for initial receive processing which is separate from the later client LL packet processing stage.",
114 "ms",
115 "clientstack",
116 scene.Name,
117 StatType.Pull,
118 MeasuresOfInterest.None,
119 stat => stat.Value = m_udpServer.AverageReceiveTicksForLastSamplePeriod / TimeSpan.TicksPerMillisecond,
120// stat =>
121// stat.Value = Math.Round(m_udpServer.AverageReceiveTicksForLastSamplePeriod / TimeSpan.TicksPerMillisecond, 7),
122 StatVerbosity.Debug));
82 } 123 }
83 124
84 public bool HandlesRegion(Location x) 125 public bool HandlesRegion(Location x)
@@ -185,6 +226,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
185 protected bool m_sendPing; 226 protected bool m_sendPing;
186 227
187 private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>(); 228 private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>();
229
230 /// <summary>
231 /// Event used to signal when queued packets are available for sending.
232 /// </summary>
233 /// <remarks>
234 /// This allows the outbound loop to only operate when there is data to send rather than continuously polling.
235 /// Some data is sent immediately and not queued. That data would not trigger this event.
236 /// </remarks>
237 private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false);
238
188 private Pool<IncomingPacket> m_incomingPacketPool; 239 private Pool<IncomingPacket> m_incomingPacketPool;
189 240
190 /// <summary> 241 /// <summary>
@@ -462,6 +513,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
462 m_scene = (Scene)scene; 513 m_scene = (Scene)scene;
463 m_location = new Location(m_scene.RegionInfo.RegionHandle); 514 m_location = new Location(m_scene.RegionInfo.RegionHandle);
464 515
516 StatsManager.RegisterStat(
517 new Stat(
518 "InboxPacketsCount",
519 "Number of LL protocol packets waiting for the second stage of processing after initial receive.",
520 "Number of LL protocol packets waiting for the second stage of processing after initial receive.",
521 "",
522 "clientstack",
523 scene.Name,
524 StatType.Pull,
525 MeasuresOfInterest.AverageChangeOverTime,
526 stat => stat.Value = packetInbox.Count,
527 StatVerbosity.Debug));
528
465 // XXX: These stats are also pool stats but we register them separately since they are currently not 529 // XXX: These stats are also pool stats but we register them separately since they are currently not
466 // turned on and off by EnablePools()/DisablePools() 530 // turned on and off by EnablePools()/DisablePools()
467 StatsManager.RegisterStat( 531 StatsManager.RegisterStat(
@@ -575,6 +639,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
575 "debug lludp status", 639 "debug lludp status",
576 "Return status of LLUDP packet processing.", 640 "Return status of LLUDP packet processing.",
577 HandleStatusCommand); 641 HandleStatusCommand);
642
643 MainConsole.Instance.Commands.AddCommand(
644 "Debug",
645 false,
646 "debug lludp toggle agentupdate",
647 "debug lludp toggle agentupdate",
648 "Toggle whether agentupdate packets are processed or simply discarded.",
649 HandleAgentUpdateCommand);
578 } 650 }
579 651
580 private void HandlePacketCommand(string module, string[] args) 652 private void HandlePacketCommand(string module, string[] args)
@@ -709,6 +781,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
709 } 781 }
710 } 782 }
711 783
784 bool m_discardAgentUpdates;
785
786 private void HandleAgentUpdateCommand(string module, string[] args)
787 {
788 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
789 return;
790
791 m_discardAgentUpdates = !m_discardAgentUpdates;
792
793 MainConsole.Instance.OutputFormat(
794 "Discard AgentUpdates now {0} for {1}", m_discardAgentUpdates, m_scene.Name);
795 }
796
712 private void HandleStatusCommand(string module, string[] args) 797 private void HandleStatusCommand(string module, string[] args)
713 { 798 {
714 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) 799 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
@@ -809,12 +894,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
809 } 894 }
810 895
811 PacketPool.Instance.ReturnPacket(packet); 896 PacketPool.Instance.ReturnPacket(packet);
812 m_dataPresentEvent.Set();
813 897
898 m_dataPresentEvent.Set();
814 } 899 }
815 900
816 private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false);
817
818 /// <summary> 901 /// <summary>
819 /// Start the process of sending a packet to the client. 902 /// Start the process of sending a packet to the client.
820 /// </summary> 903 /// </summary>
@@ -1325,6 +1408,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1325 LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length); 1408 LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length);
1326 #endregion BinaryStats 1409 #endregion BinaryStats
1327 1410
1411 if (packet.Type == PacketType.AgentUpdate)
1412 {
1413 if (m_discardAgentUpdates)
1414 return;
1415
1416 ((LLClientView)client).TotalAgentUpdates++;
1417
1418 AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
1419
1420 LLClientView llClient = client as LLClientView;
1421 if (agentUpdate.AgentData.SessionID != client.SessionId
1422 || agentUpdate.AgentData.AgentID != client.AgentId
1423 || !(llClient == null || llClient.CheckAgentUpdateSignificance(agentUpdate.AgentData)) )
1424 {
1425 PacketPool.Instance.ReturnPacket(packet);
1426 return;
1427 }
1428 }
1429
1328 #region Ping Check Handling 1430 #region Ping Check Handling
1329 1431
1330 if (packet.Type == PacketType.StartPingCheck) 1432 if (packet.Type == PacketType.StartPingCheck)
@@ -1734,7 +1836,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1734 // Action generic every round 1836 // Action generic every round
1735 Action<IClientAPI> clientPacketHandler = ClientOutgoingPacketHandler; 1837 Action<IClientAPI> clientPacketHandler = ClientOutgoingPacketHandler;
1736 1838
1737// while (true)
1738 while (base.IsRunningOutbound) 1839 while (base.IsRunningOutbound)
1739 { 1840 {
1740 m_scene.ThreadAlive(2); 1841 m_scene.ThreadAlive(2);
@@ -1798,6 +1899,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1798 // token bucket could get more tokens 1899 // token bucket could get more tokens
1799 //if (!m_packetSent) 1900 //if (!m_packetSent)
1800 // Thread.Sleep((int)TickCountResolution); 1901 // Thread.Sleep((int)TickCountResolution);
1902 //
1903 // Instead, now wait for data present to be explicitly signalled. Evidence so far is that with
1904 // modern mono it reduces CPU base load since there is no more continuous polling.
1801 m_dataPresentEvent.WaitOne(100); 1905 m_dataPresentEvent.WaitOne(100);
1802 1906
1803 Watchdog.UpdateThread(); 1907 Watchdog.UpdateThread();
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
index 7035e38..48c5b37 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
@@ -78,6 +78,36 @@ namespace OpenMetaverse
78 public bool IsRunningOutbound { get; private set; } 78 public bool IsRunningOutbound { get; private set; }
79 79
80 /// <summary> 80 /// <summary>
81 /// Number of UDP receives.
82 /// </summary>
83 public int UdpReceives { get; private set; }
84
85 /// <summary>
86 /// Number of UDP sends
87 /// </summary>
88 public int UdpSends { get; private set; }
89
90 /// <summary>
91 /// Number of receives over which to establish a receive time average.
92 /// </summary>
93 private readonly static int s_receiveTimeSamples = 500;
94
95 /// <summary>
96 /// Current number of samples taken to establish a receive time average.
97 /// </summary>
98 private int m_currentReceiveTimeSamples;
99
100 /// <summary>
101 /// Cumulative receive time for the sample so far.
102 /// </summary>
103 private int m_receiveTicksInCurrentSamplePeriod;
104
105 /// <summary>
106 /// The average time taken for each require receive in the last sample.
107 /// </summary>
108 public float AverageReceiveTicksForLastSamplePeriod { get; private set; }
109
110 /// <summary>
81 /// Default constructor 111 /// Default constructor
82 /// </summary> 112 /// </summary>
83 /// <param name="bindAddress">Local IP address to bind the server to</param> 113 /// <param name="bindAddress">Local IP address to bind the server to</param>
@@ -111,6 +141,8 @@ namespace OpenMetaverse
111 141
112 if (!IsRunningInbound) 142 if (!IsRunningInbound)
113 { 143 {
144 m_log.DebugFormat("[UDPBASE]: Starting inbound UDP loop");
145
114 const int SIO_UDP_CONNRESET = -1744830452; 146 const int SIO_UDP_CONNRESET = -1744830452;
115 147
116 IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort); 148 IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort);
@@ -151,6 +183,8 @@ namespace OpenMetaverse
151 /// </summary> 183 /// </summary>
152 public void StartOutbound() 184 public void StartOutbound()
153 { 185 {
186 m_log.DebugFormat("[UDPBASE]: Starting outbound UDP loop");
187
154 IsRunningOutbound = true; 188 IsRunningOutbound = true;
155 } 189 }
156 190
@@ -158,10 +192,8 @@ namespace OpenMetaverse
158 { 192 {
159 if (IsRunningInbound) 193 if (IsRunningInbound)
160 { 194 {
161 // wait indefinitely for a writer lock. Once this is called, the .NET runtime 195 m_log.DebugFormat("[UDPBASE]: Stopping inbound UDP loop");
162 // will deny any more reader locks, in effect blocking all other send/receive 196
163 // threads. Once we have the lock, we set IsRunningInbound = false to inform the other
164 // threads that the socket is closed.
165 IsRunningInbound = false; 197 IsRunningInbound = false;
166 m_udpSocket.Close(); 198 m_udpSocket.Close();
167 } 199 }
@@ -169,6 +201,8 @@ namespace OpenMetaverse
169 201
170 public void StopOutbound() 202 public void StopOutbound()
171 { 203 {
204 m_log.DebugFormat("[UDPBASE]: Stopping outbound UDP loop");
205
172 IsRunningOutbound = false; 206 IsRunningOutbound = false;
173 } 207 }
174 208
@@ -267,6 +301,8 @@ namespace OpenMetaverse
267 // to AsyncBeginReceive 301 // to AsyncBeginReceive
268 if (IsRunningInbound) 302 if (IsRunningInbound)
269 { 303 {
304 UdpReceives++;
305
270 // Asynchronous mode will start another receive before the 306 // Asynchronous mode will start another receive before the
271 // callback for this packet is even fired. Very parallel :-) 307 // callback for this packet is even fired. Very parallel :-)
272 if (m_asyncPacketHandling) 308 if (m_asyncPacketHandling)
@@ -278,6 +314,8 @@ namespace OpenMetaverse
278 314
279 try 315 try
280 { 316 {
317 int startTick = Util.EnvironmentTickCount();
318
281 // get the length of data actually read from the socket, store it with the 319 // get the length of data actually read from the socket, store it with the
282 // buffer 320 // buffer
283 buffer.DataLength = m_udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint); 321 buffer.DataLength = m_udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint);
@@ -285,6 +323,23 @@ namespace OpenMetaverse
285 // call the abstract method PacketReceived(), passing the buffer that 323 // call the abstract method PacketReceived(), passing the buffer that
286 // has just been filled from the socket read. 324 // has just been filled from the socket read.
287 PacketReceived(buffer); 325 PacketReceived(buffer);
326
327 // If more than one thread can be calling AsyncEndReceive() at once (e.g. if m_asyncPacketHandler)
328 // then a particular stat may be inaccurate due to a race condition. We won't worry about this
329 // since this should be rare and won't cause a runtime problem.
330 if (m_currentReceiveTimeSamples >= s_receiveTimeSamples)
331 {
332 AverageReceiveTicksForLastSamplePeriod
333 = (float)m_receiveTicksInCurrentSamplePeriod / s_receiveTimeSamples;
334
335 m_receiveTicksInCurrentSamplePeriod = 0;
336 m_currentReceiveTimeSamples = 0;
337 }
338 else
339 {
340 m_receiveTicksInCurrentSamplePeriod += Util.EnvironmentTickCountSubtract(startTick);
341 m_currentReceiveTimeSamples++;
342 }
288 } 343 }
289 catch (SocketException) { } 344 catch (SocketException) { }
290 catch (ObjectDisposedException) { } 345 catch (ObjectDisposedException) { }
@@ -298,14 +353,13 @@ namespace OpenMetaverse
298 if (!m_asyncPacketHandling) 353 if (!m_asyncPacketHandling)
299 AsyncBeginReceive(); 354 AsyncBeginReceive();
300 } 355 }
301
302 } 356 }
303 } 357 }
304 358
305 public void AsyncBeginSend(UDPPacketBuffer buf) 359 public void AsyncBeginSend(UDPPacketBuffer buf)
306 { 360 {
307 if (IsRunningOutbound) 361// if (IsRunningOutbound)
308 { 362// {
309 try 363 try
310 { 364 {
311 m_udpSocket.BeginSendTo( 365 m_udpSocket.BeginSendTo(
@@ -319,7 +373,7 @@ namespace OpenMetaverse
319 } 373 }
320 catch (SocketException) { } 374 catch (SocketException) { }
321 catch (ObjectDisposedException) { } 375 catch (ObjectDisposedException) { }
322 } 376// }
323 } 377 }
324 378
325 void AsyncEndSend(IAsyncResult result) 379 void AsyncEndSend(IAsyncResult result)
@@ -328,6 +382,8 @@ namespace OpenMetaverse
328 { 382 {
329// UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState; 383// UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState;
330 m_udpSocket.EndSendTo(result); 384 m_udpSocket.EndSendTo(result);
385
386 UdpSends++;
331 } 387 }
332 catch (SocketException) { } 388 catch (SocketException) { }
333 catch (ObjectDisposedException) { } 389 catch (ObjectDisposedException) { }