From 854f6723ac6b4ab4cf7ad3a4202040f55fa0997e Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 7 Feb 2024 22:12:05 +0000 Subject: [PATCH] mantis 9111: make code a bit more resilient to requests for large bit rates --- .../ClientStack/Linden/UDP/LLUDPClient.cs | 103 ++++++++---------- .../Region/Framework/Scenes/ScenePresence.cs | 3 +- bin/OpenMetaverse.Rendering.Meshmerizer.dll | Bin 24576 -> 24576 bytes bin/OpenMetaverse.StructuredData.dll | Bin 126976 -> 126976 bytes bin/OpenMetaverse.dll | Bin 2215936 -> 2215936 bytes bin/OpenMetaverseTypes.dll | Bin 192512 -> 192512 bytes 6 files changed, 49 insertions(+), 57 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs index 74960f4399..58399476fb 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs @@ -163,15 +163,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// A reference to the LLUDPServer that is managing this client private readonly LLUDPServer m_udpServer; - /// Caches packed throttle information - private byte[] m_packedThrottles; - private readonly int m_defaultRTO = 1000; // 1sec is the recommendation in the RFC private readonly int m_maxRTO = 3000; private readonly int m_minRTO = 250; private readonly float m_burstTime; - private readonly int m_maxRate; + private readonly float m_maxRate; public double m_lastStartpingTimeMS; public int m_pingMS; @@ -355,7 +352,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP public void SendPacketStats() { PacketStats callback = OnPacketStats; - if (callback != null) + if (callback is not null) { int newPacketsReceived = PacketsReceived - m_packetsReceivedReported; int newPacketsSent = PacketsSent - m_packetsSentReported; @@ -376,7 +373,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP public void SetThrottles(byte[] throttleData, float factor) { byte[] adjData; - int pos = 0; if (!BitConverter.IsLittleEndian) { @@ -395,30 +391,38 @@ namespace OpenSim.Region.ClientStack.LindenUDP // 0.125f converts from bits to bytes float scale = 0.125f * factor; - int resend = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4; - int land = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4; - int wind = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4; - int cloud = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4; - int task = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4; - int texture = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4; - int asset = (int)(BitConverter.ToSingle(adjData, pos) * scale); + float resend = Utils.BytesToFloat(adjData) * scale; + float land = Utils.BytesToFloat(adjData, 4) * scale; + float wind = Utils.BytesToFloat(adjData, 8) * scale; + float cloud = Utils.BytesToFloat(adjData, 12) * scale; + float task = Utils.BytesToFloat(adjData, 16) * scale; + float texture = Utils.BytesToFloat(adjData, 20) * scale; + float asset = Utils.BytesToFloat(adjData, 24) * scale; - int total = resend + land + wind + cloud + task + texture + asset; + resend = Math.Clamp(resend, 1000, m_maxRate); + land = Math.Clamp(land, 1000, m_maxRate); + wind = Math.Clamp(wind, 50, m_maxRate); + cloud = Math.Clamp(cloud, 50, m_maxRate); + task = Math.Clamp(task, 1000, m_maxRate); + texture = Math.Clamp(texture, 1000, m_maxRate); + asset = Math.Clamp(asset, 1000, m_maxRate); + + float total = resend + land + wind + cloud + task + texture + asset; if(total > m_maxRate) { - scale = (float)total / m_maxRate; - resend = (int)(resend * scale); - land = (int)(land * scale); - wind = (int)(wind * scale); - cloud = (int)(cloud * scale); - task = (int)(task * scale); - texture = (int)(texture * scale); - asset = (int)(texture * scale); - int ntotal = resend + land + wind + cloud + task + texture + asset; - m_log.DebugFormat("[LLUDPCLIENT]: limiting {0} bandwith from {1} to {2}",AgentID, ntotal, total); + scale = m_maxRate / total; + resend *= scale; + land *= scale; + wind *= scale; + cloud *= scale; + task *= scale; + texture *= scale; + asset *= scale; + float ntotal = total * scale; + m_log.Debug($"[LLUDPCLIENT]: limiting {AgentID} bandwith from {total} to {ntotal}"); total = ntotal; } - + if (ThrottleDebugLevel > 0) { m_log.DebugFormat( @@ -454,47 +458,36 @@ namespace OpenSim.Region.ClientStack.LindenUDP bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture]; bucket.RequestedDripRate = texture; bucket.RequestedBurst = texture * m_burstTime; - - m_packedThrottles = null; } public byte[] GetThrottlesPacked(float multiplier) { - byte[] data = m_packedThrottles; + byte[] data = new byte[7 * 4]; + + // multiply by 8 to convert bytes back to bits + multiplier *= 8; + float rate; - if (data == null) - { - float rate; + rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].RequestedDripRate * multiplier; + Utils.FloatToBytes(rate, data, 0); - data = new byte[7 * 4]; - int i = 0; + rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Land].RequestedDripRate * multiplier; + Utils.FloatToBytes(rate, data, 4); - // multiply by 8 to convert bytes back to bits - multiplier *= 8; + rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].RequestedDripRate * multiplier; + Utils.FloatToBytes(rate, data, 8); - rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].RequestedDripRate * multiplier; - Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; + rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].RequestedDripRate * multiplier; + Utils.FloatToBytes(rate, data, 12); - rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Land].RequestedDripRate * multiplier; - Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; + rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Task].RequestedDripRate * multiplier; + Utils.FloatToBytes(rate, data, 16); - rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].RequestedDripRate * multiplier; - Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; + rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].RequestedDripRate * multiplier; + Utils.FloatToBytes(rate, data, 20); - rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].RequestedDripRate * multiplier; - Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; - - rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Task].RequestedDripRate * multiplier; - Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; - - rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].RequestedDripRate * multiplier; - Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; - - rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].RequestedDripRate * multiplier; - Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); //i += 4; - - m_packedThrottles = data; - } + rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].RequestedDripRate * multiplier; + Utils.FloatToBytes(rate, data, 24); return data; } diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index ac73e66f38..adb107320b 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -4790,10 +4790,9 @@ namespace OpenSim.Region.Framework.Scenes Vector3 offset = new(shiftx, shifty, 0f); - DrawDistance = cAgentData.Far; - m_pos = cAgentData.Position + offset; CameraPosition = cAgentData.Center + offset; + DrawDistance = cAgentData.Far; if (cAgentData.ChildrenCapSeeds is not null && cAgentData.ChildrenCapSeeds.Count > 0) { diff --git a/bin/OpenMetaverse.Rendering.Meshmerizer.dll b/bin/OpenMetaverse.Rendering.Meshmerizer.dll index b987e5b35e6c904275c8e6cb19cd1201b750dfbe..4c101ec69dc607c1c907a4ca717e112005e65eb8 100755 GIT binary patch delta 107 zcmZoTz}RqraY6@+pz5?Q8+#J81y1^|yS-CqvG?u?`(E!q_KXV1gM?L7-~RWyLrEXqdov_ Cn=knQ delta 107 zcmZoTz}RqraY6?RS7`XFjXeq40&Kh$78xbp-d%>pjk|-Er*HnFeT13i)UzdPCLhrc z5O^%OY06pWX!lhNvU2AyB#KN{F{oC631&eBfvR;nf^J=L=nSj-sBuDf^L_(IeE@)Y BE^+_> diff --git a/bin/OpenMetaverse.StructuredData.dll b/bin/OpenMetaverse.StructuredData.dll index 0115602b4d29c0e696232573d99d65fc6cd1caf0..d51dcef74fa4bf834104cd5164d85a0f2d841050 100755 GIT binary patch delta 114 zcmZp8z~1nHeL@Gzbph# zx2BsMV+;^5Tw%4}<`;v{BKbU47Ed$J=~Ip|<|;r%V_>2n^}m+R7Jk8TX;Z@%KAr7~ J#~JTy002KmF*^VN delta 114 zcmZp8z~1nHeL@Edm-?(jjXhg?7!}qCR6b{&Bx}g(y>jZJSJ%42b++$W!&oB8qM=o} zWV*>Q#sGoHR{!N9FMT|B{JeFc{_pag)2AF`%vFGjYW{$Vg4D0ASKwh$`Ln{Gi_3Dm J;&I0N8USfxGo}Cl diff --git a/bin/OpenMetaverse.dll b/bin/OpenMetaverse.dll index 04c04ca6f2c6d64ee6e381e276bcbf0a1735b32c..10180e59481ca38d5a864e836153b3437e13dee2 100755 GIT binary patch delta 210 zcmZoz(9YNZ#1lGLdUN@HH}sxIT!nqz?jDDUYqG?pGlCo29iGT!hF4Rpu%N2+S(G z_JmhH->E&c!uy3YckA?)xr+V@P|-^;QK0(DLuQhpQ+jB>$K6-kZ@*=)bdnqFpacX%Sd-QkJCgB>iB#n~QCSDC9AAi%dE zE9qs!C65)>&6cfKpG!|~nXBlp02S4E0Tl(Q&*5Lr&z0gcYdMQy@Al7g6?u&SwYXL+ diff --git a/bin/OpenMetaverseTypes.dll b/bin/OpenMetaverseTypes.dll index 39133f8fed89268c1e81938fd6b6905bb101d1a3..3d7096d040aa1febbe1878754c27de1438b652a7 100755 GIT binary patch delta 7457 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 delta 7448 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 ml>e