From d8ee0cbe1cf93ca521f52ce39aa2a15cb5784e48 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 30 Apr 2011 09:24:15 -0700 Subject: First stab at cleaning up Caps. Compiles. Untested. --- .../Region/ClientStack/LindenUDP/LLUDPClient.cs | 697 --------------------- 1 file changed, 697 deletions(-) delete mode 100644 OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs (limited to 'OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs deleted file mode 100644 index ca5501d..0000000 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs +++ /dev/null @@ -1,697 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Net; -using System.Threading; -using log4net; -using OpenSim.Framework; -using OpenMetaverse; -using OpenMetaverse.Packets; - -using TokenBucket = OpenSim.Region.ClientStack.LindenUDP.TokenBucket; - -namespace OpenSim.Region.ClientStack.LindenUDP -{ - #region Delegates - - /// - /// Fired when updated networking stats are produced for this client - /// - /// Number of incoming packets received since this - /// event was last fired - /// Number of outgoing packets sent since this - /// event was last fired - /// Current total number of bytes in packets we - /// are waiting on ACKs for - public delegate void PacketStats(int inPackets, int outPackets, int unAckedBytes); - /// - /// Fired when the queue for one or more packet categories is empty. This - /// event can be hooked to put more data on the empty queues - /// - /// Categories of the packet queues that are empty - public delegate void QueueEmpty(ThrottleOutPacketTypeFlags categories); - - #endregion Delegates - - /// - /// Tracks state for a client UDP connection and provides client-specific methods - /// - public sealed class LLUDPClient - { - // TODO: Make this a config setting - /// Percentage of the task throttle category that is allocated to avatar and prim - /// state updates - const float STATE_TASK_PERCENTAGE = 0.8f; - - private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); - - /// The number of packet categories to throttle on. If a throttle category is added - /// or removed, this number must also change - const int THROTTLE_CATEGORY_COUNT = 8; - - /// Fired when updated networking stats are produced for this client - public event PacketStats OnPacketStats; - /// Fired when the queue for a packet category is empty. This event can be - /// hooked to put more data on the empty queue - public event QueueEmpty OnQueueEmpty; - - /// AgentID for this client - public readonly UUID AgentID; - /// The remote address of the connected client - public readonly IPEndPoint RemoteEndPoint; - /// Circuit code that this client is connected on - public readonly uint CircuitCode; - /// Sequence numbers of packets we've received (for duplicate checking) - public readonly IncomingPacketHistoryCollection PacketArchive = new IncomingPacketHistoryCollection(200); - /// Packets we have sent that need to be ACKed by the client - public readonly UnackedPacketCollection NeedAcks = new UnackedPacketCollection(); - /// ACKs that are queued up, waiting to be sent to the client - public readonly OpenSim.Framework.LocklessQueue PendingAcks = new OpenSim.Framework.LocklessQueue(); - - /// Current packet sequence number - public int CurrentSequence; - /// Current ping sequence number - public byte CurrentPingSequence; - /// True when this connection is alive, otherwise false - public bool IsConnected = true; - /// True when this connection is paused, otherwise false - public bool IsPaused; - /// Environment.TickCount when the last packet was received for this client - public int TickLastPacketReceived; - - /// Smoothed round-trip time. A smoothed average of the round-trip time for sending a - /// reliable packet to the client and receiving an ACK - public float SRTT; - /// Round-trip time variance. Measures the consistency of round-trip times - public float RTTVAR; - /// Retransmission timeout. Packets that have not been acknowledged in this number of - /// milliseconds or longer will be resent - /// Calculated from and using the - /// guidelines in RFC 2988 - public int RTO; - /// Number of bytes received since the last acknowledgement was sent out. This is used - /// to loosely follow the TCP delayed ACK algorithm in RFC 1122 (4.2.3.2) - public int BytesSinceLastACK; - /// Number of packets received from this client - public int PacketsReceived; - /// Number of packets sent to this client - public int PacketsSent; - /// Number of packets resent to this client - public int PacketsResent; - /// Total byte count of unacked packets sent to this client - public int UnackedBytes; - - /// Total number of received packets that we have reported to the OnPacketStats event(s) - private int m_packetsReceivedReported; - /// Total number of sent packets that we have reported to the OnPacketStats event(s) - private int m_packetsSentReported; - /// Holds the Environment.TickCount value of when the next OnQueueEmpty can be fired - private int m_nextOnQueueEmpty = 1; - - /// Throttle bucket for this agent's connection - private readonly AdaptiveTokenBucket m_throttleClient; - public AdaptiveTokenBucket FlowThrottle - { - get { return m_throttleClient; } - } - - /// Throttle bucket for this agent's connection - private readonly TokenBucket m_throttleCategory; - /// Throttle buckets for each packet category - private readonly TokenBucket[] m_throttleCategories; - /// Outgoing queues for throttled packets - private readonly OpenSim.Framework.LocklessQueue[] m_packetOutboxes = new OpenSim.Framework.LocklessQueue[THROTTLE_CATEGORY_COUNT]; - /// A container that can hold one packet for each outbox, used to store - /// dequeued packets that are being held for throttling - private readonly OutgoingPacket[] m_nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT]; - /// A reference to the LLUDPServer that is managing this client - private readonly LLUDPServer m_udpServer; - - /// Caches packed throttle information - private byte[] m_packedThrottles; - - private int m_defaultRTO = 1000; // 1sec is the recommendation in the RFC - private int m_maxRTO = 60000; - - /// - /// Default constructor - /// - /// Reference to the UDP server this client is connected to - /// Default throttling rates and maximum throttle limits - /// Parent HTB (hierarchical token bucket) - /// that the child throttles will be governed by - /// Circuit code for this connection - /// AgentID for the connected agent - /// Remote endpoint for this connection - public LLUDPClient(LLUDPServer server, ThrottleRates rates, TokenBucket parentThrottle, uint circuitCode, UUID agentID, IPEndPoint remoteEndPoint, int defaultRTO, int maxRTO) - { - AgentID = agentID; - RemoteEndPoint = remoteEndPoint; - CircuitCode = circuitCode; - m_udpServer = server; - if (defaultRTO != 0) - m_defaultRTO = defaultRTO; - if (maxRTO != 0) - m_maxRTO = maxRTO; - - // Create a token bucket throttle for this client that has the scene token bucket as a parent - m_throttleClient = new AdaptiveTokenBucket(parentThrottle, rates.Total, rates.AdaptiveThrottlesEnabled); - // Create a token bucket throttle for the total categary with the client bucket as a throttle - m_throttleCategory = new TokenBucket(m_throttleClient, 0); - // Create an array of token buckets for this clients different throttle categories - m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; - - for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) - { - ThrottleOutPacketType type = (ThrottleOutPacketType)i; - - // Initialize the packet outboxes, where packets sit while they are waiting for tokens - m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue(); - // Initialize the token buckets that control the throttling for each category - m_throttleCategories[i] = new TokenBucket(m_throttleCategory, rates.GetRate(type)); - } - - // Default the retransmission timeout to three seconds - RTO = m_defaultRTO; - - // Initialize this to a sane value to prevent early disconnects - TickLastPacketReceived = Environment.TickCount & Int32.MaxValue; - } - - /// - /// Shuts down this client connection - /// - public void Shutdown() - { - IsConnected = false; - for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) - { - m_packetOutboxes[i].Clear(); - m_nextPackets[i] = null; - } - - // pull the throttle out of the scene throttle - m_throttleClient.Parent.UnregisterRequest(m_throttleClient); - OnPacketStats = null; - OnQueueEmpty = null; - } - - /// - /// Gets information about this client connection - /// - /// Information about the client connection - public ClientInfo GetClientInfo() - { - // TODO: This data structure is wrong in so many ways. Locking and copying the entire lists - // of pending and needed ACKs for every client every time some method wants information about - // this connection is a recipe for poor performance - ClientInfo info = new ClientInfo(); - info.pendingAcks = new Dictionary(); - info.needAck = new Dictionary(); - - info.resendThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate; - info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; - info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; - info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; - info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; - info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; - info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; - info.totalThrottle = (int)m_throttleCategory.DripRate; - - return info; - } - - /// - /// Modifies the UDP throttles - /// - /// New throttling values - public void SetClientInfo(ClientInfo info) - { - // TODO: Allowing throttles to be manually set from this function seems like a reasonable - // idea. On the other hand, letting external code manipulate our ACK accounting is not - // going to happen - throw new NotImplementedException(); - } - - /// - /// Return statistics information about client packet queues. - /// - /// - /// FIXME: This should really be done in a more sensible manner rather than sending back a formatted string. - /// - /// - public string GetStats() - { - return string.Format( - "{0,7} {1,7} {2,7} {3,9} {4,7} {5,7} {6,7} {7,7} {8,7} {9,8} {10,7} {11,7}", - PacketsReceived, - PacketsSent, - PacketsResent, - UnackedBytes, - m_packetOutboxes[(int)ThrottleOutPacketType.Resend].Count, - m_packetOutboxes[(int)ThrottleOutPacketType.Land].Count, - m_packetOutboxes[(int)ThrottleOutPacketType.Wind].Count, - m_packetOutboxes[(int)ThrottleOutPacketType.Cloud].Count, - m_packetOutboxes[(int)ThrottleOutPacketType.Task].Count, - m_packetOutboxes[(int)ThrottleOutPacketType.Texture].Count, - m_packetOutboxes[(int)ThrottleOutPacketType.Asset].Count, - m_packetOutboxes[(int)ThrottleOutPacketType.State].Count); - } - - public void SendPacketStats() - { - PacketStats callback = OnPacketStats; - if (callback != null) - { - int newPacketsReceived = PacketsReceived - m_packetsReceivedReported; - int newPacketsSent = PacketsSent - m_packetsSentReported; - - callback(newPacketsReceived, newPacketsSent, UnackedBytes); - - m_packetsReceivedReported += newPacketsReceived; - m_packetsSentReported += newPacketsSent; - } - } - - public void SetThrottles(byte[] throttleData) - { - byte[] adjData; - int pos = 0; - - if (!BitConverter.IsLittleEndian) - { - byte[] newData = new byte[7 * 4]; - Buffer.BlockCopy(throttleData, 0, newData, 0, 7 * 4); - - for (int i = 0; i < 7; i++) - Array.Reverse(newData, i * 4, 4); - - adjData = newData; - } - else - { - adjData = throttleData; - } - - // 0.125f converts from bits to bytes - int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; - int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; - int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; - int cloud = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; - int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; - int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; - int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); - // State is a subcategory of task that we allocate a percentage to - int state = 0; - - // Make sure none of the throttles are set below our packet MTU, - // otherwise a throttle could become permanently clogged - resend = Math.Max(resend, LLUDPServer.MTU); - land = Math.Max(land, LLUDPServer.MTU); - wind = Math.Max(wind, LLUDPServer.MTU); - cloud = Math.Max(cloud, LLUDPServer.MTU); - task = Math.Max(task, LLUDPServer.MTU); - texture = Math.Max(texture, LLUDPServer.MTU); - asset = Math.Max(asset, LLUDPServer.MTU); - - //int total = resend + land + wind + cloud + task + texture + asset; - //m_log.DebugFormat("[LLUDPCLIENT]: {0} is setting throttles. Resend={1}, Land={2}, Wind={3}, Cloud={4}, Task={5}, Texture={6}, Asset={7}, Total={8}", - // AgentID, resend, land, wind, cloud, task, texture, asset, total); - - // Update the token buckets with new throttle values - TokenBucket bucket; - - bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend]; - bucket.RequestedDripRate = resend; - - bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land]; - bucket.RequestedDripRate = land; - - bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind]; - bucket.RequestedDripRate = wind; - - bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud]; - bucket.RequestedDripRate = cloud; - - bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset]; - bucket.RequestedDripRate = asset; - - bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task]; - bucket.RequestedDripRate = task; - - bucket = m_throttleCategories[(int)ThrottleOutPacketType.State]; - bucket.RequestedDripRate = state; - - bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture]; - bucket.RequestedDripRate = texture; - - // Reset the packed throttles cached data - m_packedThrottles = null; - } - - public byte[] GetThrottlesPacked(float multiplier) - { - byte[] data = m_packedThrottles; - - if (data == null) - { - float rate; - - data = new byte[7 * 4]; - int i = 0; - - // multiply by 8 to convert bytes back to bits - rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].RequestedDripRate * 8 * multiplier; - Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; - - rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Land].RequestedDripRate * 8 * multiplier; - Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; - - rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].RequestedDripRate * 8 * multiplier; - Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; - - rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].RequestedDripRate * 8 * multiplier; - Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; - - rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Task].RequestedDripRate * 8 * multiplier; - Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; - - rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].RequestedDripRate * 8 * multiplier; - Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; - - rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].RequestedDripRate * 8 * multiplier; - Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; - - m_packedThrottles = data; - } - - return data; - } - - /// - /// Queue an outgoing packet if appropriate. - /// - /// - /// Always queue the packet if at all possible. - /// - /// true if the packet has been queued, - /// false if the packet has not been queued and should be sent immediately. - /// - public bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue) - { - int category = (int)packet.Category; - - if (category >= 0 && category < m_packetOutboxes.Length) - { - OpenSim.Framework.LocklessQueue queue = m_packetOutboxes[category]; - TokenBucket bucket = m_throttleCategories[category]; - - // Don't send this packet if there is already a packet waiting in the queue - // even if we have the tokens to send it, tokens should go to the already - // queued packets - if (queue.Count > 0) - { - queue.Enqueue(packet); - return true; - } - - - if (!forceQueue && bucket.RemoveTokens(packet.Buffer.DataLength)) - { - // Enough tokens were removed from the bucket, the packet will not be queued - return false; - } - else - { - // Force queue specified or not enough tokens in the bucket, queue this packet - queue.Enqueue(packet); - return true; - } - } - else - { - // We don't have a token bucket for this category, so it will not be queued - return false; - } - } - - /// - /// Loops through all of the packet queues for this client and tries to send - /// an outgoing packet from each, obeying the throttling bucket limits - /// - /// - /// - /// Packet queues are inspected in ascending numerical order starting from 0. Therefore, queues with a lower - /// ThrottleOutPacketType number will see their packet get sent first (e.g. if both Land and Wind queues have - /// packets, then the packet at the front of the Land queue will be sent before the packet at the front of the - /// wind queue). - /// - /// This function is only called from a synchronous loop in the - /// UDPServer so we don't need to bother making this thread safe - /// - /// - /// True if any packets were sent, otherwise false - public bool DequeueOutgoing() - { - OutgoingPacket packet; - OpenSim.Framework.LocklessQueue queue; - TokenBucket bucket; - bool packetSent = false; - ThrottleOutPacketTypeFlags emptyCategories = 0; - - //string queueDebugOutput = String.Empty; // Serious debug business - - for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) - { - bucket = m_throttleCategories[i]; - //queueDebugOutput += m_packetOutboxes[i].Count + " "; // Serious debug business - - if (m_nextPackets[i] != null) - { - // This bucket was empty the last time we tried to send a packet, - // leaving a dequeued packet still waiting to be sent out. Try to - // send it again - OutgoingPacket nextPacket = m_nextPackets[i]; - if (bucket.RemoveTokens(nextPacket.Buffer.DataLength)) - { - // Send the packet - m_udpServer.SendPacketFinal(nextPacket); - m_nextPackets[i] = null; - packetSent = true; - } - } - else - { - // No dequeued packet waiting to be sent, try to pull one off - // this queue - queue = m_packetOutboxes[i]; - if (queue.Dequeue(out packet)) - { - // A packet was pulled off the queue. See if we have - // enough tokens in the bucket to send it out - if (bucket.RemoveTokens(packet.Buffer.DataLength)) - { - // Send the packet - m_udpServer.SendPacketFinal(packet); - packetSent = true; - } - else - { - // Save the dequeued packet for the next iteration - m_nextPackets[i] = packet; - } - - // If the queue is empty after this dequeue, fire the queue - // empty callback now so it has a chance to fill before we - // get back here - if (queue.Count == 0) - emptyCategories |= CategoryToFlag(i); - } - else - { - // No packets in this queue. Fire the queue empty callback - // if it has not been called recently - emptyCategories |= CategoryToFlag(i); - } - } - } - - if (emptyCategories != 0) - BeginFireQueueEmpty(emptyCategories); - - //m_log.Info("[LLUDPCLIENT]: Queues: " + queueDebugOutput); // Serious debug business - return packetSent; - } - - /// - /// Called when an ACK packet is received and a round-trip time for a - /// packet is calculated. This is used to calculate the smoothed - /// round-trip time, round trip time variance, and finally the - /// retransmission timeout - /// - /// Round-trip time of a single packet and its - /// acknowledgement - public void UpdateRoundTrip(float r) - { - const float ALPHA = 0.125f; - const float BETA = 0.25f; - const float K = 4.0f; - - if (RTTVAR == 0.0f) - { - // First RTT measurement - SRTT = r; - RTTVAR = r * 0.5f; - } - else - { - // Subsequence RTT measurement - RTTVAR = (1.0f - BETA) * RTTVAR + BETA * Math.Abs(SRTT - r); - SRTT = (1.0f - ALPHA) * SRTT + ALPHA * r; - } - - int rto = (int)(SRTT + Math.Max(m_udpServer.TickCountResolution, K * RTTVAR)); - - // Clamp the retransmission timeout to manageable values - rto = Utils.Clamp(rto, m_defaultRTO, m_maxRTO); - - RTO = rto; - - //m_log.Debug("[LLUDPCLIENT]: Setting agent " + this.Agent.FullName + "'s RTO to " + RTO + "ms with an RTTVAR of " + - // RTTVAR + " based on new RTT of " + r + "ms"); - } - - /// - /// Exponential backoff of the retransmission timeout, per section 5.5 - /// of RFC 2988 - /// - public void BackoffRTO() - { - // Reset SRTT and RTTVAR, we assume they are bogus since things - // didn't work out and we're backing off the timeout - SRTT = 0.0f; - RTTVAR = 0.0f; - - // Double the retransmission timeout - RTO = Math.Min(RTO * 2, m_maxRTO); - } - - /// - /// Does an early check to see if this queue empty callback is already - /// running, then asynchronously firing the event - /// - /// Throttle category to fire the callback - /// for - private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories) - { - if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty) - { - // Use a value of 0 to signal that FireQueueEmpty is running - m_nextOnQueueEmpty = 0; - // Asynchronously run the callback - Util.FireAndForget(FireQueueEmpty, categories); - } - } - - /// - /// Fires the OnQueueEmpty callback and sets the minimum time that it - /// can be called again - /// - /// Throttle categories to fire the callback for, - /// stored as an object to match the WaitCallback delegate - /// signature - private void FireQueueEmpty(object o) - { - const int MIN_CALLBACK_MS = 30; - - ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o; - QueueEmpty callback = OnQueueEmpty; - - int start = Environment.TickCount & Int32.MaxValue; - - if (callback != null) - { - try { callback(categories); } - catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); } - } - - m_nextOnQueueEmpty = start + MIN_CALLBACK_MS; - if (m_nextOnQueueEmpty == 0) - m_nextOnQueueEmpty = 1; - } - - /// - /// Converts a integer to a - /// flag value - /// - /// Throttle category to convert - /// Flag representation of the throttle category - private static ThrottleOutPacketTypeFlags CategoryToFlag(int i) - { - ThrottleOutPacketType category = (ThrottleOutPacketType)i; - - /* - * Land = 1, - /// Wind data - Wind = 2, - /// Cloud data - Cloud = 3, - /// Any packets that do not fit into the other throttles - Task = 4, - /// Texture assets - Texture = 5, - /// Non-texture assets - Asset = 6, - /// Avatar and primitive data - /// This is a sub-category of Task - State = 7, - */ - - switch (category) - { - case ThrottleOutPacketType.Land: - return ThrottleOutPacketTypeFlags.Land; - case ThrottleOutPacketType.Wind: - return ThrottleOutPacketTypeFlags.Wind; - case ThrottleOutPacketType.Cloud: - return ThrottleOutPacketTypeFlags.Cloud; - case ThrottleOutPacketType.Task: - return ThrottleOutPacketTypeFlags.Task; - case ThrottleOutPacketType.Texture: - return ThrottleOutPacketTypeFlags.Texture; - case ThrottleOutPacketType.Asset: - return ThrottleOutPacketTypeFlags.Asset; - case ThrottleOutPacketType.State: - return ThrottleOutPacketTypeFlags.State; - default: - return 0; - } - } - } -} -- cgit v1.1