diff options
author | Melanie | 2013-07-24 04:45:07 +0100 |
---|---|---|
committer | Melanie | 2013-07-24 04:45:07 +0100 |
commit | e82d4154a2e348e4a38f01cb1877878c94569bba (patch) | |
tree | 7b27e6d30d04f6089fd17d5779cfb0a81e50d508 /OpenSim/Region/ClientStack/Linden | |
parent | Merge branch 'master' into careminster (diff) | |
parent | For unknown user issue, bump GUN7 to GUN8 and UMMAU3 to UMMAU4 to assess what... (diff) | |
download | opensim-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')
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; | |||
31 | using System.Threading; | 31 | using System.Threading; |
32 | using log4net; | 32 | using log4net; |
33 | using OpenSim.Framework; | 33 | using OpenSim.Framework; |
34 | using OpenSim.Framework.Monitoring; | ||
34 | using OpenMetaverse; | 35 | using OpenMetaverse; |
35 | using OpenMetaverse.Packets; | 36 | using OpenMetaverse.Packets; |
36 | 37 | ||
@@ -81,6 +82,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
81 | /// hooked to put more data on the empty queue</summary> | 82 | /// hooked to put more data on the empty queue</summary> |
82 | public event QueueEmpty OnQueueEmpty; | 83 | public event QueueEmpty OnQueueEmpty; |
83 | 84 | ||
85 | public event Func<ThrottleOutPacketTypeFlags, bool> HasUpdates; | ||
86 | |||
84 | /// <summary>AgentID for this client</summary> | 87 | /// <summary>AgentID for this client</summary> |
85 | public readonly UUID AgentID; | 88 | public readonly UUID AgentID; |
86 | /// <summary>The remote address of the connected client</summary> | 89 | /// <summary>The remote address of the connected client</summary> |
@@ -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) { } |