From 14d0a2ac7412951916e220c0f04e472fc2f114f0 Mon Sep 17 00:00:00 2001
From: Sean Dague
Date: Mon, 3 Dec 2007 21:47:28 +0000
Subject: further encapsulation of function in PacketQueue and PacketThrottle

---
 OpenSim/Region/ClientStack/PacketQueue.cs    | 165 ++++++++++++++++++++++++++-
 OpenSim/Region/ClientStack/PacketThrottle.cs |  11 +-
 2 files changed, 172 insertions(+), 4 deletions(-)

(limited to 'OpenSim')

diff --git a/OpenSim/Region/ClientStack/PacketQueue.cs b/OpenSim/Region/ClientStack/PacketQueue.cs
index 3d284e8..270af48 100644
--- a/OpenSim/Region/ClientStack/PacketQueue.cs
+++ b/OpenSim/Region/ClientStack/PacketQueue.cs
@@ -221,9 +221,168 @@ namespace OpenSim.Region.ClientStack
 
         }
 
+        private void ThrottleCheck(ref PacketThrottle throttle, ref Queue<QueItem> q, QueItem item)
+        {
+            // The idea..  is if the packet throttle queues are empty
+            // and the client is under throttle for the type.  Queue
+            // it up directly.  This basically short cuts having to
+            // wait for the timer to fire to put things into the
+            // output queue
 
-    }
+            if((q.Count == 0) && (throttle.UnderLimit()))
+            {
+                throttle.Add(item.Packet.ToBytes().Length);
+                TotalThrottle.Add(item.Packet.ToBytes().Length);
+                SendQueue.Enqueue(item);
+            }
+            else
+            {
+                q.Enqueue(item);
+            }
+        }
+
+        public void Add(QueItem item)
+        {
+            switch (item.throttleType)
+            {
+                case ThrottleOutPacketType.Resend:
+                    ThrottleCheck(ref ResendThrottle, ref ResendOutgoingPacketQueue, item);
+                    break;
+                case ThrottleOutPacketType.Texture:
+                    ThrottleCheck(ref TextureThrottle, ref TextureOutgoingPacketQueue, item);
+                    break;
+                case ThrottleOutPacketType.Task:
+                    ThrottleCheck(ref TaskThrottle, ref TaskOutgoingPacketQueue, item);
+                    break;
+                case ThrottleOutPacketType.Land:
+                    ThrottleCheck(ref LandThrottle, ref LandOutgoingPacketQueue, item);
+                    break;
+                case ThrottleOutPacketType.Asset:
+                    ThrottleCheck(ref AssetThrottle, ref AssetOutgoingPacketQueue, item);
+                    break;
+                case ThrottleOutPacketType.Cloud:
+                    ThrottleCheck(ref CloudThrottle, ref CloudOutgoingPacketQueue, item);
+                    break;
+                case ThrottleOutPacketType.Wind:
+                    ThrottleCheck(ref WindThrottle, ref WindOutgoingPacketQueue, item);
+                    break;
 
-    
-    
+                default:
+                    // Acknowledgements and other such stuff should go directly to the blocking Queue
+                    // Throttling them may and likely 'will' be problematic
+                    SendQueue.Enqueue(item); 
+                    break;
+            }
+
+        }
+
+        private int ScaleThrottle(int value, int curmax, int newmax)
+        {
+            return (int)(((float)value/(float)curmax) * newmax);
+        }
+
+        public void SetThrottleFromClient(Packet Pack)
+        {
+            
+            //OpenSim.Framework.Console.MainLog.Instance.Verbose("CLIENT", "unhandled packet " + Pack.ToString());
+            
+            AgentThrottlePacket atpack = (AgentThrottlePacket)Pack;
+            
+            byte[] throttle = atpack.Throttle.Throttles;
+            int tResend = -1;
+            int tLand = -1;
+            int tWind = -1;
+            int tCloud = -1;
+            int tTask = -1;
+            int tTexture = -1;
+            int tAsset = -1;
+            int tall = -1;
+            int singlefloat = 4;
+
+            //Agent Throttle Block contains 7 single floatingpoint values.
+            int j = 0;
+
+            // Some Systems may be big endian...  
+            // it might be smart to do this check more often... 
+            if (!BitConverter.IsLittleEndian)
+                for (int i = 0; i < 7; i++)
+                    Array.Reverse(throttle, j + i * singlefloat, singlefloat);
+            
+            // values gotten from libsecondlife.org/wiki/Throttle.  Thanks MW_
+            // bytes
+            // Convert to integer, since..   the full fp space isn't used.
+            tResend = (int)BitConverter.ToSingle(throttle, j);
+            j += singlefloat;
+            tLand = (int)BitConverter.ToSingle(throttle, j);
+            j += singlefloat;
+            tWind = (int)BitConverter.ToSingle(throttle, j);
+            j += singlefloat;
+            tCloud = (int)BitConverter.ToSingle(throttle, j);
+            j += singlefloat;
+            tTask = (int)BitConverter.ToSingle(throttle, j);
+            j += singlefloat;
+            tTexture = (int)BitConverter.ToSingle(throttle, j);
+            j += singlefloat;
+            tAsset = (int)BitConverter.ToSingle(throttle, j);
+            
+            tall = tResend + tLand + tWind + tCloud + tTask + tTexture + tAsset;
+            /*
+              OpenSim.Framework.Console.MainLog.Instance.Verbose("CLIENT", "Client AgentThrottle - Got throttle:resendbytes=" + tResend +
+              " landbytes=" + tLand +
+              " windbytes=" + tWind +
+              " cloudbytes=" + tCloud +
+              " taskbytes=" + tTask +
+              " texturebytes=" + tTexture +
+              " Assetbytes=" + tAsset +
+              " Allbytes=" + tall);
+            */
+            
+            // Total Sanity
+            // Make sure that the client sent sane total values.
+            
+            // If the client didn't send acceptable values....
+            // Scale the clients values down until they are acceptable.
+            
+            if (tall <= TotalThrottle.Max)
+            {
+                ResendThrottle.Throttle = tResend;
+                LandThrottle.Throttle = tLand;
+                WindThrottle.Throttle = tWind;
+                CloudThrottle.Throttle = tCloud;
+                TaskThrottle.Throttle = tTask;
+                TextureThrottle.Throttle = tTexture;
+                AssetThrottle.Throttle = tAsset;
+                TotalThrottle.Throttle = tall;
+            } 
+            else if (tall < 1)
+            {
+                // client is stupid, penalize him by minning everything
+                ResendThrottle.Throttle = ResendThrottle.Min;
+                LandThrottle.Throttle = LandThrottle.Min;
+                WindThrottle.Throttle = WindThrottle.Min;
+                CloudThrottle.Throttle = CloudThrottle.Min;
+                TaskThrottle.Throttle = TaskThrottle.Min;
+                TextureThrottle.Throttle = TextureThrottle.Min;
+                AssetThrottle.Throttle = AssetThrottle.Min;
+                TotalThrottle.Throttle = TotalThrottle.Min;
+            }
+            else
+            {
+                // we're over so figure out percentages and use those
+                ResendThrottle.Throttle = tResend;
+
+                LandThrottle.Throttle = ScaleThrottle(tLand, tall, TotalThrottle.Max);
+                WindThrottle.Throttle = ScaleThrottle(tWind, tall, TotalThrottle.Max);
+                CloudThrottle.Throttle = ScaleThrottle(tCloud, tall, TotalThrottle.Max);
+                TaskThrottle.Throttle = ScaleThrottle(tTask, tall, TotalThrottle.Max);
+                TextureThrottle.Throttle = ScaleThrottle(tTexture, tall, TotalThrottle.Max);
+                AssetThrottle.Throttle = ScaleThrottle(tAsset, tall, TotalThrottle.Max);
+                TotalThrottle.Throttle = TotalThrottle.Max;
+            }
+            // effectively wiggling the slider causes things reset
+            ResetCounters();
+            
+        }
+
+    }
 }
\ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/PacketThrottle.cs b/OpenSim/Region/ClientStack/PacketThrottle.cs
index 30d7c25..0f52802 100644
--- a/OpenSim/Region/ClientStack/PacketThrottle.cs
+++ b/OpenSim/Region/ClientStack/PacketThrottle.cs
@@ -89,7 +89,16 @@ namespace OpenSim.Region.ClientStack
         public int Throttle
         {
             get {return throttle;}
-            set {throttle = value;}
+            set 
+            {
+                if (value > max) {
+                    throttle = max;
+                } else if (value < min) {
+                    throttle = min;
+                } else {
+                    throttle = value;
+                }
+            }
         }
     }
 }
\ No newline at end of file
-- 
cgit v1.1