Merge branch 'master' into vehicles
						commit
						f6b8bac0fa
					
				| 
						 | 
				
			
			@ -89,7 +89,6 @@ namespace OpenSim.Client.MXP.PacketHandler
 | 
			
		|||
            m_clientThread.Name = "MXPThread";
 | 
			
		||||
            m_clientThread.IsBackground = true;
 | 
			
		||||
            m_clientThread.Start();
 | 
			
		||||
            ThreadTracker.Add(m_clientThread);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void StartListener()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -239,10 +239,8 @@ namespace OpenSim.Data.MySQL
 | 
			
		|||
                }
 | 
			
		||||
                catch (Exception e)
 | 
			
		||||
                {
 | 
			
		||||
                    m_log.ErrorFormat(
 | 
			
		||||
                        "[ASSETS DB]: " +
 | 
			
		||||
                        "MySql failure creating asset {0} with name {1}" + Environment.NewLine + e.ToString()
 | 
			
		||||
                        + Environment.NewLine + "Attempting reconnection", asset.FullID, asset.Name);
 | 
			
		||||
                    m_log.ErrorFormat("[ASSET DB]: MySQL failure creating asset {0} with name \"{1}\". Attempting reconnect. Error: {2}",
 | 
			
		||||
                        asset.FullID, asset.Name, e.Message);
 | 
			
		||||
                    _dbConnection.Reconnect();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -124,9 +124,11 @@ namespace OpenSim.Framework.Communications.Clients
 | 
			
		|||
            // Let's wait for the response
 | 
			
		||||
            //m_log.Info("[REST COMMS]: Waiting for a reply after DoCreateChildAgentCall");
 | 
			
		||||
 | 
			
		||||
            WebResponse webResponse = null;
 | 
			
		||||
            StreamReader sr = null;
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                WebResponse webResponse = AgentCreateRequest.GetResponse();
 | 
			
		||||
                webResponse = AgentCreateRequest.GetResponse();
 | 
			
		||||
                if (webResponse == null)
 | 
			
		||||
                {
 | 
			
		||||
                    m_log.Info("[REST COMMS]: Null reply on DoCreateChildAgentCall post");
 | 
			
		||||
| 
						 | 
				
			
			@ -134,11 +136,10 @@ namespace OpenSim.Framework.Communications.Clients
 | 
			
		|||
                else
 | 
			
		||||
                {
 | 
			
		||||
 | 
			
		||||
                    StreamReader sr = new StreamReader(webResponse.GetResponseStream());
 | 
			
		||||
                    sr = new StreamReader(webResponse.GetResponseStream());
 | 
			
		||||
                    string response = sr.ReadToEnd().Trim();
 | 
			
		||||
                    sr.Close();
 | 
			
		||||
                    m_log.InfoFormat("[REST COMMS]: DoCreateChildAgentCall reply was {0} ", response);
 | 
			
		||||
                
 | 
			
		||||
 | 
			
		||||
                    if (!String.IsNullOrEmpty(response))
 | 
			
		||||
                    {
 | 
			
		||||
                        try
 | 
			
		||||
| 
						 | 
				
			
			@ -167,6 +168,11 @@ namespace OpenSim.Framework.Communications.Clients
 | 
			
		|||
                m_log.InfoFormat("[REST COMMS]: exception on reply of DoCreateChildAgentCall {0}", ex.Message);
 | 
			
		||||
                // ignore, really
 | 
			
		||||
            }
 | 
			
		||||
            finally
 | 
			
		||||
            {
 | 
			
		||||
                if (sr != null)
 | 
			
		||||
                    sr.Close();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -246,15 +252,17 @@ namespace OpenSim.Framework.Communications.Clients
 | 
			
		|||
            // Let's wait for the response
 | 
			
		||||
            //m_log.Info("[REST COMMS]: Waiting for a reply after ChildAgentUpdate");
 | 
			
		||||
 | 
			
		||||
            WebResponse webResponse = null;
 | 
			
		||||
            StreamReader sr = null;
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                WebResponse webResponse = ChildUpdateRequest.GetResponse();
 | 
			
		||||
                webResponse = ChildUpdateRequest.GetResponse();
 | 
			
		||||
                if (webResponse == null)
 | 
			
		||||
                {
 | 
			
		||||
                    m_log.Info("[REST COMMS]: Null reply on ChilAgentUpdate post");
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                StreamReader sr = new StreamReader(webResponse.GetResponseStream());
 | 
			
		||||
                sr = new StreamReader(webResponse.GetResponseStream());
 | 
			
		||||
                //reply = sr.ReadToEnd().Trim();
 | 
			
		||||
                sr.ReadToEnd().Trim();
 | 
			
		||||
                sr.Close();
 | 
			
		||||
| 
						 | 
				
			
			@ -266,6 +274,11 @@ namespace OpenSim.Framework.Communications.Clients
 | 
			
		|||
                m_log.InfoFormat("[REST COMMS]: exception on reply of ChilAgentUpdate {0}", ex.Message);
 | 
			
		||||
                // ignore, really
 | 
			
		||||
            }
 | 
			
		||||
            finally
 | 
			
		||||
            {
 | 
			
		||||
                if (sr != null)
 | 
			
		||||
                    sr.Close();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -284,6 +297,7 @@ namespace OpenSim.Framework.Communications.Clients
 | 
			
		|||
 | 
			
		||||
            HttpWebResponse webResponse = null;
 | 
			
		||||
            string reply = string.Empty;
 | 
			
		||||
            StreamReader sr = null;
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                webResponse = (HttpWebResponse)request.GetResponse();
 | 
			
		||||
| 
						 | 
				
			
			@ -292,9 +306,8 @@ namespace OpenSim.Framework.Communications.Clients
 | 
			
		|||
                    m_log.Info("[REST COMMS]: Null reply on agent get ");
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                StreamReader sr = new StreamReader(webResponse.GetResponseStream());
 | 
			
		||||
                sr = new StreamReader(webResponse.GetResponseStream());
 | 
			
		||||
                reply = sr.ReadToEnd().Trim();
 | 
			
		||||
                sr.Close();
 | 
			
		||||
 | 
			
		||||
                //Console.WriteLine("[REST COMMS]: ChilAgentUpdate reply was " + reply);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -305,6 +318,11 @@ namespace OpenSim.Framework.Communications.Clients
 | 
			
		|||
                // ignore, really
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            finally
 | 
			
		||||
            {
 | 
			
		||||
                if (sr != null)
 | 
			
		||||
                    sr.Close();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (webResponse.StatusCode == HttpStatusCode.OK)
 | 
			
		||||
            {
 | 
			
		||||
| 
						 | 
				
			
			@ -333,6 +351,7 @@ namespace OpenSim.Framework.Communications.Clients
 | 
			
		|||
            request.Method = "DELETE";
 | 
			
		||||
            request.Timeout = 10000;
 | 
			
		||||
 | 
			
		||||
            StreamReader sr = null;
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                WebResponse webResponse = request.GetResponse();
 | 
			
		||||
| 
						 | 
				
			
			@ -341,7 +360,7 @@ namespace OpenSim.Framework.Communications.Clients
 | 
			
		|||
                    m_log.Info("[REST COMMS]: Null reply on agent delete ");
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                StreamReader sr = new StreamReader(webResponse.GetResponseStream());
 | 
			
		||||
                sr = new StreamReader(webResponse.GetResponseStream());
 | 
			
		||||
                //reply = sr.ReadToEnd().Trim();
 | 
			
		||||
                sr.ReadToEnd().Trim();
 | 
			
		||||
                sr.Close();
 | 
			
		||||
| 
						 | 
				
			
			@ -353,6 +372,11 @@ namespace OpenSim.Framework.Communications.Clients
 | 
			
		|||
                m_log.InfoFormat("[REST COMMS]: exception on reply of agent delete {0}", ex.Message);
 | 
			
		||||
                // ignore, really
 | 
			
		||||
            }
 | 
			
		||||
            finally
 | 
			
		||||
            {
 | 
			
		||||
                if (sr != null)
 | 
			
		||||
                    sr.Close();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -377,6 +401,7 @@ namespace OpenSim.Framework.Communications.Clients
 | 
			
		|||
            request.Method = "DELETE";
 | 
			
		||||
            request.Timeout = 10000;
 | 
			
		||||
 | 
			
		||||
            StreamReader sr = null;
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                WebResponse webResponse = request.GetResponse();
 | 
			
		||||
| 
						 | 
				
			
			@ -385,7 +410,7 @@ namespace OpenSim.Framework.Communications.Clients
 | 
			
		|||
                    m_log.Info("[REST COMMS]: Null reply on agent delete ");
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                StreamReader sr = new StreamReader(webResponse.GetResponseStream());
 | 
			
		||||
                sr = new StreamReader(webResponse.GetResponseStream());
 | 
			
		||||
                //reply = sr.ReadToEnd().Trim();
 | 
			
		||||
                sr.ReadToEnd().Trim();
 | 
			
		||||
                sr.Close();
 | 
			
		||||
| 
						 | 
				
			
			@ -397,6 +422,11 @@ namespace OpenSim.Framework.Communications.Clients
 | 
			
		|||
                m_log.InfoFormat("[REST COMMS]: exception on reply of agent delete {0}", ex.Message);
 | 
			
		||||
                // ignore, really
 | 
			
		||||
            }
 | 
			
		||||
            finally
 | 
			
		||||
            {
 | 
			
		||||
                if (sr != null)
 | 
			
		||||
                    sr.Close();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -463,6 +493,7 @@ namespace OpenSim.Framework.Communications.Clients
 | 
			
		|||
            // Let's wait for the response
 | 
			
		||||
            //m_log.Info("[REST COMMS]: Waiting for a reply after DoCreateChildAgentCall");
 | 
			
		||||
 | 
			
		||||
            StreamReader sr = null;
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                WebResponse webResponse = ObjectCreateRequest.GetResponse();
 | 
			
		||||
| 
						 | 
				
			
			@ -471,10 +502,9 @@ namespace OpenSim.Framework.Communications.Clients
 | 
			
		|||
                    m_log.Info("[REST COMMS]: Null reply on DoCreateObjectCall post");
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                StreamReader sr = new StreamReader(webResponse.GetResponseStream());
 | 
			
		||||
                sr = new StreamReader(webResponse.GetResponseStream());
 | 
			
		||||
                //reply = sr.ReadToEnd().Trim();
 | 
			
		||||
                sr.ReadToEnd().Trim();
 | 
			
		||||
                sr.Close();
 | 
			
		||||
                //m_log.InfoFormat("[REST COMMS]: DoCreateChildAgentCall reply was {0} ", reply);
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -483,6 +513,11 @@ namespace OpenSim.Framework.Communications.Clients
 | 
			
		|||
                m_log.InfoFormat("[REST COMMS]: exception on reply of DoCreateObjectCall {0}", ex.Message);
 | 
			
		||||
                // ignore, really
 | 
			
		||||
            }
 | 
			
		||||
            finally
 | 
			
		||||
            {
 | 
			
		||||
                if (sr != null)
 | 
			
		||||
                    sr.Close();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -542,6 +577,7 @@ namespace OpenSim.Framework.Communications.Clients
 | 
			
		|||
            // Let's wait for the response
 | 
			
		||||
            //m_log.Info("[REST COMMS]: Waiting for a reply after DoCreateChildAgentCall");
 | 
			
		||||
 | 
			
		||||
            StreamReader sr = null;
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                WebResponse webResponse = ObjectCreateRequest.GetResponse();
 | 
			
		||||
| 
						 | 
				
			
			@ -550,11 +586,10 @@ namespace OpenSim.Framework.Communications.Clients
 | 
			
		|||
                    m_log.Info("[REST COMMS]: Null reply on DoCreateObjectCall post");
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                StreamReader sr = new StreamReader(webResponse.GetResponseStream());
 | 
			
		||||
                sr = new StreamReader(webResponse.GetResponseStream());
 | 
			
		||||
                sr.ReadToEnd().Trim();
 | 
			
		||||
                sr.ReadToEnd().Trim();
 | 
			
		||||
                sr.Close();
 | 
			
		||||
                
 | 
			
		||||
 | 
			
		||||
                //m_log.InfoFormat("[REST COMMS]: DoCreateChildAgentCall reply was {0} ", reply);
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -563,6 +598,11 @@ namespace OpenSim.Framework.Communications.Clients
 | 
			
		|||
                m_log.InfoFormat("[REST COMMS]: exception on reply of DoCreateObjectCall {0}", ex.Message);
 | 
			
		||||
                // ignore, really
 | 
			
		||||
            }
 | 
			
		||||
            finally
 | 
			
		||||
            {
 | 
			
		||||
                if (sr != null)
 | 
			
		||||
                    sr.Close();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -630,6 +670,7 @@ namespace OpenSim.Framework.Communications.Clients
 | 
			
		|||
            // Let's wait for the response
 | 
			
		||||
            //m_log.Info("[REST COMMS]: Waiting for a reply after DoHelloNeighbourCall");
 | 
			
		||||
 | 
			
		||||
            StreamReader sr = null;
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                WebResponse webResponse = HelloNeighbourRequest.GetResponse();
 | 
			
		||||
| 
						 | 
				
			
			@ -638,10 +679,9 @@ namespace OpenSim.Framework.Communications.Clients
 | 
			
		|||
                    m_log.Info("[REST COMMS]: Null reply on DoHelloNeighbourCall post");
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                StreamReader sr = new StreamReader(webResponse.GetResponseStream());
 | 
			
		||||
                sr = new StreamReader(webResponse.GetResponseStream());
 | 
			
		||||
                //reply = sr.ReadToEnd().Trim();
 | 
			
		||||
                sr.ReadToEnd().Trim();
 | 
			
		||||
                sr.Close();
 | 
			
		||||
                //m_log.InfoFormat("[REST COMMS]: DoHelloNeighbourCall reply was {0} ", reply);
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -650,6 +690,11 @@ namespace OpenSim.Framework.Communications.Clients
 | 
			
		|||
                m_log.InfoFormat("[REST COMMS]: exception on reply of DoHelloNeighbourCall {0}", ex.Message);
 | 
			
		||||
                // ignore, really
 | 
			
		||||
            }
 | 
			
		||||
            finally
 | 
			
		||||
            {
 | 
			
		||||
                if (sr != null)
 | 
			
		||||
                    sr.Close();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,207 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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.Threading;
 | 
			
		||||
 | 
			
		||||
namespace OpenSim.Framework
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Provides helper methods for parallelizing loops
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public static class Parallel
 | 
			
		||||
    {
 | 
			
		||||
        private static readonly int processorCount = System.Environment.ProcessorCount;
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Executes a for loop in which iterations may run in parallel
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="fromInclusive">The loop will be started at this index</param>
 | 
			
		||||
        /// <param name="toExclusive">The loop will be terminated before this index is reached</param>
 | 
			
		||||
        /// <param name="body">Method body to run for each iteration of the loop</param>
 | 
			
		||||
        public static void For(int fromInclusive, int toExclusive, Action<int> body)
 | 
			
		||||
        {
 | 
			
		||||
            For(processorCount, fromInclusive, toExclusive, body);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Executes a for loop in which iterations may run in parallel
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="threadCount">The number of concurrent execution threads to run</param>
 | 
			
		||||
        /// <param name="fromInclusive">The loop will be started at this index</param>
 | 
			
		||||
        /// <param name="toExclusive">The loop will be terminated before this index is reached</param>
 | 
			
		||||
        /// <param name="body">Method body to run for each iteration of the loop</param>
 | 
			
		||||
        public static void For(int threadCount, int fromInclusive, int toExclusive, Action<int> body)
 | 
			
		||||
        {
 | 
			
		||||
            int counter = threadCount;
 | 
			
		||||
            AutoResetEvent threadFinishEvent = new AutoResetEvent(false);
 | 
			
		||||
            Exception exception = null;
 | 
			
		||||
 | 
			
		||||
            --fromInclusive;
 | 
			
		||||
 | 
			
		||||
            for (int i = 0; i < threadCount; i++)
 | 
			
		||||
            {
 | 
			
		||||
                ThreadPool.QueueUserWorkItem(
 | 
			
		||||
                    delegate(object o)
 | 
			
		||||
                    {
 | 
			
		||||
                        int threadIndex = (int)o;
 | 
			
		||||
 | 
			
		||||
                        while (exception == null)
 | 
			
		||||
                        {
 | 
			
		||||
                            int currentIndex = Interlocked.Increment(ref fromInclusive);
 | 
			
		||||
 | 
			
		||||
                            if (currentIndex >= toExclusive)
 | 
			
		||||
                                break;
 | 
			
		||||
 | 
			
		||||
                            try { body(currentIndex); }
 | 
			
		||||
                            catch (Exception ex) { exception = ex; break; }
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        if (Interlocked.Decrement(ref counter) == 0)
 | 
			
		||||
                            threadFinishEvent.Set();
 | 
			
		||||
                    }, i
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            threadFinishEvent.WaitOne();
 | 
			
		||||
 | 
			
		||||
            if (exception != null)
 | 
			
		||||
                throw new Exception(exception.Message, exception);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Executes a foreach loop in which iterations may run in parallel
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <typeparam name="T">Object type that the collection wraps</typeparam>
 | 
			
		||||
        /// <param name="enumerable">An enumerable collection to iterate over</param>
 | 
			
		||||
        /// <param name="body">Method body to run for each object in the collection</param>
 | 
			
		||||
        public static void ForEach<T>(IEnumerable<T> enumerable, Action<T> body)
 | 
			
		||||
        {
 | 
			
		||||
            ForEach<T>(processorCount, enumerable, body);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Executes a foreach loop in which iterations may run in parallel
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <typeparam name="T">Object type that the collection wraps</typeparam>
 | 
			
		||||
        /// <param name="threadCount">The number of concurrent execution threads to run</param>
 | 
			
		||||
        /// <param name="enumerable">An enumerable collection to iterate over</param>
 | 
			
		||||
        /// <param name="body">Method body to run for each object in the collection</param>
 | 
			
		||||
        public static void ForEach<T>(int threadCount, IEnumerable<T> enumerable, Action<T> body)
 | 
			
		||||
        {
 | 
			
		||||
            int counter = threadCount;
 | 
			
		||||
            AutoResetEvent threadFinishEvent = new AutoResetEvent(false);
 | 
			
		||||
            IEnumerator<T> enumerator = enumerable.GetEnumerator();
 | 
			
		||||
            Exception exception = null;
 | 
			
		||||
 | 
			
		||||
            for (int i = 0; i < threadCount; i++)
 | 
			
		||||
            {
 | 
			
		||||
                ThreadPool.QueueUserWorkItem(
 | 
			
		||||
                    delegate(object o)
 | 
			
		||||
                    {
 | 
			
		||||
                        int threadIndex = (int)o;
 | 
			
		||||
 | 
			
		||||
                        while (exception == null)
 | 
			
		||||
                        {
 | 
			
		||||
                            T entry;
 | 
			
		||||
 | 
			
		||||
                            lock (enumerator)
 | 
			
		||||
                            {
 | 
			
		||||
                                if (!enumerator.MoveNext())
 | 
			
		||||
                                    break;
 | 
			
		||||
                                entry = (T)enumerator.Current; // Explicit typecast for Mono's sake
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            try { body(entry); }
 | 
			
		||||
                            catch (Exception ex) { exception = ex; break; }
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        if (Interlocked.Decrement(ref counter) == 0)
 | 
			
		||||
                            threadFinishEvent.Set();
 | 
			
		||||
                    }, i
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            threadFinishEvent.WaitOne();
 | 
			
		||||
 | 
			
		||||
            if (exception != null)
 | 
			
		||||
                throw new Exception(exception.Message, exception);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Executes a series of tasks in parallel
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="actions">A series of method bodies to execute</param>
 | 
			
		||||
        public static void Invoke(params Action[] actions)
 | 
			
		||||
        {
 | 
			
		||||
            Invoke(processorCount, actions);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Executes a series of tasks in parallel
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="threadCount">The number of concurrent execution threads to run</param>
 | 
			
		||||
        /// <param name="actions">A series of method bodies to execute</param>
 | 
			
		||||
        public static void Invoke(int threadCount, params Action[] actions)
 | 
			
		||||
        {
 | 
			
		||||
            int counter = threadCount;
 | 
			
		||||
            AutoResetEvent threadFinishEvent = new AutoResetEvent(false);
 | 
			
		||||
            int index = -1;
 | 
			
		||||
            Exception exception = null;
 | 
			
		||||
 | 
			
		||||
            for (int i = 0; i < threadCount; i++)
 | 
			
		||||
            {
 | 
			
		||||
                ThreadPool.QueueUserWorkItem(
 | 
			
		||||
                    delegate(object o)
 | 
			
		||||
                    {
 | 
			
		||||
                        int threadIndex = (int)o;
 | 
			
		||||
 | 
			
		||||
                        while (exception == null)
 | 
			
		||||
                        {
 | 
			
		||||
                            int currentIndex = Interlocked.Increment(ref index);
 | 
			
		||||
 | 
			
		||||
                            if (currentIndex >= actions.Length)
 | 
			
		||||
                                break;
 | 
			
		||||
 | 
			
		||||
                            try { actions[currentIndex](); }
 | 
			
		||||
                            catch (Exception ex) { exception = ex; break; }
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        if (Interlocked.Decrement(ref counter) == 0)
 | 
			
		||||
                            threadFinishEvent.Set();
 | 
			
		||||
                    }, i
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            threadFinishEvent.WaitOne();
 | 
			
		||||
 | 
			
		||||
            if (exception != null)
 | 
			
		||||
                throw new Exception(exception.Message, exception);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -27,6 +27,7 @@
 | 
			
		|||
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using System.Text;
 | 
			
		||||
| 
						 | 
				
			
			@ -109,9 +110,8 @@ namespace OpenSim.Framework.Servers
 | 
			
		|||
            m_periodicDiagnosticsTimer.Elapsed += new ElapsedEventHandler(LogDiagnostics);
 | 
			
		||||
            m_periodicDiagnosticsTimer.Enabled = true;
 | 
			
		||||
 | 
			
		||||
            // Add ourselves to thread monitoring.  This thread will go on to become the console listening thread
 | 
			
		||||
            // This thread will go on to become the console listening thread
 | 
			
		||||
            Thread.CurrentThread.Name = "ConsoleThread";
 | 
			
		||||
            ThreadTracker.Add(Thread.CurrentThread);
 | 
			
		||||
 | 
			
		||||
            ILoggerRepository repository = LogManager.GetRepository();
 | 
			
		||||
            IAppender[] appenders = repository.GetAppenders();
 | 
			
		||||
| 
						 | 
				
			
			@ -235,7 +235,7 @@ namespace OpenSim.Framework.Servers
 | 
			
		|||
        {
 | 
			
		||||
            StringBuilder sb = new StringBuilder();
 | 
			
		||||
 | 
			
		||||
            List<Thread> threads = ThreadTracker.GetThreads();
 | 
			
		||||
            ProcessThreadCollection threads = ThreadTracker.GetThreads();
 | 
			
		||||
            if (threads == null)
 | 
			
		||||
            {
 | 
			
		||||
                sb.Append("OpenSim thread tracking is only enabled in DEBUG mode.");
 | 
			
		||||
| 
						 | 
				
			
			@ -243,25 +243,15 @@ namespace OpenSim.Framework.Servers
 | 
			
		|||
            else
 | 
			
		||||
            {
 | 
			
		||||
                sb.Append(threads.Count + " threads are being tracked:" + Environment.NewLine);
 | 
			
		||||
                foreach (Thread t in threads)
 | 
			
		||||
                foreach (ProcessThread t in threads)
 | 
			
		||||
                {
 | 
			
		||||
                    if (t.IsAlive)
 | 
			
		||||
                    {
 | 
			
		||||
                        sb.Append(
 | 
			
		||||
                            "ID: " + t.ManagedThreadId + ", Name: " + t.Name + ", Alive: " + t.IsAlive
 | 
			
		||||
                            + ", Pri: " + t.Priority + ", State: " + t.ThreadState + Environment.NewLine);
 | 
			
		||||
                    }
 | 
			
		||||
                    sb.Append("ID: " + t.Id + ", TotalProcessorTime: " + t.TotalProcessorTime + ", TimeRunning: " +
 | 
			
		||||
                        (DateTime.Now - t.StartTime) + ", Pri: " + t.CurrentPriority + ", State: " + t.ThreadState );
 | 
			
		||||
                    if (t.ThreadState == System.Diagnostics.ThreadState.Wait)
 | 
			
		||||
                        sb.Append(", Reason: " + t.WaitReason + Environment.NewLine);
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        try
 | 
			
		||||
                        {
 | 
			
		||||
                            sb.Append("ID: " + t.ManagedThreadId + ", Name: " + t.Name + ", DEAD" + Environment.NewLine);
 | 
			
		||||
                        }
 | 
			
		||||
                        catch
 | 
			
		||||
                        {
 | 
			
		||||
                            sb.Append("THREAD ERROR" + Environment.NewLine);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                        sb.Append(Environment.NewLine);
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            int workers = 0, ports = 0, maxWorkers = 0, maxPorts = 0;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,192 +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 NUnit.Framework;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace OpenSim.Framework.Tests
 | 
			
		||||
{
 | 
			
		||||
    [TestFixture]
 | 
			
		||||
    public class ThreadTrackerTests
 | 
			
		||||
    {
 | 
			
		||||
        private bool running = true;
 | 
			
		||||
        private bool running2 = true;
 | 
			
		||||
 | 
			
		||||
        [Test]
 | 
			
		||||
        public void DefaultThreadTrackerTest()
 | 
			
		||||
        {
 | 
			
		||||
            List<Thread> lThread = ThreadTracker.GetThreads();
 | 
			
		||||
            
 | 
			
		||||
            /*
 | 
			
		||||
            foreach (Thread t in lThread)
 | 
			
		||||
            {
 | 
			
		||||
                System.Console.WriteLine(t.Name);
 | 
			
		||||
            }
 | 
			
		||||
            */
 | 
			
		||||
 | 
			
		||||
            Assert.That(lThread.Count == 1);
 | 
			
		||||
            Assert.That(lThread[0].Name == "ThreadTrackerThread");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Validate that adding a thread to the thread tracker works
 | 
			
		||||
        /// Validate that removing a thread from the thread tracker also works.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        [Test]
 | 
			
		||||
        public void AddThreadToThreadTrackerTestAndRemoveTest()
 | 
			
		||||
        {
 | 
			
		||||
            Thread t = new Thread(run);
 | 
			
		||||
            t.Name = "TestThread";
 | 
			
		||||
            t.Priority = ThreadPriority.BelowNormal;
 | 
			
		||||
            t.IsBackground = true;
 | 
			
		||||
            t.SetApartmentState(ApartmentState.MTA);
 | 
			
		||||
            t.Start();
 | 
			
		||||
            ThreadTracker.Add(t);
 | 
			
		||||
 | 
			
		||||
            List<Thread> lThread = ThreadTracker.GetThreads();
 | 
			
		||||
 | 
			
		||||
            Assert.That(lThread.Count == 2);
 | 
			
		||||
 | 
			
		||||
            foreach (Thread tr in lThread)
 | 
			
		||||
            {
 | 
			
		||||
                Assert.That((tr.Name == "ThreadTrackerThread" || tr.Name == "TestThread"));
 | 
			
		||||
            }
 | 
			
		||||
            running = false;
 | 
			
		||||
            ThreadTracker.Remove(t);
 | 
			
		||||
 | 
			
		||||
            lThread = ThreadTracker.GetThreads();
 | 
			
		||||
 | 
			
		||||
            Assert.That(lThread.Count == 1);
 | 
			
		||||
 | 
			
		||||
            foreach (Thread tr in lThread)
 | 
			
		||||
            {
 | 
			
		||||
                Assert.That((tr.Name == "ThreadTrackerThread"));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Test a dead thread removal by aborting it and setting it's last seen active date to 50 seconds
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        [Test]
 | 
			
		||||
        public void DeadThreadTest()
 | 
			
		||||
        {
 | 
			
		||||
            Thread t = new Thread(run2);
 | 
			
		||||
            t.Name = "TestThread";
 | 
			
		||||
            t.Priority = ThreadPriority.BelowNormal;
 | 
			
		||||
            t.IsBackground = true;
 | 
			
		||||
            t.SetApartmentState(ApartmentState.MTA);
 | 
			
		||||
            t.Start();
 | 
			
		||||
            ThreadTracker.Add(t);
 | 
			
		||||
            t.Abort();
 | 
			
		||||
            Thread.Sleep(5000);
 | 
			
		||||
            ThreadTracker.m_Threads[1].LastSeenActive = DateTime.Now.Ticks - (50*10000000);
 | 
			
		||||
            ThreadTracker.CleanUp();
 | 
			
		||||
            List<Thread> lThread = ThreadTracker.GetThreads();
 | 
			
		||||
 | 
			
		||||
            Assert.That(lThread.Count == 1);
 | 
			
		||||
 | 
			
		||||
            foreach (Thread tr in lThread)
 | 
			
		||||
            {
 | 
			
		||||
                Assert.That((tr.Name == "ThreadTrackerThread"));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Test]
 | 
			
		||||
        public void UnstartedThreadTest()
 | 
			
		||||
        {
 | 
			
		||||
            Thread t = new Thread(run2);
 | 
			
		||||
            t.Name = "TestThread";
 | 
			
		||||
            t.Priority = ThreadPriority.BelowNormal;
 | 
			
		||||
            t.IsBackground = true;
 | 
			
		||||
            t.SetApartmentState(ApartmentState.MTA);
 | 
			
		||||
            ThreadTracker.Add(t);
 | 
			
		||||
            ThreadTracker.m_Threads[1].LastSeenActive = DateTime.Now.Ticks - (50 * 10000000);
 | 
			
		||||
            ThreadTracker.CleanUp();
 | 
			
		||||
            List<Thread> lThread = ThreadTracker.GetThreads();
 | 
			
		||||
 | 
			
		||||
            Assert.That(lThread.Count == 1);
 | 
			
		||||
 | 
			
		||||
            foreach (Thread tr in lThread)
 | 
			
		||||
            {
 | 
			
		||||
                Assert.That((tr.Name == "ThreadTrackerThread"));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Test]
 | 
			
		||||
        public void NullThreadTest()
 | 
			
		||||
        {
 | 
			
		||||
            Thread t = null;
 | 
			
		||||
            ThreadTracker.Add(t);
 | 
			
		||||
            
 | 
			
		||||
            List<Thread> lThread = ThreadTracker.GetThreads();
 | 
			
		||||
 | 
			
		||||
            Assert.That(lThread.Count == 1);
 | 
			
		||||
 | 
			
		||||
            foreach (Thread tr in lThread)
 | 
			
		||||
            {
 | 
			
		||||
                Assert.That((tr.Name == "ThreadTrackerThread"));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Worker thread 0
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="o"></param>
 | 
			
		||||
        public void run(object o)
 | 
			
		||||
        {
 | 
			
		||||
            while (running)
 | 
			
		||||
            {
 | 
			
		||||
                Thread.Sleep(5000);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Worker thread 1
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="o"></param>
 | 
			
		||||
        public void run2(object o)
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                while (running2)
 | 
			
		||||
                {
 | 
			
		||||
                    Thread.Sleep(5000);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
            } 
 | 
			
		||||
            catch (ThreadAbortException)
 | 
			
		||||
            {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -26,138 +26,21 @@
 | 
			
		|||
 */
 | 
			
		||||
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
using log4net;
 | 
			
		||||
 | 
			
		||||
namespace OpenSim.Framework
 | 
			
		||||
{
 | 
			
		||||
    public static class ThreadTracker
 | 
			
		||||
    {
 | 
			
		||||
        private static readonly ILog m_log
 | 
			
		||||
            = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
 | 
			
		||||
        
 | 
			
		||||
        private static readonly long ThreadTimeout = 30 * 10000000;
 | 
			
		||||
        public static List<ThreadTrackerItem> m_Threads;
 | 
			
		||||
        public static Thread ThreadTrackerThread;
 | 
			
		||||
        private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
 | 
			
		||||
 | 
			
		||||
        static ThreadTracker()
 | 
			
		||||
        public static ProcessThreadCollection GetThreads()
 | 
			
		||||
        {
 | 
			
		||||
#if DEBUG
 | 
			
		||||
            m_Threads = new List<ThreadTrackerItem>();
 | 
			
		||||
            ThreadTrackerThread = new Thread(ThreadTrackerThreadLoop);
 | 
			
		||||
            ThreadTrackerThread.Name = "ThreadTrackerThread";
 | 
			
		||||
            ThreadTrackerThread.IsBackground = true;
 | 
			
		||||
            ThreadTrackerThread.Priority = ThreadPriority.BelowNormal;
 | 
			
		||||
            ThreadTrackerThread.Start();
 | 
			
		||||
            Add(ThreadTrackerThread);
 | 
			
		||||
#endif
 | 
			
		||||
            Process thisProc = Process.GetCurrentProcess();
 | 
			
		||||
            return thisProc.Threads;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static void ThreadTrackerThreadLoop()
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                while (true)
 | 
			
		||||
                {
 | 
			
		||||
                    Thread.Sleep(5000);
 | 
			
		||||
                    CleanUp();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception e)
 | 
			
		||||
            {
 | 
			
		||||
                m_log.ErrorFormat(
 | 
			
		||||
                    "[THREAD TRACKER]: Thread tracker cleanup thread terminating with exception.  Please report this error.  Exception is {0}", 
 | 
			
		||||
                    e);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void Add(Thread thread)
 | 
			
		||||
        {
 | 
			
		||||
#if DEBUG
 | 
			
		||||
            if (thread != null)
 | 
			
		||||
            {
 | 
			
		||||
                lock (m_Threads)
 | 
			
		||||
                {
 | 
			
		||||
                    ThreadTrackerItem tti = new ThreadTrackerItem();
 | 
			
		||||
                    tti.Thread = thread;
 | 
			
		||||
                    tti.LastSeenActive = DateTime.Now.Ticks;
 | 
			
		||||
                    m_Threads.Add(tti);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
#endif
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void Remove(Thread thread)
 | 
			
		||||
        {
 | 
			
		||||
#if DEBUG
 | 
			
		||||
            lock (m_Threads)
 | 
			
		||||
            {
 | 
			
		||||
                foreach (ThreadTrackerItem tti in new ArrayList(m_Threads))
 | 
			
		||||
                {
 | 
			
		||||
                    if (tti.Thread == thread)
 | 
			
		||||
                        m_Threads.Remove(tti);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
#endif
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void CleanUp()
 | 
			
		||||
        {
 | 
			
		||||
            lock (m_Threads)
 | 
			
		||||
            {
 | 
			
		||||
                foreach (ThreadTrackerItem tti in new ArrayList(m_Threads))
 | 
			
		||||
                {
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        
 | 
			
		||||
                    
 | 
			
		||||
                        if (tti.Thread.IsAlive)
 | 
			
		||||
                        {
 | 
			
		||||
                            // Its active
 | 
			
		||||
                            tti.LastSeenActive = DateTime.Now.Ticks;
 | 
			
		||||
                        }
 | 
			
		||||
                        else
 | 
			
		||||
                        {
 | 
			
		||||
                            // Its not active -- if its expired then remove it
 | 
			
		||||
                            if (tti.LastSeenActive + ThreadTimeout < DateTime.Now.Ticks)
 | 
			
		||||
                                m_Threads.Remove(tti);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    catch (NullReferenceException)
 | 
			
		||||
                    {
 | 
			
		||||
                        m_Threads.Remove(tti);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static List<Thread> GetThreads()
 | 
			
		||||
        {
 | 
			
		||||
            if (m_Threads == null)
 | 
			
		||||
                return null;
 | 
			
		||||
 | 
			
		||||
            List<Thread> threads = new List<Thread>();
 | 
			
		||||
            lock (m_Threads)
 | 
			
		||||
            {
 | 
			
		||||
                foreach (ThreadTrackerItem tti in new ArrayList(m_Threads))
 | 
			
		||||
                {
 | 
			
		||||
                    threads.Add(tti.Thread);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return threads;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        #region Nested type: ThreadTrackerItem
 | 
			
		||||
 | 
			
		||||
        public class ThreadTrackerItem
 | 
			
		||||
        {
 | 
			
		||||
            public long LastSeenActive;
 | 
			
		||||
            public Thread Thread;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        #endregion
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,9 +29,9 @@ using System;
 | 
			
		|||
 | 
			
		||||
namespace OpenSim.Framework
 | 
			
		||||
{
 | 
			
		||||
    [Flags]
 | 
			
		||||
    public enum ThrottleOutPacketType : int
 | 
			
		||||
    {
 | 
			
		||||
        Unknown = -1, // Also doubles as 'do not throttle'
 | 
			
		||||
        Resend = 0,
 | 
			
		||||
        Land = 1,
 | 
			
		||||
        Wind = 2,
 | 
			
		||||
| 
						 | 
				
			
			@ -39,11 +39,5 @@ namespace OpenSim.Framework
 | 
			
		|||
        Task = 4,
 | 
			
		||||
        Texture = 5,
 | 
			
		||||
        Asset = 6,
 | 
			
		||||
        Unknown = 7, // Also doubles as 'do not throttle'
 | 
			
		||||
        Back = 8,
 | 
			
		||||
 | 
			
		||||
        TypeMask = 15, // The mask to mask off the flags
 | 
			
		||||
 | 
			
		||||
        LowPriority = 128 // Additional flags
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1231,6 +1231,42 @@ namespace OpenSim.Framework
 | 
			
		|||
            return (ipaddr1 != null) ? "http://" + ipaddr1.ToString() + ":" + port1 : uri;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static byte[] StringToBytes256(string str)
 | 
			
		||||
        {
 | 
			
		||||
            if (String.IsNullOrEmpty(str)) { return Utils.EmptyBytes; }
 | 
			
		||||
            if (str.Length > 254) str = str.Remove(254);
 | 
			
		||||
            if (!str.EndsWith("\0")) { str += "\0"; }
 | 
			
		||||
            
 | 
			
		||||
            // Because this is UTF-8 encoding and not ASCII, it's possible we
 | 
			
		||||
            // might have gotten an oversized array even after the string trim
 | 
			
		||||
            byte[] data = UTF8.GetBytes(str);
 | 
			
		||||
            if (data.Length > 256)
 | 
			
		||||
            {
 | 
			
		||||
                Array.Resize<byte>(ref data, 256);
 | 
			
		||||
                data[255] = 0;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return data;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static byte[] StringToBytes1024(string str)
 | 
			
		||||
        {
 | 
			
		||||
            if (String.IsNullOrEmpty(str)) { return Utils.EmptyBytes; }
 | 
			
		||||
            if (str.Length > 1023) str = str.Remove(1023);
 | 
			
		||||
            if (!str.EndsWith("\0")) { str += "\0"; }
 | 
			
		||||
 | 
			
		||||
            // Because this is UTF-8 encoding and not ASCII, it's possible we
 | 
			
		||||
            // might have gotten an oversized array even after the string trim
 | 
			
		||||
            byte[] data = UTF8.GetBytes(str);
 | 
			
		||||
            if (data.Length > 1024)
 | 
			
		||||
            {
 | 
			
		||||
                Array.Resize<byte>(ref data, 1024);
 | 
			
		||||
                data[1023] = 0;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return data;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        #region FireAndForget Threading Pattern
 | 
			
		||||
 | 
			
		||||
        public static void FireAndForget(System.Threading.WaitCallback callback)
 | 
			
		||||
| 
						 | 
				
			
			@ -1247,7 +1283,9 @@ namespace OpenSim.Framework
 | 
			
		|||
        {
 | 
			
		||||
            System.Threading.WaitCallback callback = (System.Threading.WaitCallback)ar.AsyncState;
 | 
			
		||||
 | 
			
		||||
            callback.EndInvoke(ar);
 | 
			
		||||
            try { callback.EndInvoke(ar); }
 | 
			
		||||
            catch (Exception ex) { m_log.Error("[UTIL]: Asynchronous method threw an exception: " + ex.Message, ex); }
 | 
			
		||||
 | 
			
		||||
            ar.AsyncWaitHandle.Close();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -91,6 +91,18 @@ namespace OpenSim
 | 
			
		|||
                m_log.Info("[OPENSIM MAIN]: configured log4net using default OpenSim.exe.config");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Increase the number of IOCP threads available. Mono defaults to a tragically low number
 | 
			
		||||
            int workerThreads, iocpThreads;
 | 
			
		||||
            System.Threading.ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads);
 | 
			
		||||
            m_log.InfoFormat("[OPENSIM MAIN]: Runtime gave us {0} worker threads and {1} IOCP threads", workerThreads, iocpThreads);
 | 
			
		||||
            if (workerThreads < 500 || iocpThreads < 1000)
 | 
			
		||||
            {
 | 
			
		||||
                workerThreads = 500;
 | 
			
		||||
                iocpThreads = 1000;
 | 
			
		||||
                m_log.Info("[OPENSIM MAIN]: Bumping up to 500 worker threads and 1000 IOCP threads");
 | 
			
		||||
                System.Threading.ThreadPool.SetMaxThreads(workerThreads, iocpThreads);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Check if the system is compatible with OpenSimulator.
 | 
			
		||||
            // Ensures that the minimum system requirements are met
 | 
			
		||||
            m_log.Info("Performing compatibility checks... ");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -675,7 +675,7 @@ namespace OpenSim
 | 
			
		|||
 | 
			
		||||
            if (foundClientServer)
 | 
			
		||||
            {
 | 
			
		||||
                m_clientServers[clientServerElement].Server.Close();
 | 
			
		||||
                m_clientServers[clientServerElement].NetworkStop();
 | 
			
		||||
                m_clientServers.RemoveAt(clientServerElement);
 | 
			
		||||
            }
 | 
			
		||||
            IScene scene;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,7 +38,7 @@ namespace OpenSim.Region.ClientStack
 | 
			
		|||
            IPAddress _listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, 
 | 
			
		||||
            AgentCircuitManager authenticateClass);
 | 
			
		||||
 | 
			
		||||
        Socket Server { get; }
 | 
			
		||||
        void NetworkStop();
 | 
			
		||||
        bool HandlesRegion(Location x);
 | 
			
		||||
        void AddScene(IScene x);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,38 +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.Net.Sockets;
 | 
			
		||||
 | 
			
		||||
namespace OpenSim.Region.ClientStack.LindenUDP
 | 
			
		||||
{
 | 
			
		||||
    public interface ILLClientStackNetworkHandler
 | 
			
		||||
    {
 | 
			
		||||
        void SendPacketTo(byte[] buffer, int size, SocketFlags flags, uint circuitcode); // EndPoint packetSender);
 | 
			
		||||
        void RemoveClientCircuit(uint circuitcode);
 | 
			
		||||
        void RegisterPacketServer(LLPacketServer server);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,83 +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 OpenMetaverse;
 | 
			
		||||
using OpenMetaverse.Packets;
 | 
			
		||||
using OpenSim.Framework;
 | 
			
		||||
 | 
			
		||||
namespace OpenSim.Region.ClientStack.LindenUDP
 | 
			
		||||
{
 | 
			
		||||
    public delegate void PacketStats(int inPackets, int outPackets, int unAckedBytes);
 | 
			
		||||
    public delegate void PacketDrop(Packet pack, Object id);
 | 
			
		||||
    public delegate void QueueEmpty(ThrottleOutPacketType queue);
 | 
			
		||||
    public delegate bool SynchronizeClientHandler(IScene scene, Packet packet, UUID agentID, ThrottleOutPacketType throttlePacketType);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Interface to a class that handles all the activity involved with maintaining the client circuit (handling acks,
 | 
			
		||||
    /// resends, pings, etc.)
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public interface ILLPacketHandler : IDisposable
 | 
			
		||||
    {
 | 
			
		||||
        event PacketStats OnPacketStats;
 | 
			
		||||
        event PacketDrop OnPacketDrop;
 | 
			
		||||
        event QueueEmpty OnQueueEmpty;
 | 
			
		||||
        SynchronizeClientHandler SynchronizeClient { set; }
 | 
			
		||||
 | 
			
		||||
        int PacketsReceived { get; }
 | 
			
		||||
        int PacketsReceivedReported { get; }
 | 
			
		||||
        uint ResendTimeout { get; set; }
 | 
			
		||||
        bool ReliableIsImportant { get; set; }
 | 
			
		||||
        int MaxReliableResends { get; set; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Initial handling of a received packet.  It will be processed later in ProcessInPacket()
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="packet"></param>
 | 
			
		||||
        void InPacket(Packet packet);
 | 
			
		||||
        
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Take action depending on the type and contents of an received packet.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="item"></param>
 | 
			
		||||
        void ProcessInPacket(LLQueItem item);
 | 
			
		||||
        
 | 
			
		||||
        void ProcessOutPacket(LLQueItem item);
 | 
			
		||||
        void OutPacket(Packet NewPack,
 | 
			
		||||
                       ThrottleOutPacketType throttlePacketType);
 | 
			
		||||
        void OutPacket(Packet NewPack,
 | 
			
		||||
                       ThrottleOutPacketType throttlePacketType, Object id);
 | 
			
		||||
        LLPacketQueue PacketQueue { get; }
 | 
			
		||||
        void Flush();
 | 
			
		||||
        void Clear();
 | 
			
		||||
        ClientInfo GetClientInfo();
 | 
			
		||||
        void SetClientInfo(ClientInfo info);
 | 
			
		||||
        void AddImportantPacket(PacketType type);
 | 
			
		||||
        void RemoveImportantPacket(PacketType type);
 | 
			
		||||
        int GetQueueCount(ThrottleOutPacketType queue);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
/*
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) Contributors, http://opensimulator.org/
 | 
			
		||||
 * See CONTRIBUTORS.TXT for a full list of copyright holders.
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -26,24 +26,32 @@
 | 
			
		|||
 */
 | 
			
		||||
 | 
			
		||||
using System;
 | 
			
		||||
using OpenMetaverse.Packets;
 | 
			
		||||
using OpenSim.Framework;
 | 
			
		||||
using OpenMetaverse;
 | 
			
		||||
using OpenMetaverse.Packets;
 | 
			
		||||
 | 
			
		||||
namespace OpenSim.Region.ClientStack.LindenUDP
 | 
			
		||||
{
 | 
			
		||||
    public class LLQueItem
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Holds a reference to a <seealso cref="LLUDPClient"/> and a <seealso cref="Packet"/>
 | 
			
		||||
    /// for incoming packets
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public sealed class IncomingPacket
 | 
			
		||||
    {
 | 
			
		||||
        public LLQueItem()
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>Client this packet came from</summary>
 | 
			
		||||
        public LLUDPClient Client;
 | 
			
		||||
        /// <summary>Packet data that has been received</summary>
 | 
			
		||||
        public Packet Packet;
 | 
			
		||||
        public bool Incoming;
 | 
			
		||||
        public ThrottleOutPacketType throttleType;
 | 
			
		||||
        public int TickCount;
 | 
			
		||||
        public Object Identifier;
 | 
			
		||||
        public int Resends;
 | 
			
		||||
        public int Length;
 | 
			
		||||
        public uint Sequence;
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Default constructor
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="client">Reference to the client this packet came from</param>
 | 
			
		||||
        /// <param name="packet">Packet data</param>
 | 
			
		||||
        public IncomingPacket(LLUDPClient client, Packet packet)
 | 
			
		||||
        {
 | 
			
		||||
            Client = client;
 | 
			
		||||
            Packet = packet;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
/*
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) Contributors, http://opensimulator.org/
 | 
			
		||||
 * See CONTRIBUTORS.TXT for a full list of copyright holders.
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -25,47 +25,49 @@
 | 
			
		|||
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
using OpenMetaverse.Packets;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace OpenSim.Region.ClientStack.LindenUDP
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// When packetqueue dequeues this packet in the outgoing stream, it thread aborts
 | 
			
		||||
    /// Ensures that the thread abort happens from within the client thread
 | 
			
		||||
    /// regardless of where the close method is called
 | 
			
		||||
    /// A circular buffer and hashset for tracking incoming packet sequence
 | 
			
		||||
    /// numbers
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    class KillPacket : Packet
 | 
			
		||||
    public sealed class IncomingPacketHistoryCollection
 | 
			
		||||
    {
 | 
			
		||||
        public override int Length
 | 
			
		||||
        private readonly uint[] m_items;
 | 
			
		||||
        private HashSet<uint> m_hashSet;
 | 
			
		||||
        private int m_first;
 | 
			
		||||
        private int m_next;
 | 
			
		||||
        private int m_capacity;
 | 
			
		||||
 | 
			
		||||
        public IncomingPacketHistoryCollection(int capacity)
 | 
			
		||||
        {
 | 
			
		||||
            get { return 0; }
 | 
			
		||||
            this.m_capacity = capacity;
 | 
			
		||||
            m_items = new uint[capacity];
 | 
			
		||||
            m_hashSet = new HashSet<uint>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd)
 | 
			
		||||
        public bool TryEnqueue(uint ack)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
            lock (m_hashSet)
 | 
			
		||||
            {
 | 
			
		||||
                if (m_hashSet.Add(ack))
 | 
			
		||||
                {
 | 
			
		||||
                    m_items[m_next] = ack;
 | 
			
		||||
                    m_next = (m_next + 1) % m_capacity;
 | 
			
		||||
                    if (m_next == m_first)
 | 
			
		||||
                    {
 | 
			
		||||
                        m_hashSet.Remove(m_items[m_first]);
 | 
			
		||||
                        m_first = (m_first + 1) % m_capacity;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
        public override void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        public override byte[] ToBytes()
 | 
			
		||||
        {
 | 
			
		||||
            return new byte[0];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override byte[][] ToBytesMultiple()
 | 
			
		||||
        {
 | 
			
		||||
            return new byte[][] { new byte[0] };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public KillPacket()
 | 
			
		||||
        {
 | 
			
		||||
            Type = PacketType.UseCircuitCode;
 | 
			
		||||
            Header = new Header();
 | 
			
		||||
            Header.Frequency = OpenMetaverse.PacketFrequency.Low;
 | 
			
		||||
            Header.ID = 65531;
 | 
			
		||||
            Header.Reliable = true;
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -76,27 +76,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
 | 
			
		|||
        {
 | 
			
		||||
            if (m_currentPacket <= m_stopPacket)
 | 
			
		||||
            {
 | 
			
		||||
                bool SendMore = true;
 | 
			
		||||
                int count = 0;
 | 
			
		||||
                bool sendMore = true;
 | 
			
		||||
 | 
			
		||||
                if (!m_sentInfo || (m_currentPacket == 0))
 | 
			
		||||
                {
 | 
			
		||||
                    if (SendFirstPacket(client))
 | 
			
		||||
                    {
 | 
			
		||||
                        SendMore = false;
 | 
			
		||||
                    }
 | 
			
		||||
                    sendMore = !SendFirstPacket(client);
 | 
			
		||||
 | 
			
		||||
                    m_sentInfo = true;
 | 
			
		||||
                    m_currentPacket++;
 | 
			
		||||
                    ++m_currentPacket;
 | 
			
		||||
                    ++count;
 | 
			
		||||
                }
 | 
			
		||||
                if (m_currentPacket < 2)
 | 
			
		||||
                {
 | 
			
		||||
                    m_currentPacket = 2;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                int count = 0;
 | 
			
		||||
                while (SendMore && count < maxpack && m_currentPacket <= m_stopPacket)
 | 
			
		||||
                
 | 
			
		||||
                while (sendMore && count < maxpack && m_currentPacket <= m_stopPacket)
 | 
			
		||||
                {
 | 
			
		||||
                    count++;
 | 
			
		||||
                    SendMore = SendPacket(client);
 | 
			
		||||
                    m_currentPacket++;
 | 
			
		||||
                    sendMore = SendPacket(client);
 | 
			
		||||
                    ++m_currentPacket;
 | 
			
		||||
                    ++count;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (m_currentPacket > m_stopPacket)
 | 
			
		||||
| 
						 | 
				
			
			@ -196,13 +196,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
 | 
			
		|||
 | 
			
		||||
                        m_currentPacket = StartPacket;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if ((m_imageManager != null) && (m_imageManager.Client != null) && (m_imageManager.Client.PacketHandler != null))
 | 
			
		||||
                        if (m_imageManager.Client.PacketHandler.GetQueueCount(ThrottleOutPacketType.Texture) == 0)
 | 
			
		||||
                        {
 | 
			
		||||
                            //m_log.Debug("No textures queued, sending one packet to kickstart it");
 | 
			
		||||
                            SendPacket(m_imageManager.Client);
 | 
			
		||||
                        }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
				
			
			@ -172,7 +172,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
 | 
			
		|||
                m_lastloopprocessed = DateTime.Now.Ticks;
 | 
			
		||||
 | 
			
		||||
                // This can happen during Close()
 | 
			
		||||
                if (m_client == null || m_client.PacketHandler == null || m_client.PacketHandler.PacketQueue == null)
 | 
			
		||||
                if (m_client == null)
 | 
			
		||||
                    return false;
 | 
			
		||||
                
 | 
			
		||||
                while ((imagereq = GetHighestPriorityImage()) != null)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,870 +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.Reflection;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Net.Sockets;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Timers;
 | 
			
		||||
using OpenMetaverse;
 | 
			
		||||
using OpenMetaverse.Packets;
 | 
			
		||||
using log4net;
 | 
			
		||||
using OpenSim.Framework;
 | 
			
		||||
using Timer=System.Timers.Timer;
 | 
			
		||||
 | 
			
		||||
namespace OpenSim.Region.ClientStack.LindenUDP
 | 
			
		||||
{
 | 
			
		||||
    public class LLPacketHandler : ILLPacketHandler
 | 
			
		||||
    {
 | 
			
		||||
        private static readonly ILog m_log 
 | 
			
		||||
            = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
 | 
			
		||||
 | 
			
		||||
        //private int m_resentCount;
 | 
			
		||||
 | 
			
		||||
        // Packet queues
 | 
			
		||||
        //
 | 
			
		||||
        LLPacketQueue m_PacketQueue;
 | 
			
		||||
 | 
			
		||||
        public LLPacketQueue PacketQueue
 | 
			
		||||
        {
 | 
			
		||||
            get { return m_PacketQueue; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Timer to run stats and acks on
 | 
			
		||||
        //
 | 
			
		||||
        private Timer m_AckTimer = new Timer(250);
 | 
			
		||||
 | 
			
		||||
        // A list of the packets we haven't acked yet
 | 
			
		||||
        //
 | 
			
		||||
        private List<uint> m_PendingAcks = new List<uint>();
 | 
			
		||||
        private Dictionary<uint, uint> m_PendingAcksMap = new Dictionary<uint, uint>();
 | 
			
		||||
 | 
			
		||||
        private Dictionary<uint, LLQueItem> m_NeedAck =
 | 
			
		||||
                new Dictionary<uint, LLQueItem>();
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// The number of milliseconds that can pass before a packet that needs an ack is resent.
 | 
			
		||||
        /// </param>
 | 
			
		||||
        private uint m_ResendTimeout = 4000;
 | 
			
		||||
 | 
			
		||||
        public uint ResendTimeout
 | 
			
		||||
        {
 | 
			
		||||
            get { return m_ResendTimeout; }
 | 
			
		||||
            set { m_ResendTimeout = value; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private int m_MaxReliableResends = 3;
 | 
			
		||||
 | 
			
		||||
        public int MaxReliableResends
 | 
			
		||||
        {
 | 
			
		||||
            get { return m_MaxReliableResends; }
 | 
			
		||||
            set { m_MaxReliableResends = value; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Track duplicated packets. This uses a Dictionary. Both insertion
 | 
			
		||||
        // and lookup are common operations and need to take advantage of
 | 
			
		||||
        // the hashing. Expiration is less common and can be allowed the
 | 
			
		||||
        // time for a linear scan.
 | 
			
		||||
        //
 | 
			
		||||
        private List<uint> m_alreadySeenList = new List<uint>();
 | 
			
		||||
        private Dictionary<uint, int>m_alreadySeenTracker = new Dictionary<uint, int>();
 | 
			
		||||
        private int m_alreadySeenWindow = 30000;
 | 
			
		||||
        private int m_lastAlreadySeenCheck = Environment.TickCount & Int32.MaxValue;
 | 
			
		||||
 | 
			
		||||
        // private Dictionary<uint, int> m_DupeTracker =
 | 
			
		||||
        //     new Dictionary<uint, int>();
 | 
			
		||||
        // private uint m_DupeTrackerWindow = 30;
 | 
			
		||||
        // private int m_DupeTrackerLastCheck = Environment.TickCount;
 | 
			
		||||
 | 
			
		||||
        // Values for the SimStatsReporter
 | 
			
		||||
        //
 | 
			
		||||
        private int m_PacketsReceived = 0;
 | 
			
		||||
        private int m_PacketsReceivedReported = 0;
 | 
			
		||||
        private int m_PacketsSent = 0;
 | 
			
		||||
        private int m_PacketsSentReported = 0;
 | 
			
		||||
        private int m_UnackedBytes = 0;
 | 
			
		||||
 | 
			
		||||
        private int m_LastResend = 0;
 | 
			
		||||
 | 
			
		||||
        public int PacketsReceived
 | 
			
		||||
        {
 | 
			
		||||
            get { return m_PacketsReceived; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public int PacketsReceivedReported
 | 
			
		||||
        {
 | 
			
		||||
            get { return m_PacketsReceivedReported; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // The client we are working for
 | 
			
		||||
        //
 | 
			
		||||
        private IClientAPI m_Client;
 | 
			
		||||
 | 
			
		||||
        // Some events
 | 
			
		||||
        //
 | 
			
		||||
        public event PacketStats OnPacketStats;
 | 
			
		||||
        public event PacketDrop OnPacketDrop;
 | 
			
		||||
        public event QueueEmpty OnQueueEmpty;
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        //private SynchronizeClientHandler m_SynchronizeClient = null;
 | 
			
		||||
 | 
			
		||||
        public SynchronizeClientHandler SynchronizeClient
 | 
			
		||||
        {
 | 
			
		||||
            set { /* m_SynchronizeClient = value; */ }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Packet sequencing
 | 
			
		||||
        //
 | 
			
		||||
        private uint m_Sequence = 0;
 | 
			
		||||
        private object m_SequenceLock = new object();
 | 
			
		||||
        private const int MAX_SEQUENCE = 0xFFFFFF;
 | 
			
		||||
 | 
			
		||||
        // Packet dropping
 | 
			
		||||
        //
 | 
			
		||||
        List<PacketType> m_ImportantPackets = new List<PacketType>();
 | 
			
		||||
        private bool m_ReliableIsImportant = false;
 | 
			
		||||
 | 
			
		||||
        public bool ReliableIsImportant
 | 
			
		||||
        {
 | 
			
		||||
            get { return m_ReliableIsImportant; }
 | 
			
		||||
            set { m_ReliableIsImportant = value; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private int m_DropSafeTimeout;
 | 
			
		||||
 | 
			
		||||
        LLPacketServer m_PacketServer;
 | 
			
		||||
        private byte[] m_ZeroOutBuffer = new byte[4096];
 | 
			
		||||
 | 
			
		||||
        ////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
        // Constructors
 | 
			
		||||
        //
 | 
			
		||||
        public LLPacketHandler(IClientAPI client, LLPacketServer server, ClientStackUserSettings userSettings)
 | 
			
		||||
        {
 | 
			
		||||
            m_Client = client;
 | 
			
		||||
            m_PacketServer = server;
 | 
			
		||||
            m_DropSafeTimeout = Environment.TickCount + 15000;
 | 
			
		||||
 | 
			
		||||
            m_PacketQueue = new LLPacketQueue(client.AgentId, userSettings);
 | 
			
		||||
 | 
			
		||||
            m_PacketQueue.OnQueueEmpty += TriggerOnQueueEmpty;
 | 
			
		||||
 | 
			
		||||
            m_AckTimer.Elapsed += AckTimerElapsed;
 | 
			
		||||
            m_AckTimer.Start();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Dispose()
 | 
			
		||||
        {
 | 
			
		||||
            m_AckTimer.Stop();
 | 
			
		||||
            m_AckTimer.Close();
 | 
			
		||||
 | 
			
		||||
            m_PacketQueue.Enqueue(null);
 | 
			
		||||
            m_PacketQueue.Close();
 | 
			
		||||
            m_Client = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Send one packet. This actually doesn't send anything, it queues
 | 
			
		||||
        // it. Designed to be fire-and-forget, but there is an optional
 | 
			
		||||
        // notifier.
 | 
			
		||||
        //
 | 
			
		||||
        public void OutPacket(
 | 
			
		||||
            Packet packet, ThrottleOutPacketType throttlePacketType)
 | 
			
		||||
        {
 | 
			
		||||
            OutPacket(packet, throttlePacketType, null);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void OutPacket(
 | 
			
		||||
            Packet packet, ThrottleOutPacketType throttlePacketType,
 | 
			
		||||
            Object id)
 | 
			
		||||
        {
 | 
			
		||||
            // Call the load balancer's hook. If this is not active here
 | 
			
		||||
            // we defer to the sim server this client is actually connected
 | 
			
		||||
            // to. Packet drop notifies will not be triggered in this
 | 
			
		||||
            // configuration!
 | 
			
		||||
            //
 | 
			
		||||
 | 
			
		||||
            packet.Header.Sequence = 0;
 | 
			
		||||
 | 
			
		||||
            lock (m_NeedAck)
 | 
			
		||||
            {
 | 
			
		||||
                DropResend(id);
 | 
			
		||||
 | 
			
		||||
                AddAcks(ref packet);
 | 
			
		||||
                QueuePacket(packet, throttlePacketType, id);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void AddAcks(ref Packet packet)
 | 
			
		||||
        {
 | 
			
		||||
            // These packet types have shown to have issues with
 | 
			
		||||
            // acks being appended to the payload, just don't send
 | 
			
		||||
            // any with them until libsl is fixed.
 | 
			
		||||
            //
 | 
			
		||||
            if (packet is ViewerEffectPacket)
 | 
			
		||||
                return;
 | 
			
		||||
            if (packet is SimStatsPacket)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            // Add acks to outgoing packets
 | 
			
		||||
            //
 | 
			
		||||
            if (m_PendingAcks.Count > 0)
 | 
			
		||||
            {
 | 
			
		||||
                int count = m_PendingAcks.Count;
 | 
			
		||||
                if (count > 10)
 | 
			
		||||
                    count = 10;
 | 
			
		||||
                packet.Header.AckList = new uint[count];
 | 
			
		||||
                packet.Header.AppendedAcks = true;
 | 
			
		||||
 | 
			
		||||
                for (int i = 0; i < count; i++)
 | 
			
		||||
                {
 | 
			
		||||
                    packet.Header.AckList[i] = m_PendingAcks[i];
 | 
			
		||||
                    m_PendingAcksMap.Remove(m_PendingAcks[i]);
 | 
			
		||||
                }
 | 
			
		||||
                m_PendingAcks.RemoveRange(0, count);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void QueuePacket(
 | 
			
		||||
                Packet packet, ThrottleOutPacketType throttlePacketType,
 | 
			
		||||
                Object id)
 | 
			
		||||
        {
 | 
			
		||||
            LLQueItem item = new LLQueItem();
 | 
			
		||||
            item.Packet = packet;
 | 
			
		||||
            item.Incoming = false;
 | 
			
		||||
            item.throttleType = throttlePacketType;
 | 
			
		||||
            item.TickCount = Environment.TickCount;
 | 
			
		||||
            item.Identifier = id;
 | 
			
		||||
            item.Resends = 0;
 | 
			
		||||
            item.Length = packet.Length;
 | 
			
		||||
            item.Sequence = packet.Header.Sequence;
 | 
			
		||||
 | 
			
		||||
            m_PacketQueue.Enqueue(item);
 | 
			
		||||
            m_PacketsSent++;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ResendUnacked()
 | 
			
		||||
        {
 | 
			
		||||
            int now = Environment.TickCount;
 | 
			
		||||
 | 
			
		||||
            int intervalMs = 250;
 | 
			
		||||
 | 
			
		||||
            if (m_LastResend != 0)
 | 
			
		||||
                intervalMs = now - m_LastResend;
 | 
			
		||||
 | 
			
		||||
            lock (m_NeedAck)
 | 
			
		||||
            {
 | 
			
		||||
                if (m_DropSafeTimeout > now ||
 | 
			
		||||
                    intervalMs > 500) // We were frozen!
 | 
			
		||||
                {
 | 
			
		||||
                    foreach (LLQueItem data in m_NeedAck.Values)
 | 
			
		||||
                    {
 | 
			
		||||
                        if (m_DropSafeTimeout > now)
 | 
			
		||||
                        {
 | 
			
		||||
                            m_NeedAck[data.Packet.Header.Sequence].TickCount = now;
 | 
			
		||||
                        }
 | 
			
		||||
                        else
 | 
			
		||||
                        {
 | 
			
		||||
                            m_NeedAck[data.Packet.Header.Sequence].TickCount += intervalMs;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                m_LastResend = now;
 | 
			
		||||
                
 | 
			
		||||
                // Unless we have received at least one ack, don't bother resending
 | 
			
		||||
                // anything. There may not be a client there, don't clog up the
 | 
			
		||||
                // pipes.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                // Nothing to do
 | 
			
		||||
                //
 | 
			
		||||
                if (m_NeedAck.Count == 0)
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                int resent = 0;
 | 
			
		||||
                long dueDate = now - m_ResendTimeout;
 | 
			
		||||
 | 
			
		||||
                List<LLQueItem> dropped = new List<LLQueItem>();
 | 
			
		||||
                foreach (LLQueItem data in m_NeedAck.Values)
 | 
			
		||||
                {
 | 
			
		||||
                    Packet packet = data.Packet;
 | 
			
		||||
 | 
			
		||||
                    // Packets this old get resent
 | 
			
		||||
                    //
 | 
			
		||||
                    if (data.TickCount < dueDate && data.Sequence != 0 && !m_PacketQueue.Contains(data.Sequence))
 | 
			
		||||
                    {
 | 
			
		||||
                        if (resent < 20) // Was 20 (= Max 117kbit/sec resends)
 | 
			
		||||
                        {
 | 
			
		||||
                            m_NeedAck[packet.Header.Sequence].Resends++;
 | 
			
		||||
 | 
			
		||||
                            // The client needs to be told that a packet is being resent, otherwise it appears to believe
 | 
			
		||||
                            // that it should reset its sequence to that packet number.
 | 
			
		||||
                            packet.Header.Resent = true;
 | 
			
		||||
 | 
			
		||||
                            if ((m_NeedAck[packet.Header.Sequence].Resends >= m_MaxReliableResends) && 
 | 
			
		||||
                                (!m_ReliableIsImportant))
 | 
			
		||||
                            {
 | 
			
		||||
                                dropped.Add(data);
 | 
			
		||||
                                continue;
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            m_NeedAck[packet.Header.Sequence].TickCount = Environment.TickCount;
 | 
			
		||||
                            QueuePacket(packet, ThrottleOutPacketType.Resend, data.Identifier);
 | 
			
		||||
                            resent++;
 | 
			
		||||
                        }
 | 
			
		||||
                        else
 | 
			
		||||
                        {
 | 
			
		||||
                            m_NeedAck[packet.Header.Sequence].TickCount += intervalMs;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                foreach (LLQueItem data in dropped)
 | 
			
		||||
                {
 | 
			
		||||
                    m_NeedAck.Remove(data.Packet.Header.Sequence);
 | 
			
		||||
                    TriggerOnPacketDrop(data.Packet, data.Identifier);
 | 
			
		||||
                    m_PacketQueue.Cancel(data.Packet.Header.Sequence);
 | 
			
		||||
                    PacketPool.Instance.ReturnPacket(data.Packet);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Send the pending packet acks to the client
 | 
			
		||||
        // Will send blocks of acks for up to 250 packets
 | 
			
		||||
        //
 | 
			
		||||
        private void SendAcks()
 | 
			
		||||
        {
 | 
			
		||||
            lock (m_NeedAck)
 | 
			
		||||
            {
 | 
			
		||||
                if (m_PendingAcks.Count == 0)
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                PacketAckPacket acks = (PacketAckPacket)PacketPool.Instance.GetPacket(PacketType.PacketAck);
 | 
			
		||||
 | 
			
		||||
                // The case of equality is more common than one might think,
 | 
			
		||||
                // because this function will be called unconditionally when
 | 
			
		||||
                // the counter reaches 250. So there is a good chance another
 | 
			
		||||
                // packet with 250 blocks exists.
 | 
			
		||||
                //
 | 
			
		||||
                if (acks.Packets == null ||
 | 
			
		||||
                    acks.Packets.Length != m_PendingAcks.Count)
 | 
			
		||||
                    acks.Packets = new PacketAckPacket.PacketsBlock[m_PendingAcks.Count];
 | 
			
		||||
 | 
			
		||||
                for (int i = 0; i < m_PendingAcks.Count; i++)
 | 
			
		||||
                {
 | 
			
		||||
                    acks.Packets[i] = new PacketAckPacket.PacketsBlock();
 | 
			
		||||
                    acks.Packets[i].ID = m_PendingAcks[i];
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
                m_PendingAcks.Clear();
 | 
			
		||||
                m_PendingAcksMap.Clear();
 | 
			
		||||
 | 
			
		||||
                acks.Header.Reliable = false;
 | 
			
		||||
                OutPacket(acks, ThrottleOutPacketType.Unknown);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Queue a packet ack. It will be sent either after 250 acks are
 | 
			
		||||
        // queued, or when the timer fires.
 | 
			
		||||
        //
 | 
			
		||||
        private void AckPacket(Packet packet)
 | 
			
		||||
        {
 | 
			
		||||
            lock (m_NeedAck)
 | 
			
		||||
            {
 | 
			
		||||
                if (m_PendingAcks.Count < 250)
 | 
			
		||||
                {
 | 
			
		||||
                    if (!m_PendingAcksMap.ContainsKey(packet.Header.Sequence))
 | 
			
		||||
                    {
 | 
			
		||||
                        m_PendingAcks.Add(packet.Header.Sequence);
 | 
			
		||||
                        m_PendingAcksMap.Add(packet.Header.Sequence,
 | 
			
		||||
                                             packet.Header.Sequence);
 | 
			
		||||
                    }
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            SendAcks();
 | 
			
		||||
 | 
			
		||||
            lock (m_NeedAck)
 | 
			
		||||
            {
 | 
			
		||||
                // If this is still full we have a truly exceptional
 | 
			
		||||
                // condition (means, can't happen)
 | 
			
		||||
                //
 | 
			
		||||
                if (m_PendingAcks.Count < 250)
 | 
			
		||||
                {
 | 
			
		||||
                    if (!m_PendingAcksMap.ContainsKey(packet.Header.Sequence))
 | 
			
		||||
                    {
 | 
			
		||||
                        m_PendingAcks.Add(packet.Header.Sequence);
 | 
			
		||||
                        m_PendingAcksMap.Add(packet.Header.Sequence,
 | 
			
		||||
                                             packet.Header.Sequence);
 | 
			
		||||
                    }
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // When the timer elapses, send the pending acks, trigger resends
 | 
			
		||||
        // and report all the stats.
 | 
			
		||||
        //
 | 
			
		||||
        private void AckTimerElapsed(object sender, ElapsedEventArgs ea)
 | 
			
		||||
        {
 | 
			
		||||
            SendAcks();
 | 
			
		||||
            ResendUnacked();
 | 
			
		||||
            SendPacketStats();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Push out pachet counts for the sim status reporter
 | 
			
		||||
        //
 | 
			
		||||
        private void SendPacketStats()
 | 
			
		||||
        {
 | 
			
		||||
            PacketStats handlerPacketStats = OnPacketStats;
 | 
			
		||||
            if (handlerPacketStats != null)
 | 
			
		||||
            {
 | 
			
		||||
                handlerPacketStats(
 | 
			
		||||
                    m_PacketsReceived - m_PacketsReceivedReported,
 | 
			
		||||
                    m_PacketsSent - m_PacketsSentReported,
 | 
			
		||||
                    m_UnackedBytes);
 | 
			
		||||
 | 
			
		||||
                m_PacketsReceivedReported = m_PacketsReceived;
 | 
			
		||||
                m_PacketsSentReported = m_PacketsSent;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // We can't keep an unlimited record of dupes. This will prune the
 | 
			
		||||
        // dictionary by age.
 | 
			
		||||
        //
 | 
			
		||||
        // NOTE: this needs to be called from within lock
 | 
			
		||||
        // (m_alreadySeenTracker) context!
 | 
			
		||||
        private void ExpireSeenPackets()
 | 
			
		||||
        {
 | 
			
		||||
            if (m_alreadySeenList.Count < 1024)
 | 
			
		||||
                return;
 | 
			
		||||
            
 | 
			
		||||
            int ticks = 0;
 | 
			
		||||
            int tc = Environment.TickCount & Int32.MaxValue;
 | 
			
		||||
            if (tc >= m_lastAlreadySeenCheck) 
 | 
			
		||||
                ticks = tc - m_lastAlreadySeenCheck;
 | 
			
		||||
            else
 | 
			
		||||
                ticks = Int32.MaxValue - m_lastAlreadySeenCheck + tc;
 | 
			
		||||
            
 | 
			
		||||
            if (ticks < 2000) return;
 | 
			
		||||
            m_lastAlreadySeenCheck = tc;
 | 
			
		||||
 | 
			
		||||
            // we calculate the drop dead tick count here instead of
 | 
			
		||||
            // in the loop: any packet with a timestamp before
 | 
			
		||||
            // dropDeadTC can be expired
 | 
			
		||||
            int dropDeadTC = tc - m_alreadySeenWindow;
 | 
			
		||||
            int i = 0;
 | 
			
		||||
            while (i < m_alreadySeenList.Count && m_alreadySeenTracker[m_alreadySeenList[i]] < dropDeadTC)
 | 
			
		||||
            {
 | 
			
		||||
                m_alreadySeenTracker.Remove(m_alreadySeenList[i]);
 | 
			
		||||
                i++;
 | 
			
		||||
            }
 | 
			
		||||
            // if we dropped packet from m_alreadySeenTracker we need
 | 
			
		||||
            // to drop them from m_alreadySeenList as well, let's do
 | 
			
		||||
            // that in one go: the list is ordered after all.
 | 
			
		||||
            if (i > 0)
 | 
			
		||||
            {
 | 
			
		||||
                m_alreadySeenList.RemoveRange(0, i);
 | 
			
		||||
                // m_log.DebugFormat("[CLIENT]: expired {0} packets, {1}:{2} left", i, m_alreadySeenList.Count, m_alreadySeenTracker.Count);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void InPacket(Packet packet)
 | 
			
		||||
        {
 | 
			
		||||
            if (packet == null)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            // When too many acks are needed to be sent, the client sends
 | 
			
		||||
            // a packet consisting of acks only
 | 
			
		||||
            //
 | 
			
		||||
            if (packet.Type == PacketType.PacketAck)
 | 
			
		||||
            {
 | 
			
		||||
                PacketAckPacket ackPacket = (PacketAckPacket)packet;
 | 
			
		||||
 | 
			
		||||
                foreach (PacketAckPacket.PacketsBlock block in ackPacket.Packets)
 | 
			
		||||
                {
 | 
			
		||||
                    ProcessAck(block.ID);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                PacketPool.Instance.ReturnPacket(packet);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Any packet can have some packet acks in the header.
 | 
			
		||||
            // Process them here
 | 
			
		||||
            //
 | 
			
		||||
            if (packet.Header.AppendedAcks)
 | 
			
		||||
            {
 | 
			
		||||
                foreach (uint id in packet.Header.AckList)
 | 
			
		||||
                {
 | 
			
		||||
                    ProcessAck(id);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // If this client is on another partial instance, no need
 | 
			
		||||
            // to handle packets
 | 
			
		||||
            //
 | 
			
		||||
            if (!m_Client.IsActive && packet.Type != PacketType.LogoutRequest)
 | 
			
		||||
            {
 | 
			
		||||
                PacketPool.Instance.ReturnPacket(packet);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (packet.Type == PacketType.StartPingCheck)
 | 
			
		||||
            {
 | 
			
		||||
                StartPingCheckPacket startPing = (StartPingCheckPacket)packet;
 | 
			
		||||
                CompletePingCheckPacket endPing
 | 
			
		||||
                    = (CompletePingCheckPacket)PacketPool.Instance.GetPacket(PacketType.CompletePingCheck);
 | 
			
		||||
 | 
			
		||||
                endPing.PingID.PingID = startPing.PingID.PingID;
 | 
			
		||||
                OutPacket(endPing, ThrottleOutPacketType.Task);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                LLQueItem item = new LLQueItem();
 | 
			
		||||
                item.Packet = packet;
 | 
			
		||||
                item.Incoming = true;
 | 
			
		||||
                m_PacketQueue.Enqueue(item);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void ProcessInPacket(LLQueItem item)
 | 
			
		||||
        {
 | 
			
		||||
            Packet packet = item.Packet;
 | 
			
		||||
 | 
			
		||||
            // Always ack the packet!
 | 
			
		||||
            //
 | 
			
		||||
            if (packet.Header.Reliable)
 | 
			
		||||
                AckPacket(packet);
 | 
			
		||||
 | 
			
		||||
            if (packet.Type != PacketType.AgentUpdate)
 | 
			
		||||
                m_PacketsReceived++;
 | 
			
		||||
 | 
			
		||||
            // Check for duplicate packets..    packets that the client is
 | 
			
		||||
            // resending because it didn't receive our ack
 | 
			
		||||
            //
 | 
			
		||||
            lock (m_alreadySeenTracker)
 | 
			
		||||
            {
 | 
			
		||||
                ExpireSeenPackets();
 | 
			
		||||
            
 | 
			
		||||
                if (m_alreadySeenTracker.ContainsKey(packet.Header.Sequence))
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                m_alreadySeenTracker.Add(packet.Header.Sequence, Environment.TickCount & Int32.MaxValue);
 | 
			
		||||
                m_alreadySeenList.Add(packet.Header.Sequence);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            m_Client.ProcessInPacket(packet);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Flush()
 | 
			
		||||
        {
 | 
			
		||||
            m_PacketQueue.Flush();
 | 
			
		||||
            m_UnackedBytes = (-1 * m_UnackedBytes);
 | 
			
		||||
            SendPacketStats();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Clear()
 | 
			
		||||
        {
 | 
			
		||||
            m_UnackedBytes = (-1 * m_UnackedBytes);
 | 
			
		||||
            SendPacketStats();
 | 
			
		||||
            lock (m_NeedAck) 
 | 
			
		||||
            {
 | 
			
		||||
                m_NeedAck.Clear();
 | 
			
		||||
                m_PendingAcks.Clear();
 | 
			
		||||
                m_PendingAcksMap.Clear();
 | 
			
		||||
            }
 | 
			
		||||
            m_Sequence += 1000000;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ProcessAck(uint id)
 | 
			
		||||
        {
 | 
			
		||||
            LLQueItem data;
 | 
			
		||||
 | 
			
		||||
            lock (m_NeedAck)
 | 
			
		||||
            {
 | 
			
		||||
                //m_log.DebugFormat("[CLIENT]: In {0} received ack for packet {1}", m_Client.Scene.RegionInfo.ExternalEndPoint.Port, id);
 | 
			
		||||
 | 
			
		||||
                if (!m_NeedAck.TryGetValue(id, out data))
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                m_NeedAck.Remove(id);
 | 
			
		||||
                m_PacketQueue.Cancel(data.Sequence);
 | 
			
		||||
                PacketPool.Instance.ReturnPacket(data.Packet);
 | 
			
		||||
                m_UnackedBytes -= data.Length;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Allocate packet sequence numbers in a threadsave manner
 | 
			
		||||
        //
 | 
			
		||||
        protected uint NextPacketSequenceNumber()
 | 
			
		||||
        {
 | 
			
		||||
            // Set the sequence number
 | 
			
		||||
            uint seq = 1;
 | 
			
		||||
            lock (m_SequenceLock)
 | 
			
		||||
            {
 | 
			
		||||
                if (m_Sequence >= MAX_SEQUENCE)
 | 
			
		||||
                {
 | 
			
		||||
                    m_Sequence = 1;
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    m_Sequence++;
 | 
			
		||||
                }
 | 
			
		||||
                seq = m_Sequence;
 | 
			
		||||
            }
 | 
			
		||||
            return seq;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public ClientInfo GetClientInfo()
 | 
			
		||||
        {
 | 
			
		||||
            ClientInfo info = new ClientInfo();
 | 
			
		||||
 | 
			
		||||
            info.pendingAcks = m_PendingAcksMap;
 | 
			
		||||
            info.needAck = new Dictionary<uint, byte[]>();
 | 
			
		||||
 | 
			
		||||
            lock (m_NeedAck)
 | 
			
		||||
            {
 | 
			
		||||
                foreach (uint key in m_NeedAck.Keys)
 | 
			
		||||
                    info.needAck.Add(key, m_NeedAck[key].Packet.ToBytes());
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            LLQueItem[] queitems = m_PacketQueue.GetQueueArray();
 | 
			
		||||
 | 
			
		||||
            for (int i = 0; i < queitems.Length; i++)
 | 
			
		||||
            {
 | 
			
		||||
                if (queitems[i].Incoming == false)
 | 
			
		||||
                    info.out_packets.Add(queitems[i].Packet.ToBytes());
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            info.sequence = m_Sequence;
 | 
			
		||||
 | 
			
		||||
            float multiplier = m_PacketQueue.ThrottleMultiplier;
 | 
			
		||||
            info.resendThrottle = (int) (m_PacketQueue.ResendThrottle.Throttle / multiplier);
 | 
			
		||||
            info.landThrottle = (int) (m_PacketQueue.LandThrottle.Throttle / multiplier);
 | 
			
		||||
            info.windThrottle = (int) (m_PacketQueue.WindThrottle.Throttle / multiplier);
 | 
			
		||||
            info.cloudThrottle = (int) (m_PacketQueue.CloudThrottle.Throttle / multiplier);
 | 
			
		||||
            info.taskThrottle = (int) (m_PacketQueue.TaskThrottle.Throttle / multiplier);
 | 
			
		||||
            info.assetThrottle = (int) (m_PacketQueue.AssetThrottle.Throttle / multiplier);
 | 
			
		||||
            info.textureThrottle = (int) (m_PacketQueue.TextureThrottle.Throttle / multiplier);
 | 
			
		||||
            info.totalThrottle = (int) (m_PacketQueue.TotalThrottle.Throttle / multiplier);
 | 
			
		||||
 | 
			
		||||
            return info;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SetClientInfo(ClientInfo info)
 | 
			
		||||
        {
 | 
			
		||||
            m_PendingAcksMap = info.pendingAcks;
 | 
			
		||||
            m_PendingAcks = new List<uint>(m_PendingAcksMap.Keys);
 | 
			
		||||
            m_NeedAck = new Dictionary<uint, LLQueItem>();
 | 
			
		||||
 | 
			
		||||
            Packet packet = null;
 | 
			
		||||
            int packetEnd = 0;
 | 
			
		||||
            byte[] zero = new byte[3000];
 | 
			
		||||
 | 
			
		||||
            foreach (uint key in info.needAck.Keys)
 | 
			
		||||
            {
 | 
			
		||||
                byte[] buff = info.needAck[key];
 | 
			
		||||
                packetEnd = buff.Length - 1;
 | 
			
		||||
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    packet = PacketPool.Instance.GetPacket(buff, ref packetEnd, zero);
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception)
 | 
			
		||||
                {
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                LLQueItem item = new LLQueItem();
 | 
			
		||||
                item.Packet = packet;
 | 
			
		||||
                item.Incoming = false;
 | 
			
		||||
                item.throttleType = 0;
 | 
			
		||||
                item.TickCount = Environment.TickCount;
 | 
			
		||||
                item.Identifier = 0;
 | 
			
		||||
                item.Resends = 0;
 | 
			
		||||
                item.Length = packet.Length;
 | 
			
		||||
                item.Sequence = packet.Header.Sequence;
 | 
			
		||||
                m_NeedAck.Add(key, item);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            m_Sequence = info.sequence;
 | 
			
		||||
 | 
			
		||||
            m_PacketQueue.ResendThrottle.Throttle = info.resendThrottle;
 | 
			
		||||
            m_PacketQueue.LandThrottle.Throttle = info.landThrottle;
 | 
			
		||||
            m_PacketQueue.WindThrottle.Throttle = info.windThrottle;
 | 
			
		||||
            m_PacketQueue.CloudThrottle.Throttle = info.cloudThrottle;
 | 
			
		||||
            m_PacketQueue.TaskThrottle.Throttle = info.taskThrottle;
 | 
			
		||||
            m_PacketQueue.AssetThrottle.Throttle = info.assetThrottle;
 | 
			
		||||
            m_PacketQueue.TextureThrottle.Throttle = info.textureThrottle;
 | 
			
		||||
            m_PacketQueue.TotalThrottle.Throttle = info.totalThrottle;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void AddImportantPacket(PacketType type)
 | 
			
		||||
        {
 | 
			
		||||
            if (m_ImportantPackets.Contains(type))
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            m_ImportantPackets.Add(type);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void RemoveImportantPacket(PacketType type)
 | 
			
		||||
        {
 | 
			
		||||
            if (!m_ImportantPackets.Contains(type))
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            m_ImportantPackets.Remove(type);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void DropResend(Object id)
 | 
			
		||||
        {
 | 
			
		||||
            LLQueItem d = null;
 | 
			
		||||
 | 
			
		||||
            foreach (LLQueItem data in m_NeedAck.Values)
 | 
			
		||||
            {
 | 
			
		||||
                if (data.Identifier != null && data.Identifier == id)
 | 
			
		||||
                {
 | 
			
		||||
                    d = data;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (null == d) return;
 | 
			
		||||
 | 
			
		||||
            m_NeedAck.Remove(d.Packet.Header.Sequence);
 | 
			
		||||
            m_PacketQueue.Cancel(d.Sequence);
 | 
			
		||||
            PacketPool.Instance.ReturnPacket(d.Packet);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void TriggerOnPacketDrop(Packet packet, Object id)
 | 
			
		||||
        {
 | 
			
		||||
            PacketDrop handlerPacketDrop = OnPacketDrop;
 | 
			
		||||
 | 
			
		||||
            if (handlerPacketDrop == null)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            handlerPacketDrop(packet, id);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void TriggerOnQueueEmpty(ThrottleOutPacketType queue)
 | 
			
		||||
        {
 | 
			
		||||
            QueueEmpty handlerQueueEmpty = OnQueueEmpty;
 | 
			
		||||
 | 
			
		||||
            if (handlerQueueEmpty != null)
 | 
			
		||||
                handlerQueueEmpty(queue);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Convert the packet to bytes and stuff it onto the send queue
 | 
			
		||||
        //
 | 
			
		||||
        public void ProcessOutPacket(LLQueItem item)
 | 
			
		||||
        {
 | 
			
		||||
            Packet packet = item.Packet;
 | 
			
		||||
 | 
			
		||||
            // Assign sequence number here to prevent out of order packets
 | 
			
		||||
            if (packet.Header.Sequence == 0)
 | 
			
		||||
            {
 | 
			
		||||
                lock (m_NeedAck)
 | 
			
		||||
                {
 | 
			
		||||
                    packet.Header.Sequence = NextPacketSequenceNumber();
 | 
			
		||||
                    item.Sequence = packet.Header.Sequence;
 | 
			
		||||
                    item.TickCount = Environment.TickCount;
 | 
			
		||||
 | 
			
		||||
                    // We want to see that packet arrive if it's reliable
 | 
			
		||||
                    if (packet.Header.Reliable)
 | 
			
		||||
                    {
 | 
			
		||||
                        m_UnackedBytes += item.Length;
 | 
			
		||||
 | 
			
		||||
                        // Keep track of when this packet was sent out
 | 
			
		||||
                        item.TickCount = Environment.TickCount;
 | 
			
		||||
 | 
			
		||||
                        m_NeedAck[packet.Header.Sequence] = item;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // If we sent a killpacket
 | 
			
		||||
            if (packet is KillPacket)
 | 
			
		||||
                Abort();
 | 
			
		||||
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                // If this packet has been reused/returned, the ToBytes
 | 
			
		||||
                // will blow up in our face.
 | 
			
		||||
                // Fail gracefully.
 | 
			
		||||
                //
 | 
			
		||||
 | 
			
		||||
                // Actually make the byte array and send it
 | 
			
		||||
                byte[] sendbuffer = item.Packet.ToBytes();
 | 
			
		||||
 | 
			
		||||
                if (packet.Header.Zerocoded)
 | 
			
		||||
                {
 | 
			
		||||
                    int packetsize = Helpers.ZeroEncode(sendbuffer,
 | 
			
		||||
                            sendbuffer.Length, m_ZeroOutBuffer);
 | 
			
		||||
                    m_PacketServer.SendPacketTo(m_ZeroOutBuffer, packetsize,
 | 
			
		||||
                            SocketFlags.None, m_Client.CircuitCode);
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    // Need some extra space in case we need to add proxy
 | 
			
		||||
                    // information to the message later
 | 
			
		||||
                    Buffer.BlockCopy(sendbuffer, 0, m_ZeroOutBuffer, 0,
 | 
			
		||||
                            sendbuffer.Length);
 | 
			
		||||
                    m_PacketServer.SendPacketTo(m_ZeroOutBuffer,
 | 
			
		||||
                            sendbuffer.Length, SocketFlags.None, m_Client.CircuitCode);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            catch (NullReferenceException)
 | 
			
		||||
            {
 | 
			
		||||
                m_log.Error("[PACKET]: Detected reuse of a returned packet");
 | 
			
		||||
                m_PacketQueue.Cancel(item.Sequence);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // If this is a reliable packet, we are still holding a ref
 | 
			
		||||
            // Dont't return in that case
 | 
			
		||||
            //
 | 
			
		||||
            if (!packet.Header.Reliable)
 | 
			
		||||
            {
 | 
			
		||||
                m_PacketQueue.Cancel(item.Sequence);
 | 
			
		||||
                PacketPool.Instance.ReturnPacket(packet);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void Abort()
 | 
			
		||||
        {
 | 
			
		||||
            m_PacketQueue.Close();
 | 
			
		||||
            Thread.CurrentThread.Abort();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public int GetQueueCount(ThrottleOutPacketType queue)
 | 
			
		||||
        {
 | 
			
		||||
            return m_PacketQueue.GetQueueCount(queue);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,742 +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.Reflection;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Timers;
 | 
			
		||||
using log4net;
 | 
			
		||||
using OpenMetaverse;
 | 
			
		||||
using OpenSim.Framework;
 | 
			
		||||
using OpenSim.Framework.Statistics;
 | 
			
		||||
using OpenSim.Framework.Statistics.Interfaces;
 | 
			
		||||
using Timer=System.Timers.Timer;
 | 
			
		||||
 | 
			
		||||
namespace OpenSim.Region.ClientStack.LindenUDP
 | 
			
		||||
{
 | 
			
		||||
    public class LLPacketQueue : IPullStatsProvider, IDisposable
 | 
			
		||||
    {
 | 
			
		||||
        private static readonly ILog m_log
 | 
			
		||||
            = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Is queueing enabled at all?
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        private bool m_enabled = true;
 | 
			
		||||
 | 
			
		||||
        private OpenSim.Framework.BlockingQueue<LLQueItem> SendQueue;
 | 
			
		||||
 | 
			
		||||
        private Queue<LLQueItem> IncomingPacketQueue;
 | 
			
		||||
        private Queue<LLQueItem> OutgoingPacketQueue;
 | 
			
		||||
        private Queue<LLQueItem> ResendOutgoingPacketQueue;
 | 
			
		||||
        private Queue<LLQueItem> LandOutgoingPacketQueue;
 | 
			
		||||
        private Queue<LLQueItem> WindOutgoingPacketQueue;
 | 
			
		||||
        private Queue<LLQueItem> CloudOutgoingPacketQueue;
 | 
			
		||||
        private Queue<LLQueItem> TaskOutgoingPacketQueue;
 | 
			
		||||
        private Queue<LLQueItem> TaskLowpriorityPacketQueue;
 | 
			
		||||
        private Queue<LLQueItem> TextureOutgoingPacketQueue;
 | 
			
		||||
        private Queue<LLQueItem> AssetOutgoingPacketQueue;
 | 
			
		||||
 | 
			
		||||
        private List<ThrottleOutPacketType> Empty = new List<ThrottleOutPacketType>();
 | 
			
		||||
                // m_log.Info("[THROTTLE]: Entering Throttle");
 | 
			
		||||
        // private Dictionary<uint, uint> PendingAcks = new Dictionary<uint, uint>();
 | 
			
		||||
        // private Dictionary<uint, Packet> NeedAck = new Dictionary<uint, Packet>();
 | 
			
		||||
 | 
			
		||||
        // All throttle times and number of bytes are calculated by dividing by this value
 | 
			
		||||
        // This value also determines how many times per throttletimems the timer will run
 | 
			
		||||
        // If throttleimems is 1000 ms, then the timer will fire every 1000/7 milliseconds
 | 
			
		||||
 | 
			
		||||
        private float throttleMultiplier = 2.0f; // Default value really doesn't matter.
 | 
			
		||||
        private int throttleTimeDivisor = 7;
 | 
			
		||||
 | 
			
		||||
        private int throttletimems = 1000;
 | 
			
		||||
 | 
			
		||||
        internal LLPacketThrottle ResendThrottle;
 | 
			
		||||
        internal LLPacketThrottle LandThrottle;
 | 
			
		||||
        internal LLPacketThrottle WindThrottle;
 | 
			
		||||
        internal LLPacketThrottle CloudThrottle;
 | 
			
		||||
        internal LLPacketThrottle TaskThrottle;
 | 
			
		||||
        internal LLPacketThrottle AssetThrottle;
 | 
			
		||||
        internal LLPacketThrottle TextureThrottle;
 | 
			
		||||
        internal LLPacketThrottle TotalThrottle;
 | 
			
		||||
        
 | 
			
		||||
        private Dictionary<uint,int> contents = new Dictionary<uint, int>();
 | 
			
		||||
 | 
			
		||||
        // private long LastThrottle;
 | 
			
		||||
        // private long ThrottleInterval;
 | 
			
		||||
        private Timer throttleTimer;
 | 
			
		||||
 | 
			
		||||
        private UUID m_agentId;
 | 
			
		||||
 | 
			
		||||
        public event QueueEmpty OnQueueEmpty;
 | 
			
		||||
 | 
			
		||||
        public LLPacketQueue(UUID agentId, ClientStackUserSettings userSettings)
 | 
			
		||||
        {
 | 
			
		||||
            // While working on this, the BlockingQueue had me fooled for a bit.
 | 
			
		||||
            // The Blocking queue causes the thread to stop until there's something
 | 
			
		||||
            // in it to process.  it's an on-purpose threadlock though because
 | 
			
		||||
            // without it, the clientloop will suck up all sim resources.
 | 
			
		||||
 | 
			
		||||
            SendQueue = new OpenSim.Framework.BlockingQueue<LLQueItem>();
 | 
			
		||||
 | 
			
		||||
            IncomingPacketQueue = new Queue<LLQueItem>();
 | 
			
		||||
            OutgoingPacketQueue = new Queue<LLQueItem>();
 | 
			
		||||
            ResendOutgoingPacketQueue = new Queue<LLQueItem>();
 | 
			
		||||
            LandOutgoingPacketQueue = new Queue<LLQueItem>();
 | 
			
		||||
            WindOutgoingPacketQueue = new Queue<LLQueItem>();
 | 
			
		||||
            CloudOutgoingPacketQueue = new Queue<LLQueItem>();
 | 
			
		||||
            TaskOutgoingPacketQueue = new Queue<LLQueItem>();
 | 
			
		||||
            TaskLowpriorityPacketQueue = new Queue<LLQueItem>();
 | 
			
		||||
            TextureOutgoingPacketQueue = new Queue<LLQueItem>();
 | 
			
		||||
            AssetOutgoingPacketQueue = new Queue<LLQueItem>();
 | 
			
		||||
 | 
			
		||||
            // Store the throttle multiplier for posterity.
 | 
			
		||||
            throttleMultiplier = userSettings.ClientThrottleMultipler;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            int throttleMaxBPS = 1500000;
 | 
			
		||||
            if (userSettings.TotalThrottleSettings != null)
 | 
			
		||||
                throttleMaxBPS = userSettings.TotalThrottleSettings.Max;
 | 
			
		||||
 | 
			
		||||
            // Set up the throttle classes (min, max, current) in bits per second
 | 
			
		||||
            ResendThrottle = new LLPacketThrottle(5000, throttleMaxBPS / 15, 16000, userSettings.ClientThrottleMultipler);
 | 
			
		||||
            LandThrottle = new LLPacketThrottle(1000, throttleMaxBPS / 15, 2000, userSettings.ClientThrottleMultipler);
 | 
			
		||||
            WindThrottle = new LLPacketThrottle(0, throttleMaxBPS / 15, 0, userSettings.ClientThrottleMultipler);
 | 
			
		||||
            CloudThrottle = new LLPacketThrottle(0, throttleMaxBPS / 15, 0, userSettings.ClientThrottleMultipler);
 | 
			
		||||
            TaskThrottle = new LLPacketThrottle(1000, throttleMaxBPS / 2, 3000, userSettings.ClientThrottleMultipler);
 | 
			
		||||
            AssetThrottle = new LLPacketThrottle(1000, throttleMaxBPS / 2, 1000, userSettings.ClientThrottleMultipler);
 | 
			
		||||
            TextureThrottle = new LLPacketThrottle(1000, throttleMaxBPS / 2, 4000, userSettings.ClientThrottleMultipler);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            // Total Throttle trumps all - it is the number of bits in total that are allowed to go out per second.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            ThrottleSettings totalThrottleSettings = userSettings.TotalThrottleSettings;
 | 
			
		||||
            if (null == totalThrottleSettings)
 | 
			
		||||
            {
 | 
			
		||||
                totalThrottleSettings = new ThrottleSettings(0, throttleMaxBPS, 28000);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            TotalThrottle
 | 
			
		||||
                = new LLPacketThrottle(
 | 
			
		||||
                    totalThrottleSettings.Min, totalThrottleSettings.Max, totalThrottleSettings.Current,
 | 
			
		||||
                    userSettings.ClientThrottleMultipler);
 | 
			
		||||
 | 
			
		||||
            throttleTimer = new Timer((int)(throttletimems / throttleTimeDivisor));
 | 
			
		||||
            throttleTimer.Elapsed += ThrottleTimerElapsed;
 | 
			
		||||
            throttleTimer.Start();
 | 
			
		||||
 | 
			
		||||
            // TIMERS needed for this
 | 
			
		||||
            // LastThrottle = DateTime.Now.Ticks;
 | 
			
		||||
            // ThrottleInterval = (long)(throttletimems/throttleTimeDivisor);
 | 
			
		||||
 | 
			
		||||
            m_agentId = agentId;
 | 
			
		||||
 | 
			
		||||
            if (StatsManager.SimExtraStats != null)
 | 
			
		||||
            {
 | 
			
		||||
                StatsManager.SimExtraStats.RegisterPacketQueueStatsProvider(m_agentId, this);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* STANDARD QUEUE MANIPULATION INTERFACES */
 | 
			
		||||
 | 
			
		||||
        public void Enqueue(LLQueItem item)
 | 
			
		||||
        {
 | 
			
		||||
            if (!m_enabled)
 | 
			
		||||
            {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            // We could micro lock, but that will tend to actually
 | 
			
		||||
            // probably be worse than just synchronizing on SendQueue
 | 
			
		||||
 | 
			
		||||
            if (item == null)
 | 
			
		||||
            {
 | 
			
		||||
                SendQueue.Enqueue(item);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (item.Incoming)
 | 
			
		||||
            {
 | 
			
		||||
                SendQueue.PriorityEnqueue(item);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (item.Sequence != 0)
 | 
			
		||||
                lock (contents)
 | 
			
		||||
                {
 | 
			
		||||
                    if (contents.ContainsKey(item.Sequence))
 | 
			
		||||
                        contents[item.Sequence] += 1;
 | 
			
		||||
                    else
 | 
			
		||||
                        contents.Add(item.Sequence, 1);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
            lock (this)
 | 
			
		||||
            {
 | 
			
		||||
                switch (item.throttleType & ThrottleOutPacketType.TypeMask)
 | 
			
		||||
                {
 | 
			
		||||
                    case ThrottleOutPacketType.Resend:
 | 
			
		||||
                        ThrottleCheck(ref ResendThrottle, ref ResendOutgoingPacketQueue, item, ThrottleOutPacketType.Resend);
 | 
			
		||||
                        break;
 | 
			
		||||
                    case ThrottleOutPacketType.Texture:
 | 
			
		||||
                        ThrottleCheck(ref TextureThrottle, ref TextureOutgoingPacketQueue, item, ThrottleOutPacketType.Texture);
 | 
			
		||||
                        break;
 | 
			
		||||
                    case ThrottleOutPacketType.Task:
 | 
			
		||||
                        if ((item.throttleType & ThrottleOutPacketType.LowPriority) != 0)
 | 
			
		||||
                            ThrottleCheck(ref TaskThrottle, ref TaskLowpriorityPacketQueue, item, ThrottleOutPacketType.Task);
 | 
			
		||||
                        else
 | 
			
		||||
                            ThrottleCheck(ref TaskThrottle, ref TaskOutgoingPacketQueue, item, ThrottleOutPacketType.Task);
 | 
			
		||||
                        break;
 | 
			
		||||
                    case ThrottleOutPacketType.Land:
 | 
			
		||||
                        ThrottleCheck(ref LandThrottle, ref LandOutgoingPacketQueue, item, ThrottleOutPacketType.Land);
 | 
			
		||||
                        break;
 | 
			
		||||
                    case ThrottleOutPacketType.Asset:
 | 
			
		||||
                        ThrottleCheck(ref AssetThrottle, ref AssetOutgoingPacketQueue, item, ThrottleOutPacketType.Asset);
 | 
			
		||||
                        break;
 | 
			
		||||
                    case ThrottleOutPacketType.Cloud:
 | 
			
		||||
                        ThrottleCheck(ref CloudThrottle, ref CloudOutgoingPacketQueue, item, ThrottleOutPacketType.Cloud);
 | 
			
		||||
                        break;
 | 
			
		||||
                    case ThrottleOutPacketType.Wind:
 | 
			
		||||
                        ThrottleCheck(ref WindThrottle, ref WindOutgoingPacketQueue, item, ThrottleOutPacketType.Wind);
 | 
			
		||||
                        break;
 | 
			
		||||
 | 
			
		||||
                    default:
 | 
			
		||||
                        // Acknowledgements and other such stuff should go directly to the blocking Queue
 | 
			
		||||
                        // Throttling them may and likely 'will' be problematic
 | 
			
		||||
                        SendQueue.PriorityEnqueue(item);
 | 
			
		||||
                        break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public LLQueItem Dequeue()
 | 
			
		||||
        {
 | 
			
		||||
            while (true)
 | 
			
		||||
            {
 | 
			
		||||
                LLQueItem item = SendQueue.Dequeue();
 | 
			
		||||
                if (item == null)
 | 
			
		||||
                    return null;
 | 
			
		||||
                if (item.Incoming)
 | 
			
		||||
                    return item;
 | 
			
		||||
                item.TickCount = System.Environment.TickCount;
 | 
			
		||||
                if (item.Sequence == 0)
 | 
			
		||||
                    return item;
 | 
			
		||||
                lock (contents)
 | 
			
		||||
                {
 | 
			
		||||
                    if (contents.ContainsKey(item.Sequence))
 | 
			
		||||
                    {
 | 
			
		||||
                        if (contents[item.Sequence] == 1)
 | 
			
		||||
                            contents.Remove(item.Sequence);
 | 
			
		||||
                        else
 | 
			
		||||
                            contents[item.Sequence] -= 1;
 | 
			
		||||
                        return item;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Cancel(uint sequence)
 | 
			
		||||
        {
 | 
			
		||||
            lock (contents) contents.Remove(sequence);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public bool Contains(uint sequence)
 | 
			
		||||
        {
 | 
			
		||||
            lock (contents) return contents.ContainsKey(sequence);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Flush()
 | 
			
		||||
        {
 | 
			
		||||
            lock (this)
 | 
			
		||||
            {
 | 
			
		||||
                // These categories do not contain transactional packets so we can safely drop any pending data in them
 | 
			
		||||
                LandOutgoingPacketQueue.Clear();
 | 
			
		||||
                WindOutgoingPacketQueue.Clear();
 | 
			
		||||
                CloudOutgoingPacketQueue.Clear();
 | 
			
		||||
                TextureOutgoingPacketQueue.Clear();
 | 
			
		||||
                AssetOutgoingPacketQueue.Clear();
 | 
			
		||||
 | 
			
		||||
                // Now comes the fun part..   we dump all remaining resend and task packets into the send queue
 | 
			
		||||
                while (ResendOutgoingPacketQueue.Count > 0 || TaskOutgoingPacketQueue.Count > 0 || TaskLowpriorityPacketQueue.Count > 0)
 | 
			
		||||
                {
 | 
			
		||||
                    if (ResendOutgoingPacketQueue.Count > 0)
 | 
			
		||||
                        SendQueue.Enqueue(ResendOutgoingPacketQueue.Dequeue());
 | 
			
		||||
 | 
			
		||||
                    if (TaskOutgoingPacketQueue.Count > 0)
 | 
			
		||||
                        SendQueue.PriorityEnqueue(TaskOutgoingPacketQueue.Dequeue());
 | 
			
		||||
 | 
			
		||||
                    if (TaskLowpriorityPacketQueue.Count > 0)
 | 
			
		||||
                        SendQueue.Enqueue(TaskLowpriorityPacketQueue.Dequeue());
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void WipeClean()
 | 
			
		||||
        {
 | 
			
		||||
            lock (this)
 | 
			
		||||
            {
 | 
			
		||||
                ResendOutgoingPacketQueue.Clear();
 | 
			
		||||
                LandOutgoingPacketQueue.Clear();
 | 
			
		||||
                WindOutgoingPacketQueue.Clear();
 | 
			
		||||
                CloudOutgoingPacketQueue.Clear();
 | 
			
		||||
                TaskOutgoingPacketQueue.Clear();
 | 
			
		||||
                TaskLowpriorityPacketQueue.Clear();
 | 
			
		||||
                TextureOutgoingPacketQueue.Clear();
 | 
			
		||||
                AssetOutgoingPacketQueue.Clear();
 | 
			
		||||
                SendQueue.Clear();
 | 
			
		||||
                lock (contents) contents.Clear();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Close()
 | 
			
		||||
        {
 | 
			
		||||
            Dispose();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Dispose()
 | 
			
		||||
        {
 | 
			
		||||
            Flush();
 | 
			
		||||
            WipeClean(); // I'm sure there's a dirty joke in here somewhere. -AFrisby
 | 
			
		||||
 | 
			
		||||
            m_enabled = false;
 | 
			
		||||
            throttleTimer.Stop();
 | 
			
		||||
            throttleTimer.Close();
 | 
			
		||||
 | 
			
		||||
            if (StatsManager.SimExtraStats != null)
 | 
			
		||||
            {
 | 
			
		||||
                StatsManager.SimExtraStats.DeregisterPacketQueueStatsProvider(m_agentId);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ResetCounters()
 | 
			
		||||
        {
 | 
			
		||||
            ResendThrottle.Reset();
 | 
			
		||||
            LandThrottle.Reset();
 | 
			
		||||
            WindThrottle.Reset();
 | 
			
		||||
            CloudThrottle.Reset();
 | 
			
		||||
            TaskThrottle.Reset();
 | 
			
		||||
            AssetThrottle.Reset();
 | 
			
		||||
            TextureThrottle.Reset();
 | 
			
		||||
            TotalThrottle.Reset();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private bool PacketsWaiting()
 | 
			
		||||
        {
 | 
			
		||||
            return (ResendOutgoingPacketQueue.Count > 0 ||
 | 
			
		||||
                    LandOutgoingPacketQueue.Count > 0 ||
 | 
			
		||||
                    WindOutgoingPacketQueue.Count > 0 ||
 | 
			
		||||
                    CloudOutgoingPacketQueue.Count > 0 ||
 | 
			
		||||
                    TaskOutgoingPacketQueue.Count > 0 ||
 | 
			
		||||
                    TaskLowpriorityPacketQueue.Count > 0 ||
 | 
			
		||||
                    AssetOutgoingPacketQueue.Count > 0 ||
 | 
			
		||||
                    TextureOutgoingPacketQueue.Count > 0);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void ProcessThrottle()
 | 
			
		||||
        {
 | 
			
		||||
            // I was considering this..   Will an event fire if the thread it's on is blocked?
 | 
			
		||||
 | 
			
		||||
            // Then I figured out..  it doesn't really matter..  because this thread won't be blocked for long
 | 
			
		||||
            // The General overhead of the UDP protocol gets sent to the queue un-throttled by this
 | 
			
		||||
            // so This'll pick up about around the right time.
 | 
			
		||||
 | 
			
		||||
            int MaxThrottleLoops = 4550; // 50*7 packets can be dequeued at once.
 | 
			
		||||
            int throttleLoops = 0;
 | 
			
		||||
            List<ThrottleOutPacketType> e;
 | 
			
		||||
 | 
			
		||||
            // We're going to dequeue all of the saved up packets until
 | 
			
		||||
            // we've hit the throttle limit or there's no more packets to send
 | 
			
		||||
            lock (this)
 | 
			
		||||
            {
 | 
			
		||||
                // this variable will be true if there was work done in the last execution of the
 | 
			
		||||
                // loop, since each pass through the loop checks the queue length, we no longer 
 | 
			
		||||
                // need the check on entering the loop
 | 
			
		||||
                bool qchanged = true;
 | 
			
		||||
                
 | 
			
		||||
                ResetCounters();
 | 
			
		||||
 | 
			
		||||
                while (TotalThrottle.UnderLimit() && qchanged && throttleLoops <= MaxThrottleLoops)
 | 
			
		||||
                {
 | 
			
		||||
                    qchanged = false; // We will break out of the loop if no work was accomplished
 | 
			
		||||
 | 
			
		||||
                    throttleLoops++;
 | 
			
		||||
                    //Now comes the fun part..   we dump all our elements into m_packetQueue that we've saved up.
 | 
			
		||||
                    if ((ResendOutgoingPacketQueue.Count > 0) && ResendThrottle.UnderLimit())
 | 
			
		||||
                    {
 | 
			
		||||
                        LLQueItem qpack = ResendOutgoingPacketQueue.Dequeue();
 | 
			
		||||
 | 
			
		||||
                        SendQueue.Enqueue(qpack);
 | 
			
		||||
                        TotalThrottle.AddBytes(qpack.Length);
 | 
			
		||||
                        ResendThrottle.AddBytes(qpack.Length);
 | 
			
		||||
                        
 | 
			
		||||
                        qchanged = true;
 | 
			
		||||
                    }
 | 
			
		||||
                    
 | 
			
		||||
                    if ((LandOutgoingPacketQueue.Count > 0) && LandThrottle.UnderLimit())
 | 
			
		||||
                    {
 | 
			
		||||
                        LLQueItem qpack = LandOutgoingPacketQueue.Dequeue();
 | 
			
		||||
 | 
			
		||||
                        SendQueue.Enqueue(qpack);
 | 
			
		||||
                        TotalThrottle.AddBytes(qpack.Length);
 | 
			
		||||
                        LandThrottle.AddBytes(qpack.Length);
 | 
			
		||||
                        qchanged = true;
 | 
			
		||||
 | 
			
		||||
                        if (LandOutgoingPacketQueue.Count == 0 && !Empty.Contains(ThrottleOutPacketType.Land))
 | 
			
		||||
                            Empty.Add(ThrottleOutPacketType.Land);
 | 
			
		||||
                    }
 | 
			
		||||
                    
 | 
			
		||||
                    if ((WindOutgoingPacketQueue.Count > 0) && WindThrottle.UnderLimit())
 | 
			
		||||
                    {
 | 
			
		||||
                        LLQueItem qpack = WindOutgoingPacketQueue.Dequeue();
 | 
			
		||||
 | 
			
		||||
                        SendQueue.Enqueue(qpack);
 | 
			
		||||
                        TotalThrottle.AddBytes(qpack.Length);
 | 
			
		||||
                        WindThrottle.AddBytes(qpack.Length);
 | 
			
		||||
                        qchanged = true;
 | 
			
		||||
 | 
			
		||||
                        if (WindOutgoingPacketQueue.Count == 0 && !Empty.Contains(ThrottleOutPacketType.Wind))
 | 
			
		||||
                            Empty.Add(ThrottleOutPacketType.Wind);
 | 
			
		||||
                    }
 | 
			
		||||
                    
 | 
			
		||||
                    if ((CloudOutgoingPacketQueue.Count > 0) && CloudThrottle.UnderLimit())
 | 
			
		||||
                    {
 | 
			
		||||
                        LLQueItem qpack = CloudOutgoingPacketQueue.Dequeue();
 | 
			
		||||
 | 
			
		||||
                        SendQueue.Enqueue(qpack);
 | 
			
		||||
                        TotalThrottle.AddBytes(qpack.Length);
 | 
			
		||||
                        CloudThrottle.AddBytes(qpack.Length);
 | 
			
		||||
                        qchanged = true;
 | 
			
		||||
 | 
			
		||||
                        if (CloudOutgoingPacketQueue.Count == 0 && !Empty.Contains(ThrottleOutPacketType.Cloud))
 | 
			
		||||
                            Empty.Add(ThrottleOutPacketType.Cloud);
 | 
			
		||||
                    }
 | 
			
		||||
                    
 | 
			
		||||
                    if ((TaskOutgoingPacketQueue.Count > 0 || TaskLowpriorityPacketQueue.Count > 0) && TaskThrottle.UnderLimit())
 | 
			
		||||
                    {
 | 
			
		||||
                        LLQueItem qpack;
 | 
			
		||||
                        if (TaskOutgoingPacketQueue.Count > 0)
 | 
			
		||||
                        {
 | 
			
		||||
                            qpack = TaskOutgoingPacketQueue.Dequeue();
 | 
			
		||||
                            SendQueue.PriorityEnqueue(qpack);
 | 
			
		||||
                        }
 | 
			
		||||
                        else
 | 
			
		||||
                        {
 | 
			
		||||
                            qpack = TaskLowpriorityPacketQueue.Dequeue();
 | 
			
		||||
                            SendQueue.Enqueue(qpack);
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        TotalThrottle.AddBytes(qpack.Length);
 | 
			
		||||
                        TaskThrottle.AddBytes(qpack.Length);
 | 
			
		||||
                        qchanged = true;
 | 
			
		||||
 | 
			
		||||
                        if (TaskOutgoingPacketQueue.Count == 0 && TaskLowpriorityPacketQueue.Count == 0 && !Empty.Contains(ThrottleOutPacketType.Task))
 | 
			
		||||
                            Empty.Add(ThrottleOutPacketType.Task);
 | 
			
		||||
                    }
 | 
			
		||||
                    
 | 
			
		||||
                    if ((TextureOutgoingPacketQueue.Count > 0) && TextureThrottle.UnderLimit())
 | 
			
		||||
                    {
 | 
			
		||||
                        LLQueItem qpack = TextureOutgoingPacketQueue.Dequeue();
 | 
			
		||||
 | 
			
		||||
                        SendQueue.Enqueue(qpack);
 | 
			
		||||
                        TotalThrottle.AddBytes(qpack.Length);
 | 
			
		||||
                        TextureThrottle.AddBytes(qpack.Length);
 | 
			
		||||
                        qchanged = true;
 | 
			
		||||
 | 
			
		||||
                        if (TextureOutgoingPacketQueue.Count == 0 && !Empty.Contains(ThrottleOutPacketType.Texture))
 | 
			
		||||
                            Empty.Add(ThrottleOutPacketType.Texture);
 | 
			
		||||
                    }
 | 
			
		||||
                    
 | 
			
		||||
                    if ((AssetOutgoingPacketQueue.Count > 0) && AssetThrottle.UnderLimit())
 | 
			
		||||
                    {
 | 
			
		||||
                        LLQueItem qpack = AssetOutgoingPacketQueue.Dequeue();
 | 
			
		||||
 | 
			
		||||
                        SendQueue.Enqueue(qpack);
 | 
			
		||||
                        TotalThrottle.AddBytes(qpack.Length);
 | 
			
		||||
                        AssetThrottle.AddBytes(qpack.Length);
 | 
			
		||||
                        qchanged = true;
 | 
			
		||||
 | 
			
		||||
                        if (AssetOutgoingPacketQueue.Count == 0 && !Empty.Contains(ThrottleOutPacketType.Asset))
 | 
			
		||||
                            Empty.Add(ThrottleOutPacketType.Asset);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                // m_log.Info("[THROTTLE]: Processed " + throttleLoops + " packets");
 | 
			
		||||
 | 
			
		||||
                e = new List<ThrottleOutPacketType>(Empty);
 | 
			
		||||
                Empty.Clear();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            foreach (ThrottleOutPacketType t in e)
 | 
			
		||||
            {
 | 
			
		||||
                if (GetQueueCount(t) == 0)
 | 
			
		||||
                    TriggerOnQueueEmpty(t);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void TriggerOnQueueEmpty(ThrottleOutPacketType queue)
 | 
			
		||||
        {
 | 
			
		||||
            QueueEmpty handlerQueueEmpty = OnQueueEmpty;
 | 
			
		||||
 | 
			
		||||
            if (handlerQueueEmpty != null)
 | 
			
		||||
                handlerQueueEmpty(queue);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThrottleTimerElapsed(object sender, ElapsedEventArgs e)
 | 
			
		||||
        {
 | 
			
		||||
            // just to change the signature, and that ProcessThrottle
 | 
			
		||||
            // will be used elsewhere possibly
 | 
			
		||||
            ProcessThrottle();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThrottleCheck(ref LLPacketThrottle throttle, ref Queue<LLQueItem> q, LLQueItem item, ThrottleOutPacketType itemType)
 | 
			
		||||
        {
 | 
			
		||||
            // 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()))
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    Monitor.Enter(this);
 | 
			
		||||
                    throttle.AddBytes(item.Length);
 | 
			
		||||
                    TotalThrottle.AddBytes(item.Length);
 | 
			
		||||
                    SendQueue.Enqueue(item);
 | 
			
		||||
                    lock (this)
 | 
			
		||||
                    {
 | 
			
		||||
                        if (!Empty.Contains(itemType))
 | 
			
		||||
                            Empty.Add(itemType);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception e)
 | 
			
		||||
                {
 | 
			
		||||
                    // Probably a serialization exception
 | 
			
		||||
                    m_log.WarnFormat("ThrottleCheck: {0}", e.ToString());
 | 
			
		||||
                }
 | 
			
		||||
                finally
 | 
			
		||||
                {
 | 
			
		||||
                    Monitor.Pulse(this);
 | 
			
		||||
                    Monitor.Exit(this);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                q.Enqueue(item);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static int ScaleThrottle(int value, int curmax, int newmax)
 | 
			
		||||
        {
 | 
			
		||||
            return (int)((value / (float)curmax) * newmax);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public byte[] GetThrottlesPacked(float multiplier)
 | 
			
		||||
        {
 | 
			
		||||
            int singlefloat = 4;
 | 
			
		||||
            float tResend = ResendThrottle.Throttle*multiplier;
 | 
			
		||||
            float tLand = LandThrottle.Throttle*multiplier;
 | 
			
		||||
            float tWind = WindThrottle.Throttle*multiplier;
 | 
			
		||||
            float tCloud = CloudThrottle.Throttle*multiplier;
 | 
			
		||||
            float tTask = TaskThrottle.Throttle*multiplier;
 | 
			
		||||
            float tTexture = TextureThrottle.Throttle*multiplier;
 | 
			
		||||
            float tAsset = AssetThrottle.Throttle*multiplier;
 | 
			
		||||
 | 
			
		||||
            byte[] throttles = new byte[singlefloat*7];
 | 
			
		||||
            int i = 0;
 | 
			
		||||
            Buffer.BlockCopy(BitConverter.GetBytes(tResend), 0, throttles, singlefloat*i, singlefloat);
 | 
			
		||||
            i++;
 | 
			
		||||
            Buffer.BlockCopy(BitConverter.GetBytes(tLand), 0, throttles, singlefloat*i, singlefloat);
 | 
			
		||||
            i++;
 | 
			
		||||
            Buffer.BlockCopy(BitConverter.GetBytes(tWind), 0, throttles, singlefloat*i, singlefloat);
 | 
			
		||||
            i++;
 | 
			
		||||
            Buffer.BlockCopy(BitConverter.GetBytes(tCloud), 0, throttles, singlefloat*i, singlefloat);
 | 
			
		||||
            i++;
 | 
			
		||||
            Buffer.BlockCopy(BitConverter.GetBytes(tTask), 0, throttles, singlefloat*i, singlefloat);
 | 
			
		||||
            i++;
 | 
			
		||||
            Buffer.BlockCopy(BitConverter.GetBytes(tTexture), 0, throttles, singlefloat*i, singlefloat);
 | 
			
		||||
            i++;
 | 
			
		||||
            Buffer.BlockCopy(BitConverter.GetBytes(tAsset), 0, throttles, singlefloat*i, singlefloat);
 | 
			
		||||
 | 
			
		||||
            return throttles;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SetThrottleFromClient(byte[] throttle)
 | 
			
		||||
        {
 | 
			
		||||
            // From mantis http://opensimulator.org/mantis/view.php?id=1374
 | 
			
		||||
            // it appears that sometimes we are receiving empty throttle byte arrays.
 | 
			
		||||
            // TODO: Investigate this behaviour
 | 
			
		||||
            if (throttle.Length == 0)
 | 
			
		||||
            {
 | 
			
		||||
                m_log.Warn("[PACKET QUEUE]: SetThrottleFromClient unexpectedly received a throttle byte array containing no elements!");
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            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 OpenMetaverse.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;
 | 
			
		||||
 | 
			
		||||
            /*
 | 
			
		||||
              m_log.Info("[CLIENT]: Client AgentThrottle - Got throttle:resendbits=" + tResend +
 | 
			
		||||
              " landbits=" + tLand +
 | 
			
		||||
              " windbits=" + tWind +
 | 
			
		||||
              " cloudbits=" + tCloud +
 | 
			
		||||
              " taskbits=" + tTask +
 | 
			
		||||
              " texturebits=" + tTexture +
 | 
			
		||||
              " Assetbits=" + tAsset +
 | 
			
		||||
              " Allbits=" + 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(); // DO NOT reset, better to send less for one period than more
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // See IPullStatsProvider
 | 
			
		||||
        public string GetStats()
 | 
			
		||||
        {
 | 
			
		||||
            return string.Format("{0,7} {1,7} {2,7} {3,7} {4,7} {5,7} {6,7} {7,7} {8,7} {9,7}",
 | 
			
		||||
                                 SendQueue.Count(),
 | 
			
		||||
                                 IncomingPacketQueue.Count,
 | 
			
		||||
                                 OutgoingPacketQueue.Count,
 | 
			
		||||
                                 ResendOutgoingPacketQueue.Count,
 | 
			
		||||
                                 LandOutgoingPacketQueue.Count,
 | 
			
		||||
                                 WindOutgoingPacketQueue.Count,
 | 
			
		||||
                                 CloudOutgoingPacketQueue.Count,
 | 
			
		||||
                                 TaskOutgoingPacketQueue.Count,
 | 
			
		||||
                                 TextureOutgoingPacketQueue.Count,
 | 
			
		||||
                                 AssetOutgoingPacketQueue.Count);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public LLQueItem[] GetQueueArray()
 | 
			
		||||
        {
 | 
			
		||||
            return SendQueue.GetQueueArray();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public float ThrottleMultiplier
 | 
			
		||||
        {
 | 
			
		||||
            get { return throttleMultiplier; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public int GetQueueCount(ThrottleOutPacketType queue)
 | 
			
		||||
        {
 | 
			
		||||
            switch (queue)
 | 
			
		||||
            {
 | 
			
		||||
            case ThrottleOutPacketType.Land:
 | 
			
		||||
                return LandOutgoingPacketQueue.Count;
 | 
			
		||||
            case ThrottleOutPacketType.Wind:
 | 
			
		||||
                return WindOutgoingPacketQueue.Count;
 | 
			
		||||
            case ThrottleOutPacketType.Cloud:
 | 
			
		||||
                return CloudOutgoingPacketQueue.Count;
 | 
			
		||||
            case ThrottleOutPacketType.Task:
 | 
			
		||||
                return TaskOutgoingPacketQueue.Count;
 | 
			
		||||
            case ThrottleOutPacketType.Texture:
 | 
			
		||||
                return TextureOutgoingPacketQueue.Count;
 | 
			
		||||
            case ThrottleOutPacketType.Asset:
 | 
			
		||||
                return AssetOutgoingPacketQueue.Count;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,206 +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.Net;
 | 
			
		||||
using System.Net.Sockets;
 | 
			
		||||
using OpenMetaverse;
 | 
			
		||||
using OpenMetaverse.Packets;
 | 
			
		||||
using OpenSim.Framework;
 | 
			
		||||
 | 
			
		||||
namespace OpenSim.Region.ClientStack.LindenUDP
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// This class sets up new client stacks.  It also handles the immediate distribution of incoming packets to
 | 
			
		||||
    /// client stacks
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public class LLPacketServer
 | 
			
		||||
    {
 | 
			
		||||
//        private static readonly log4net.ILog m_log
 | 
			
		||||
//            = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
 | 
			
		||||
 | 
			
		||||
        protected readonly ILLClientStackNetworkHandler m_networkHandler;
 | 
			
		||||
        protected IScene m_scene;
 | 
			
		||||
        
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Tweakable user settings
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        private ClientStackUserSettings m_userSettings;
 | 
			
		||||
 | 
			
		||||
        public LLPacketServer(ILLClientStackNetworkHandler networkHandler, ClientStackUserSettings userSettings)
 | 
			
		||||
        {
 | 
			
		||||
            m_userSettings = userSettings;
 | 
			
		||||
            m_networkHandler = networkHandler;
 | 
			
		||||
            
 | 
			
		||||
            m_networkHandler.RegisterPacketServer(this);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public IScene LocalScene
 | 
			
		||||
        {
 | 
			
		||||
            set { m_scene = value; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Process an incoming packet.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="circuitCode"></param>
 | 
			
		||||
        /// <param name="packet"></param>
 | 
			
		||||
        public virtual void InPacket(uint circuitCode, Packet packet)
 | 
			
		||||
        {
 | 
			
		||||
            m_scene.ClientManager.InPacket(circuitCode, packet);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Create a new client circuit
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="remoteEP"></param>
 | 
			
		||||
        /// <param name="scene"></param>
 | 
			
		||||
        /// <param name="assetCache"></param>
 | 
			
		||||
        /// <param name="packServer"></param>
 | 
			
		||||
        /// <param name="sessionInfo"></param>
 | 
			
		||||
        /// <param name="agentId"></param>
 | 
			
		||||
        /// <param name="sessionId"></param>
 | 
			
		||||
        /// <param name="circuitCode"></param>
 | 
			
		||||
        /// <param name="proxyEP"></param>
 | 
			
		||||
        /// <returns></returns>
 | 
			
		||||
        protected virtual IClientAPI CreateNewCircuit(
 | 
			
		||||
            EndPoint remoteEP, IScene scene, 
 | 
			
		||||
            LLPacketServer packServer, AuthenticateResponse sessionInfo,
 | 
			
		||||
             UUID agentId, UUID sessionId, uint circuitCode, EndPoint proxyEP)
 | 
			
		||||
        {
 | 
			
		||||
            return
 | 
			
		||||
                new LLClientView(
 | 
			
		||||
                     remoteEP, scene, packServer, sessionInfo, agentId, sessionId, circuitCode, proxyEP,
 | 
			
		||||
                     m_userSettings);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Check whether a given client is authorized to connect.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="useCircuit"></param>
 | 
			
		||||
        /// <param name="circuitManager"></param>
 | 
			
		||||
        /// <param name="sessionInfo"></param>
 | 
			
		||||
        /// <returns></returns>
 | 
			
		||||
        public virtual bool IsClientAuthorized(
 | 
			
		||||
            UseCircuitCodePacket useCircuit, AgentCircuitManager circuitManager, out AuthenticateResponse sessionInfo)
 | 
			
		||||
        {
 | 
			
		||||
            UUID agentId = useCircuit.CircuitCode.ID;
 | 
			
		||||
            UUID sessionId = useCircuit.CircuitCode.SessionID;
 | 
			
		||||
            uint circuitCode = useCircuit.CircuitCode.Code;
 | 
			
		||||
 | 
			
		||||
            sessionInfo = circuitManager.AuthenticateSession(sessionId, agentId, circuitCode); 
 | 
			
		||||
 | 
			
		||||
            if (!sessionInfo.Authorised)
 | 
			
		||||
                return false;
 | 
			
		||||
            
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Add a new client circuit.  We assume that is has already passed an authorization check
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="epSender"></param>
 | 
			
		||||
        /// <param name="useCircuit"></param>
 | 
			
		||||
        /// <param name="assetCache"></param>
 | 
			
		||||
        /// <param name="sessionInfo"></param>
 | 
			
		||||
        /// <param name="proxyEP"></param>
 | 
			
		||||
        /// <returns>
 | 
			
		||||
        /// true if a new circuit was created, false if a circuit with the given circuit code already existed
 | 
			
		||||
        /// </returns>
 | 
			
		||||
        public virtual bool AddNewClient(
 | 
			
		||||
            EndPoint epSender, UseCircuitCodePacket useCircuit, 
 | 
			
		||||
            AuthenticateResponse sessionInfo, EndPoint proxyEP)
 | 
			
		||||
        {
 | 
			
		||||
            IClientAPI newuser;
 | 
			
		||||
            uint circuitCode = useCircuit.CircuitCode.Code;
 | 
			
		||||
            
 | 
			
		||||
            if (m_scene.ClientManager.TryGetClient(circuitCode, out newuser))
 | 
			
		||||
            {
 | 
			
		||||
                // The circuit is already known to the scene.  This not actually a problem since this will currently
 | 
			
		||||
                // occur if a client is crossing borders (hence upgrading its circuit).  However, we shouldn't 
 | 
			
		||||
                // really by trying to add a new client if this is the case.
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            UUID agentId = useCircuit.CircuitCode.ID;
 | 
			
		||||
            UUID sessionId = useCircuit.CircuitCode.SessionID;
 | 
			
		||||
            
 | 
			
		||||
            newuser 
 | 
			
		||||
                = CreateNewCircuit(
 | 
			
		||||
                    epSender, m_scene, this, sessionInfo, agentId, sessionId, circuitCode, proxyEP);
 | 
			
		||||
 | 
			
		||||
            m_scene.ClientManager.Add(circuitCode, newuser);
 | 
			
		||||
 | 
			
		||||
            newuser.OnViewerEffect += m_scene.ClientManager.ViewerEffectHandler;
 | 
			
		||||
            newuser.OnLogout += LogoutHandler;
 | 
			
		||||
            newuser.OnConnectionClosed += CloseClient;
 | 
			
		||||
            
 | 
			
		||||
            newuser.Start();
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void LogoutHandler(IClientAPI client)
 | 
			
		||||
        {
 | 
			
		||||
            client.SendLogoutPacket();
 | 
			
		||||
            CloseClient(client);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Send a packet to the given circuit
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="buffer"></param>
 | 
			
		||||
        /// <param name="size"></param>
 | 
			
		||||
        /// <param name="flags"></param>
 | 
			
		||||
        /// <param name="circuitcode"></param>
 | 
			
		||||
        public virtual void SendPacketTo(byte[] buffer, int size, SocketFlags flags, uint circuitcode)
 | 
			
		||||
        {
 | 
			
		||||
            m_networkHandler.SendPacketTo(buffer, size, flags, circuitcode);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Close a client circuit only
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="circuitcode"></param>
 | 
			
		||||
        public virtual void CloseCircuit(uint circuitcode)
 | 
			
		||||
        {
 | 
			
		||||
            m_networkHandler.RemoveClientCircuit(circuitcode);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Completely close down the given client.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="client"></param>
 | 
			
		||||
        public virtual void CloseClient(IClientAPI client)
 | 
			
		||||
        {
 | 
			
		||||
            //m_log.Info("PacketServer:CloseClient()");
 | 
			
		||||
 | 
			
		||||
            CloseCircuit(client.CircuitCode);
 | 
			
		||||
            m_scene.ClientManager.Remove(client.CircuitCode);
 | 
			
		||||
            client.Close(false);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,128 +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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace OpenSim.Region.ClientStack.LindenUDP
 | 
			
		||||
{
 | 
			
		||||
    public class LLPacketThrottle
 | 
			
		||||
    {
 | 
			
		||||
        private readonly int m_maxAllowableThrottle;
 | 
			
		||||
        private readonly int m_minAllowableThrottle;
 | 
			
		||||
        private int m_currentThrottle;
 | 
			
		||||
        private const int m_throttleTimeDivisor = 7;
 | 
			
		||||
        private int m_currentBitsSent;
 | 
			
		||||
        private int m_throttleBits;
 | 
			
		||||
        
 | 
			
		||||
        /// <value>
 | 
			
		||||
        /// Value with which to multiply all the throttle fields
 | 
			
		||||
        /// </value>
 | 
			
		||||
        private float m_throttleMultiplier;
 | 
			
		||||
        
 | 
			
		||||
        public int Max
 | 
			
		||||
        {
 | 
			
		||||
            get { return m_maxAllowableThrottle; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public int Min
 | 
			
		||||
        {
 | 
			
		||||
            get { return m_minAllowableThrottle; }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        public int Current
 | 
			
		||||
        {
 | 
			
		||||
            get { return m_currentThrottle; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Constructor.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="min"></param>
 | 
			
		||||
        /// <param name="max"></param>
 | 
			
		||||
        /// <param name="throttle"></param>
 | 
			
		||||
        /// <param name="throttleMultiplier">
 | 
			
		||||
        /// A parameter that's ends up multiplying all throttle settings.  An alternative solution would have been 
 | 
			
		||||
        /// to multiply all the parameters by this before giving them to the constructor.  But doing it this way
 | 
			
		||||
        /// represents the fact that the multiplier is a hack that pumps data to clients much faster than the actual
 | 
			
		||||
        /// settings that we are given.
 | 
			
		||||
        /// </param>
 | 
			
		||||
        public LLPacketThrottle(int min, int max, int throttle, float throttleMultiplier)
 | 
			
		||||
        {
 | 
			
		||||
            m_throttleMultiplier = throttleMultiplier;
 | 
			
		||||
            m_maxAllowableThrottle = max;
 | 
			
		||||
            m_minAllowableThrottle = min;
 | 
			
		||||
            m_currentThrottle = throttle;
 | 
			
		||||
            m_currentBitsSent = 0;
 | 
			
		||||
 | 
			
		||||
            CalcBits();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Calculate the actual throttle required.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        private void CalcBits()
 | 
			
		||||
        {
 | 
			
		||||
            m_throttleBits = (int)((float)m_currentThrottle * m_throttleMultiplier / (float)m_throttleTimeDivisor);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Reset()
 | 
			
		||||
        {
 | 
			
		||||
            m_currentBitsSent = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public bool UnderLimit()
 | 
			
		||||
        {
 | 
			
		||||
            return m_currentBitsSent < m_throttleBits;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        public int AddBytes(int bytes)
 | 
			
		||||
        {
 | 
			
		||||
            m_currentBitsSent += bytes * 8;
 | 
			
		||||
            return m_currentBitsSent;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public int Throttle
 | 
			
		||||
        {
 | 
			
		||||
            get { return m_currentThrottle; }
 | 
			
		||||
            set
 | 
			
		||||
            {
 | 
			
		||||
                if (value < m_minAllowableThrottle)
 | 
			
		||||
                {
 | 
			
		||||
                    m_currentThrottle = m_minAllowableThrottle;
 | 
			
		||||
                }
 | 
			
		||||
                else if (value > m_maxAllowableThrottle)
 | 
			
		||||
                {
 | 
			
		||||
                    m_currentThrottle = m_maxAllowableThrottle;
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    m_currentThrottle = value;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                CalcBits();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,442 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 OpenSim.Framework;
 | 
			
		||||
using OpenMetaverse;
 | 
			
		||||
 | 
			
		||||
namespace OpenSim.Region.ClientStack.LindenUDP
 | 
			
		||||
{
 | 
			
		||||
    #region Delegates
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Fired when updated networking stats are produced for this client
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="inPackets">Number of incoming packets received since this
 | 
			
		||||
    /// event was last fired</param>
 | 
			
		||||
    /// <param name="outPackets">Number of outgoing packets sent since this
 | 
			
		||||
    /// event was last fired</param>
 | 
			
		||||
    /// <param name="unAckedBytes">Current total number of bytes in packets we
 | 
			
		||||
    /// are waiting on ACKs for</param>
 | 
			
		||||
    public delegate void PacketStats(int inPackets, int outPackets, int unAckedBytes);
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Fired when the queue for a packet category is empty. This event can be
 | 
			
		||||
    /// hooked to put more data on the empty queue
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="category">Category of the packet queue that is empty</param>
 | 
			
		||||
    public delegate void QueueEmpty(ThrottleOutPacketType category);
 | 
			
		||||
 | 
			
		||||
    #endregion Delegates
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Tracks state for a client UDP connection and provides client-specific methods
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public sealed class LLUDPClient
 | 
			
		||||
    {
 | 
			
		||||
        /// <summary>The number of packet categories to throttle on. If a throttle category is added
 | 
			
		||||
        /// or removed, this number must also change</summary>
 | 
			
		||||
        const int THROTTLE_CATEGORY_COUNT = 7;
 | 
			
		||||
 | 
			
		||||
        /// <summary>Fired when updated networking stats are produced for this client</summary>
 | 
			
		||||
        public event PacketStats OnPacketStats;
 | 
			
		||||
        /// <summary>Fired when the queue for a packet category is empty. This event can be
 | 
			
		||||
        /// hooked to put more data on the empty queue</summary>
 | 
			
		||||
        public event QueueEmpty OnQueueEmpty;
 | 
			
		||||
 | 
			
		||||
        /// <summary>AgentID for this client</summary>
 | 
			
		||||
        public readonly UUID AgentID;
 | 
			
		||||
        /// <summary>The remote address of the connected client</summary>
 | 
			
		||||
        public readonly IPEndPoint RemoteEndPoint;
 | 
			
		||||
        /// <summary>Circuit code that this client is connected on</summary>
 | 
			
		||||
        public readonly uint CircuitCode;
 | 
			
		||||
        /// <summary>Sequence numbers of packets we've received (for duplicate checking)</summary>
 | 
			
		||||
        public readonly IncomingPacketHistoryCollection PacketArchive = new IncomingPacketHistoryCollection(200);
 | 
			
		||||
        /// <summary>Packets we have sent that need to be ACKed by the client</summary>
 | 
			
		||||
        public readonly UnackedPacketCollection NeedAcks = new UnackedPacketCollection();
 | 
			
		||||
        /// <summary>ACKs that are queued up, waiting to be sent to the client</summary>
 | 
			
		||||
        public readonly LocklessQueue<uint> PendingAcks = new LocklessQueue<uint>();
 | 
			
		||||
 | 
			
		||||
        /// <summary>Reference to the IClientAPI for this client</summary>
 | 
			
		||||
        public LLClientView ClientAPI;
 | 
			
		||||
        /// <summary>Current packet sequence number</summary>
 | 
			
		||||
        public int CurrentSequence;
 | 
			
		||||
        /// <summary>Current ping sequence number</summary>
 | 
			
		||||
        public byte CurrentPingSequence;
 | 
			
		||||
        /// <summary>True when this connection is alive, otherwise false</summary>
 | 
			
		||||
        public bool IsConnected = true;
 | 
			
		||||
        /// <summary>True when this connection is paused, otherwise false</summary>
 | 
			
		||||
        public bool IsPaused = true;
 | 
			
		||||
        /// <summary>Environment.TickCount when the last packet was received for this client</summary>
 | 
			
		||||
        public int TickLastPacketReceived;
 | 
			
		||||
 | 
			
		||||
        /// <summary>Timer granularity. This is set to the measured resolution of Environment.TickCount</summary>
 | 
			
		||||
        public readonly float G;
 | 
			
		||||
        /// <summary>Smoothed round-trip time. A smoothed average of the round-trip time for sending a
 | 
			
		||||
        /// reliable packet to the client and receiving an ACK</summary>
 | 
			
		||||
        public float SRTT;
 | 
			
		||||
        /// <summary>Round-trip time variance. Measures the consistency of round-trip times</summary>
 | 
			
		||||
        public float RTTVAR;
 | 
			
		||||
        /// <summary>Retransmission timeout. Packets that have not been acknowledged in this number of
 | 
			
		||||
        /// milliseconds or longer will be resent</summary>
 | 
			
		||||
        /// <remarks>Calculated from <seealso cref="SRTT"/> and <seealso cref="RTTVAR"/> using the
 | 
			
		||||
        /// guidelines in RFC 2988</remarks>
 | 
			
		||||
        public int RTO;
 | 
			
		||||
        /// <summary>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)</summary>
 | 
			
		||||
        public int BytesSinceLastACK;
 | 
			
		||||
        /// <summary>Number of packets received from this client</summary>
 | 
			
		||||
        public int PacketsReceived;
 | 
			
		||||
        /// <summary>Number of packets sent to this client</summary>
 | 
			
		||||
        public int PacketsSent;
 | 
			
		||||
        /// <summary>Total byte count of unacked packets sent to this client</summary>
 | 
			
		||||
        public int UnackedBytes;
 | 
			
		||||
 | 
			
		||||
        /// <summary>Total number of received packets that we have reported to the OnPacketStats event(s)</summary>
 | 
			
		||||
        private int m_packetsReceivedReported;
 | 
			
		||||
        /// <summary>Total number of sent packets that we have reported to the OnPacketStats event(s)</summary>
 | 
			
		||||
        private int m_packetsSentReported;
 | 
			
		||||
 | 
			
		||||
        /// <summary>Throttle bucket for this agent's connection</summary>
 | 
			
		||||
        private readonly TokenBucket throttle;
 | 
			
		||||
        /// <summary>Throttle buckets for each packet category</summary>
 | 
			
		||||
        private readonly TokenBucket[] throttleCategories;
 | 
			
		||||
        /// <summary>Throttle rate defaults and limits</summary>
 | 
			
		||||
        private readonly ThrottleRates defaultThrottleRates;
 | 
			
		||||
        /// <summary>Outgoing queues for throttled packets</summary>
 | 
			
		||||
        private readonly LocklessQueue<OutgoingPacket>[] packetOutboxes = new LocklessQueue<OutgoingPacket>[THROTTLE_CATEGORY_COUNT];
 | 
			
		||||
        /// <summary>A container that can hold one packet for each outbox, used to store
 | 
			
		||||
        /// dequeued packets that are being held for throttling</summary>
 | 
			
		||||
        private readonly OutgoingPacket[] nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT];
 | 
			
		||||
        /// <summary>An optimization to store the length of dequeued packets being held
 | 
			
		||||
        /// for throttling. This avoids expensive calls to Packet.Length</summary>
 | 
			
		||||
        private readonly int[] nextPacketLengths = new int[THROTTLE_CATEGORY_COUNT];
 | 
			
		||||
        /// <summary>A reference to the LLUDPServer that is managing this client</summary>
 | 
			
		||||
        private readonly LLUDPServer udpServer;
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Default constructor
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="server">Reference to the UDP server this client is connected to</param>
 | 
			
		||||
        /// <param name="rates">Default throttling rates and maximum throttle limits</param>
 | 
			
		||||
        /// <param name="parentThrottle">Parent HTB (hierarchical token bucket)
 | 
			
		||||
        /// that the child throttles will be governed by</param>
 | 
			
		||||
        /// <param name="circuitCode">Circuit code for this connection</param>
 | 
			
		||||
        /// <param name="agentID">AgentID for the connected agent</param>
 | 
			
		||||
        /// <param name="remoteEndPoint">Remote endpoint for this connection</param>
 | 
			
		||||
        public LLUDPClient(LLUDPServer server, ThrottleRates rates, TokenBucket parentThrottle, uint circuitCode, UUID agentID, IPEndPoint remoteEndPoint)
 | 
			
		||||
        {
 | 
			
		||||
            udpServer = server;
 | 
			
		||||
            AgentID = agentID;
 | 
			
		||||
            RemoteEndPoint = remoteEndPoint;
 | 
			
		||||
            CircuitCode = circuitCode;
 | 
			
		||||
            defaultThrottleRates = rates;
 | 
			
		||||
 | 
			
		||||
            for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
 | 
			
		||||
                packetOutboxes[i] = new LocklessQueue<OutgoingPacket>();
 | 
			
		||||
 | 
			
		||||
            throttle = new TokenBucket(parentThrottle, 0, 0);
 | 
			
		||||
            throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT];
 | 
			
		||||
            throttleCategories[(int)ThrottleOutPacketType.Resend] = new TokenBucket(throttle, rates.ResendLimit, rates.Resend);
 | 
			
		||||
            throttleCategories[(int)ThrottleOutPacketType.Land] = new TokenBucket(throttle, rates.LandLimit, rates.Land);
 | 
			
		||||
            throttleCategories[(int)ThrottleOutPacketType.Wind] = new TokenBucket(throttle, rates.WindLimit, rates.Wind);
 | 
			
		||||
            throttleCategories[(int)ThrottleOutPacketType.Cloud] = new TokenBucket(throttle, rates.CloudLimit, rates.Cloud);
 | 
			
		||||
            throttleCategories[(int)ThrottleOutPacketType.Task] = new TokenBucket(throttle, rates.TaskLimit, rates.Task);
 | 
			
		||||
            throttleCategories[(int)ThrottleOutPacketType.Texture] = new TokenBucket(throttle, rates.TextureLimit, rates.Texture);
 | 
			
		||||
            throttleCategories[(int)ThrottleOutPacketType.Asset] = new TokenBucket(throttle, rates.AssetLimit, rates.Asset);
 | 
			
		||||
 | 
			
		||||
            // Set the granularity variable used for retransmission calculations to
 | 
			
		||||
            // the measured resolution of Environment.TickCount
 | 
			
		||||
            G = server.TickCountResolution;
 | 
			
		||||
 | 
			
		||||
            // Default the retransmission timeout to three seconds
 | 
			
		||||
            RTO = 3000;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Shuts down this client connection
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public void Shutdown()
 | 
			
		||||
        {
 | 
			
		||||
            // TODO: Do we need to invalidate the circuit?
 | 
			
		||||
            IsConnected = false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets information about this client connection
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <returns>Information about the client connection</returns>
 | 
			
		||||
        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<uint, uint>();
 | 
			
		||||
            info.needAck = new Dictionary<uint, byte[]>();
 | 
			
		||||
 | 
			
		||||
            info.resendThrottle = throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate;
 | 
			
		||||
            info.landThrottle = throttleCategories[(int)ThrottleOutPacketType.Land].DripRate;
 | 
			
		||||
            info.windThrottle = throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate;
 | 
			
		||||
            info.cloudThrottle = throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate;
 | 
			
		||||
            info.taskThrottle = throttleCategories[(int)ThrottleOutPacketType.Task].DripRate;
 | 
			
		||||
            info.assetThrottle = throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate;
 | 
			
		||||
            info.textureThrottle = throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate;
 | 
			
		||||
            info.totalThrottle = info.resendThrottle + info.landThrottle + info.windThrottle + info.cloudThrottle +
 | 
			
		||||
                info.taskThrottle + info.assetThrottle + info.textureThrottle;
 | 
			
		||||
 | 
			
		||||
            return info;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Modifies the UDP throttles
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="info">New throttling values</param>
 | 
			
		||||
        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();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public string GetStats()
 | 
			
		||||
        {
 | 
			
		||||
            // TODO: ???
 | 
			
		||||
            return string.Format("{0,7} {1,7} {2,7} {3,7} {4,7} {5,7} {6,7} {7,7} {8,7} {9,7}",
 | 
			
		||||
                0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            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);
 | 
			
		||||
 | 
			
		||||
            resend = (resend <= defaultThrottleRates.ResendLimit) ? resend : defaultThrottleRates.ResendLimit;
 | 
			
		||||
            land = (land <= defaultThrottleRates.LandLimit) ? land : defaultThrottleRates.LandLimit;
 | 
			
		||||
            wind = (wind <= defaultThrottleRates.WindLimit) ? wind : defaultThrottleRates.WindLimit;
 | 
			
		||||
            cloud = (cloud <= defaultThrottleRates.CloudLimit) ? cloud : defaultThrottleRates.CloudLimit;
 | 
			
		||||
            task = (task <= defaultThrottleRates.TaskLimit) ? task : defaultThrottleRates.TaskLimit;
 | 
			
		||||
            texture = (texture <= defaultThrottleRates.TextureLimit) ? texture : defaultThrottleRates.TextureLimit;
 | 
			
		||||
            asset = (asset <= defaultThrottleRates.AssetLimit) ? asset : defaultThrottleRates.AssetLimit;
 | 
			
		||||
 | 
			
		||||
            SetThrottle(ThrottleOutPacketType.Resend, resend);
 | 
			
		||||
            SetThrottle(ThrottleOutPacketType.Land, land);
 | 
			
		||||
            SetThrottle(ThrottleOutPacketType.Wind, wind);
 | 
			
		||||
            SetThrottle(ThrottleOutPacketType.Cloud, cloud);
 | 
			
		||||
            SetThrottle(ThrottleOutPacketType.Task, task);
 | 
			
		||||
            SetThrottle(ThrottleOutPacketType.Texture, texture);
 | 
			
		||||
            SetThrottle(ThrottleOutPacketType.Asset, asset);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public byte[] GetThrottlesPacked()
 | 
			
		||||
        {
 | 
			
		||||
            byte[] data = new byte[7 * 4];
 | 
			
		||||
            int i = 0;
 | 
			
		||||
 | 
			
		||||
            Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate), 0, data, i, 4); i += 4;
 | 
			
		||||
            Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Land].DripRate), 0, data, i, 4); i += 4;
 | 
			
		||||
            Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate), 0, data, i, 4); i += 4;
 | 
			
		||||
            Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate), 0, data, i, 4); i += 4;
 | 
			
		||||
            Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Task].DripRate), 0, data, i, 4); i += 4;
 | 
			
		||||
            Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate), 0, data, i, 4); i += 4;
 | 
			
		||||
            Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate), 0, data, i, 4); i += 4;
 | 
			
		||||
 | 
			
		||||
            return data;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SetThrottle(ThrottleOutPacketType category, int rate)
 | 
			
		||||
        {
 | 
			
		||||
            int i = (int)category;
 | 
			
		||||
            if (i >= 0 && i < throttleCategories.Length)
 | 
			
		||||
            {
 | 
			
		||||
                TokenBucket bucket = throttleCategories[(int)category];
 | 
			
		||||
                bucket.MaxBurst = rate;
 | 
			
		||||
                bucket.DripRate = rate;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public bool EnqueueOutgoing(OutgoingPacket packet)
 | 
			
		||||
        {
 | 
			
		||||
            int category = (int)packet.Category;
 | 
			
		||||
 | 
			
		||||
            if (category >= 0 && category < packetOutboxes.Length)
 | 
			
		||||
            {
 | 
			
		||||
                LocklessQueue<OutgoingPacket> queue = packetOutboxes[category];
 | 
			
		||||
                TokenBucket bucket = throttleCategories[category];
 | 
			
		||||
 | 
			
		||||
                if (throttleCategories[category].RemoveTokens(packet.Buffer.DataLength))
 | 
			
		||||
                {
 | 
			
		||||
                    // Enough tokens were removed from the bucket, the packet will not be queued
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    // 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;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Loops through all of the packet queues for this client and tries to send
 | 
			
		||||
        /// any outgoing packets, obeying the throttling bucket limits
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <remarks>This function is only called from a synchronous loop in the
 | 
			
		||||
        /// UDPServer so we don't need to bother making this thread safe</remarks>
 | 
			
		||||
        /// <returns>True if any packets were sent, otherwise false</returns>
 | 
			
		||||
        public bool DequeueOutgoing()
 | 
			
		||||
        {
 | 
			
		||||
            OutgoingPacket packet;
 | 
			
		||||
            LocklessQueue<OutgoingPacket> queue;
 | 
			
		||||
            TokenBucket bucket;
 | 
			
		||||
            bool packetSent = false;
 | 
			
		||||
 | 
			
		||||
            for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
 | 
			
		||||
            {
 | 
			
		||||
                bucket = throttleCategories[i];
 | 
			
		||||
 | 
			
		||||
                if (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
 | 
			
		||||
                    if (bucket.RemoveTokens(nextPacketLengths[i]))
 | 
			
		||||
                    {
 | 
			
		||||
                        // Send the packet
 | 
			
		||||
                        udpServer.SendPacketFinal(nextPackets[i]);
 | 
			
		||||
                        nextPackets[i] = null;
 | 
			
		||||
                        packetSent = true;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    // No dequeued packet waiting to be sent, try to pull one off
 | 
			
		||||
                    // this queue
 | 
			
		||||
                    queue = 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
 | 
			
		||||
                            udpServer.SendPacketFinal(packet);
 | 
			
		||||
                            packetSent = true;
 | 
			
		||||
                        }
 | 
			
		||||
                        else
 | 
			
		||||
                        {
 | 
			
		||||
                            // Save the dequeued packet and the length calculation for
 | 
			
		||||
                            // the next iteration
 | 
			
		||||
                            nextPackets[i] = packet;
 | 
			
		||||
                            nextPacketLengths[i] = packet.Buffer.DataLength;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        // No packets in this queue. Fire the queue empty callback
 | 
			
		||||
                        QueueEmpty callback = OnQueueEmpty;
 | 
			
		||||
                        if (callback != null)
 | 
			
		||||
                            callback((ThrottleOutPacketType)i);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return packetSent;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Always round retransmission timeout up to two seconds
 | 
			
		||||
            RTO = Math.Max(2000, (int)(SRTT + Math.Max(G, K * RTTVAR)));
 | 
			
		||||
            //Logger.Debug("Setting agent " + this.Agent.FullName + "'s RTO to " + RTO + "ms with an RTTVAR of " +
 | 
			
		||||
            //    RTTVAR + " based on new RTT of " + r + "ms");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,282 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 OpenSim.Framework;
 | 
			
		||||
using OpenMetaverse;
 | 
			
		||||
 | 
			
		||||
using ReaderWriterLockImpl = OpenMetaverse.ReaderWriterLockSlim;
 | 
			
		||||
 | 
			
		||||
namespace OpenSim.Region.ClientStack.LindenUDP
 | 
			
		||||
{
 | 
			
		||||
    public sealed class UDPClientCollection
 | 
			
		||||
    {
 | 
			
		||||
        Dictionary<UUID, LLUDPClient> Dictionary1;
 | 
			
		||||
        Dictionary<IPEndPoint, LLUDPClient> Dictionary2;
 | 
			
		||||
        LLUDPClient[] Array;
 | 
			
		||||
        ReaderWriterLockImpl rwLock = new ReaderWriterLockImpl();
 | 
			
		||||
        object m_sync = new object();
 | 
			
		||||
 | 
			
		||||
        public UDPClientCollection()
 | 
			
		||||
        {
 | 
			
		||||
            Dictionary1 = new Dictionary<UUID, LLUDPClient>();
 | 
			
		||||
            Dictionary2 = new Dictionary<IPEndPoint, LLUDPClient>();
 | 
			
		||||
            Array = new LLUDPClient[0];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public UDPClientCollection(int capacity)
 | 
			
		||||
        {
 | 
			
		||||
            Dictionary1 = new Dictionary<UUID, LLUDPClient>(capacity);
 | 
			
		||||
            Dictionary2 = new Dictionary<IPEndPoint, LLUDPClient>(capacity);
 | 
			
		||||
            Array = new LLUDPClient[0];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Add(UUID key1, IPEndPoint key2, LLUDPClient value)
 | 
			
		||||
        {
 | 
			
		||||
            //rwLock.EnterWriteLock();
 | 
			
		||||
 | 
			
		||||
            //try
 | 
			
		||||
            //{
 | 
			
		||||
            //    if (Dictionary1.ContainsKey(key1))
 | 
			
		||||
            //    {
 | 
			
		||||
            //        if (!Dictionary2.ContainsKey(key2))
 | 
			
		||||
            //            throw new ArgumentException("key1 exists in the dictionary but not key2");
 | 
			
		||||
            //    }
 | 
			
		||||
            //    else if (Dictionary2.ContainsKey(key2))
 | 
			
		||||
            //    {
 | 
			
		||||
            //        if (!Dictionary1.ContainsKey(key1))
 | 
			
		||||
            //            throw new ArgumentException("key2 exists in the dictionary but not key1");
 | 
			
		||||
            //    }
 | 
			
		||||
 | 
			
		||||
            //    Dictionary1[key1] = value;
 | 
			
		||||
            //    Dictionary2[key2] = value;
 | 
			
		||||
 | 
			
		||||
            //    LLUDPClient[] oldArray = Array;
 | 
			
		||||
            //    int oldLength = oldArray.Length;
 | 
			
		||||
 | 
			
		||||
            //    LLUDPClient[] newArray = new LLUDPClient[oldLength + 1];
 | 
			
		||||
            //    for (int i = 0; i < oldLength; i++)
 | 
			
		||||
            //        newArray[i] = oldArray[i];
 | 
			
		||||
            //    newArray[oldLength] = value;
 | 
			
		||||
 | 
			
		||||
            //    Array = newArray;
 | 
			
		||||
            //}
 | 
			
		||||
            //finally { rwLock.ExitWriteLock(); }
 | 
			
		||||
 | 
			
		||||
            lock (m_sync)
 | 
			
		||||
            {
 | 
			
		||||
                if (Dictionary1.ContainsKey(key1))
 | 
			
		||||
                {
 | 
			
		||||
                    if (!Dictionary2.ContainsKey(key2))
 | 
			
		||||
                        throw new ArgumentException("key1 exists in the dictionary but not key2");
 | 
			
		||||
                }
 | 
			
		||||
                else if (Dictionary2.ContainsKey(key2))
 | 
			
		||||
                {
 | 
			
		||||
                    if (!Dictionary1.ContainsKey(key1))
 | 
			
		||||
                        throw new ArgumentException("key2 exists in the dictionary but not key1");
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                Dictionary1[key1] = value;
 | 
			
		||||
                Dictionary2[key2] = value;
 | 
			
		||||
 | 
			
		||||
                LLUDPClient[] oldArray = Array;
 | 
			
		||||
                int oldLength = oldArray.Length;
 | 
			
		||||
 | 
			
		||||
                LLUDPClient[] newArray = new LLUDPClient[oldLength + 1];
 | 
			
		||||
                for (int i = 0; i < oldLength; i++)
 | 
			
		||||
                    newArray[i] = oldArray[i];
 | 
			
		||||
                newArray[oldLength] = value;
 | 
			
		||||
 | 
			
		||||
                Array = newArray;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public bool Remove(UUID key1, IPEndPoint key2)
 | 
			
		||||
        {
 | 
			
		||||
            //rwLock.EnterWriteLock();
 | 
			
		||||
 | 
			
		||||
            //try
 | 
			
		||||
            //{
 | 
			
		||||
            //    LLUDPClient value;
 | 
			
		||||
            //    if (Dictionary1.TryGetValue(key1, out value))
 | 
			
		||||
            //    {
 | 
			
		||||
            //        Dictionary1.Remove(key1);
 | 
			
		||||
            //        Dictionary2.Remove(key2);
 | 
			
		||||
 | 
			
		||||
            //        LLUDPClient[] oldArray = Array;
 | 
			
		||||
            //        int oldLength = oldArray.Length;
 | 
			
		||||
 | 
			
		||||
            //        LLUDPClient[] newArray = new LLUDPClient[oldLength - 1];
 | 
			
		||||
            //        int j = 0;
 | 
			
		||||
            //        for (int i = 0; i < oldLength; i++)
 | 
			
		||||
            //        {
 | 
			
		||||
            //            if (oldArray[i] != value)
 | 
			
		||||
            //                newArray[j++] = oldArray[i];
 | 
			
		||||
            //        }
 | 
			
		||||
 | 
			
		||||
            //        Array = newArray;
 | 
			
		||||
            //        return true;
 | 
			
		||||
            //    }
 | 
			
		||||
            //}
 | 
			
		||||
            //finally { rwLock.ExitWriteLock(); }
 | 
			
		||||
 | 
			
		||||
            //return false;
 | 
			
		||||
 | 
			
		||||
            lock (m_sync)
 | 
			
		||||
            {
 | 
			
		||||
                LLUDPClient value;
 | 
			
		||||
                if (Dictionary1.TryGetValue(key1, out value))
 | 
			
		||||
                {
 | 
			
		||||
                    Dictionary1.Remove(key1);
 | 
			
		||||
                    Dictionary2.Remove(key2);
 | 
			
		||||
 | 
			
		||||
                    LLUDPClient[] oldArray = Array;
 | 
			
		||||
                    int oldLength = oldArray.Length;
 | 
			
		||||
 | 
			
		||||
                    LLUDPClient[] newArray = new LLUDPClient[oldLength - 1];
 | 
			
		||||
                    int j = 0;
 | 
			
		||||
                    for (int i = 0; i < oldLength; i++)
 | 
			
		||||
                    {
 | 
			
		||||
                        if (oldArray[i] != value)
 | 
			
		||||
                            newArray[j++] = oldArray[i];
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    Array = newArray;
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Clear()
 | 
			
		||||
        {
 | 
			
		||||
            //rwLock.EnterWriteLock();
 | 
			
		||||
 | 
			
		||||
            //try
 | 
			
		||||
            //{
 | 
			
		||||
            //    Dictionary1.Clear();
 | 
			
		||||
            //    Dictionary2.Clear();
 | 
			
		||||
            //    Array = new LLUDPClient[0];
 | 
			
		||||
            //}
 | 
			
		||||
            //finally { rwLock.ExitWriteLock(); }
 | 
			
		||||
 | 
			
		||||
            lock (m_sync)
 | 
			
		||||
            {
 | 
			
		||||
                Dictionary1.Clear();
 | 
			
		||||
                Dictionary2.Clear();
 | 
			
		||||
                Array = new LLUDPClient[0];
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public int Count
 | 
			
		||||
        {
 | 
			
		||||
            get { return Array.Length; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public bool ContainsKey(UUID key)
 | 
			
		||||
        {
 | 
			
		||||
            return Dictionary1.ContainsKey(key);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public bool ContainsKey(IPEndPoint key)
 | 
			
		||||
        {
 | 
			
		||||
            return Dictionary2.ContainsKey(key);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public bool TryGetValue(UUID key, out LLUDPClient value)
 | 
			
		||||
        {
 | 
			
		||||
            ////bool success;
 | 
			
		||||
            ////bool doLock = !rwLock.IsUpgradeableReadLockHeld;
 | 
			
		||||
            ////if (doLock) rwLock.EnterReadLock();
 | 
			
		||||
 | 
			
		||||
            ////try { success = Dictionary1.TryGetValue(key, out value); }
 | 
			
		||||
            ////finally { if (doLock) rwLock.ExitReadLock(); }
 | 
			
		||||
 | 
			
		||||
            ////return success;
 | 
			
		||||
 | 
			
		||||
            //lock (m_sync)
 | 
			
		||||
            //    return Dictionary1.TryGetValue(key, out value); 
 | 
			
		||||
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                return Dictionary1.TryGetValue(key, out value);
 | 
			
		||||
            }
 | 
			
		||||
            catch { }
 | 
			
		||||
            value = null;
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public bool TryGetValue(IPEndPoint key, out LLUDPClient value)
 | 
			
		||||
        {
 | 
			
		||||
            ////bool success;
 | 
			
		||||
            ////bool doLock = !rwLock.IsUpgradeableReadLockHeld;
 | 
			
		||||
            ////if (doLock) rwLock.EnterReadLock();
 | 
			
		||||
 | 
			
		||||
            ////try { success = Dictionary2.TryGetValue(key, out value); }
 | 
			
		||||
            ////finally { if (doLock) rwLock.ExitReadLock(); }
 | 
			
		||||
 | 
			
		||||
            ////return success;
 | 
			
		||||
 | 
			
		||||
            lock (m_sync)
 | 
			
		||||
                return Dictionary2.TryGetValue(key, out value);
 | 
			
		||||
 | 
			
		||||
            //try
 | 
			
		||||
            //{
 | 
			
		||||
            //    return Dictionary2.TryGetValue(key, out value);
 | 
			
		||||
            //}
 | 
			
		||||
            //catch { }
 | 
			
		||||
            //value = null;
 | 
			
		||||
            //return false;
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void ForEach(Action<LLUDPClient> action)
 | 
			
		||||
        {
 | 
			
		||||
            //bool doLock = !rwLock.IsUpgradeableReadLockHeld;
 | 
			
		||||
            //if (doLock) rwLock.EnterUpgradeableReadLock();
 | 
			
		||||
 | 
			
		||||
            //try { Parallel.ForEach<LLUDPClient>(Array, action); }
 | 
			
		||||
            //finally { if (doLock) rwLock.ExitUpgradeableReadLock(); }
 | 
			
		||||
 | 
			
		||||
            LLUDPClient[] localArray = null;
 | 
			
		||||
            lock (m_sync)
 | 
			
		||||
            {
 | 
			
		||||
                localArray = new LLUDPClient[Array.Length];
 | 
			
		||||
                Array.CopyTo(localArray, 0);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Parallel.ForEach<LLUDPClient>(localArray, action); 
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
/*
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) Contributors, http://opensimulator.org/
 | 
			
		||||
 * See CONTRIBUTORS.TXT for a full list of copyright holders.
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -25,27 +25,46 @@
 | 
			
		|||
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
using System;
 | 
			
		||||
using OpenSim.Framework;
 | 
			
		||||
using OpenMetaverse;
 | 
			
		||||
 | 
			
		||||
namespace OpenSim.Region.ClientStack.LindenUDP
 | 
			
		||||
{
 | 
			
		||||
    public class LLUtil
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Holds a reference to the <seealso cref="LLUDPClient"/> this packet is
 | 
			
		||||
    /// destined for, along with the serialized packet data, sequence number
 | 
			
		||||
    /// (if this is a resend), number of times this packet has been resent,
 | 
			
		||||
    /// the time of the last resend, and the throttling category for this
 | 
			
		||||
    /// packet
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public sealed class OutgoingPacket
 | 
			
		||||
    {
 | 
			
		||||
        /// <summary>Client this packet is destined for</summary>
 | 
			
		||||
        public LLUDPClient Client;
 | 
			
		||||
        /// <summary>Packet data to send</summary>
 | 
			
		||||
        public UDPPacketBuffer Buffer;
 | 
			
		||||
        /// <summary>Sequence number of the wrapped packet</summary>
 | 
			
		||||
        public uint SequenceNumber;
 | 
			
		||||
        /// <summary>Number of times this packet has been resent</summary>
 | 
			
		||||
        public int ResendCount;
 | 
			
		||||
        /// <summary>Environment.TickCount when this packet was last sent over the wire</summary>
 | 
			
		||||
        public int TickCount;
 | 
			
		||||
        /// <summary>Category this packet belongs to</summary>
 | 
			
		||||
        public ThrottleOutPacketType Category;
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Convert a string to bytes suitable for use in an LL UDP packet.
 | 
			
		||||
        /// Default constructor
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="s">Truncated to 254 characters if necessary</param>
 | 
			
		||||
        /// <returns></returns>
 | 
			
		||||
        public static byte[] StringToPacketBytes(string s)
 | 
			
		||||
        /// <param name="client">Reference to the client this packet is destined for</param>
 | 
			
		||||
        /// <param name="buffer">Serialized packet data. If the flags or sequence number
 | 
			
		||||
        /// need to be updated, they will be injected directly into this binary buffer</param>
 | 
			
		||||
        /// <param name="category">Throttling category for this packet</param>
 | 
			
		||||
        public OutgoingPacket(LLUDPClient client, UDPPacketBuffer buffer, ThrottleOutPacketType category)
 | 
			
		||||
        {
 | 
			
		||||
            // Anything more than 254 will cause libsecondlife to barf
 | 
			
		||||
            // (libsl 1550) adds an \0 on the Utils.StringToBytes conversion if it isn't present
 | 
			
		||||
            if (s.Length > 254)
 | 
			
		||||
            {
 | 
			
		||||
                s = s.Remove(254);
 | 
			
		||||
            } 
 | 
			
		||||
            
 | 
			
		||||
            return Utils.StringToBytes(s);
 | 
			
		||||
            Client = client;
 | 
			
		||||
            Buffer = buffer;
 | 
			
		||||
            Category = category;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -70,7 +70,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
 | 
			
		|||
            
 | 
			
		||||
            TestClient testClient = new TestClient(agent, scene);
 | 
			
		||||
            
 | 
			
		||||
            ILLPacketHandler packetHandler 
 | 
			
		||||
            LLPacketHandler packetHandler 
 | 
			
		||||
                = new LLPacketHandler(testClient, testLLPacketServer, new ClientStackUserSettings());
 | 
			
		||||
            
 | 
			
		||||
            packetHandler.InPacket(new AgentAnimationPacket());
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -37,7 +37,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
 | 
			
		|||
        /// </summary>
 | 
			
		||||
        protected Dictionary<PacketType, int> m_packetsReceived = new Dictionary<PacketType, int>();
 | 
			
		||||
        
 | 
			
		||||
        public TestLLPacketServer(ILLClientStackNetworkHandler networkHandler, ClientStackUserSettings userSettings)
 | 
			
		||||
        public TestLLPacketServer(LLUDPServer networkHandler, ClientStackUserSettings userSettings)
 | 
			
		||||
            : base(networkHandler, userSettings)
 | 
			
		||||
        {}
 | 
			
		||||
        
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,99 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 Nini.Config;
 | 
			
		||||
 | 
			
		||||
namespace OpenSim.Region.ClientStack.LindenUDP
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Holds drip rates and maximum burst rates for throttling with hierarchical
 | 
			
		||||
    /// token buckets. The maximum burst rates set here are hard limits and can
 | 
			
		||||
    /// not be overridden by client requests
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public sealed class ThrottleRates
 | 
			
		||||
    {
 | 
			
		||||
        /// <summary>Drip rate for resent packets</summary>
 | 
			
		||||
        public int Resend;
 | 
			
		||||
        /// <summary>Drip rate for terrain packets</summary>
 | 
			
		||||
        public int Land;
 | 
			
		||||
        /// <summary>Drip rate for wind packets</summary>
 | 
			
		||||
        public int Wind;
 | 
			
		||||
        /// <summary>Drip rate for cloud packets</summary>
 | 
			
		||||
        public int Cloud;
 | 
			
		||||
        /// <summary>Drip rate for task (state and transaction) packets</summary>
 | 
			
		||||
        public int Task;
 | 
			
		||||
        /// <summary>Drip rate for texture packets</summary>
 | 
			
		||||
        public int Texture;
 | 
			
		||||
        /// <summary>Drip rate for asset packets</summary>
 | 
			
		||||
        public int Asset;
 | 
			
		||||
 | 
			
		||||
        /// <summary>Maximum burst rate for resent packets</summary>
 | 
			
		||||
        public int ResendLimit;
 | 
			
		||||
        /// <summary>Maximum burst rate for land packets</summary>
 | 
			
		||||
        public int LandLimit;
 | 
			
		||||
        /// <summary>Maximum burst rate for wind packets</summary>
 | 
			
		||||
        public int WindLimit;
 | 
			
		||||
        /// <summary>Maximum burst rate for cloud packets</summary>
 | 
			
		||||
        public int CloudLimit;
 | 
			
		||||
        /// <summary>Maximum burst rate for task (state and transaction) packets</summary>
 | 
			
		||||
        public int TaskLimit;
 | 
			
		||||
        /// <summary>Maximum burst rate for texture packets</summary>
 | 
			
		||||
        public int TextureLimit;
 | 
			
		||||
        /// <summary>Maximum burst rate for asset packets</summary>
 | 
			
		||||
        public int AssetLimit;
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Default constructor
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="config">Config source to load defaults from</param>
 | 
			
		||||
        public ThrottleRates(IConfigSource config)
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                IConfig throttleConfig = config.Configs["ClientStack.LindenUDP"];
 | 
			
		||||
 | 
			
		||||
                Resend = throttleConfig.GetInt("ResendDefault", 12500);
 | 
			
		||||
                Land = throttleConfig.GetInt("LandDefault", 500);
 | 
			
		||||
                Wind = throttleConfig.GetInt("WindDefault", 500);
 | 
			
		||||
                Cloud = throttleConfig.GetInt("CloudDefault", 500);
 | 
			
		||||
                Task = throttleConfig.GetInt("TaskDefault", 500);
 | 
			
		||||
                Texture = throttleConfig.GetInt("TextureDefault", 500);
 | 
			
		||||
                Asset = throttleConfig.GetInt("AssetDefault", 500);
 | 
			
		||||
 | 
			
		||||
                ResendLimit = throttleConfig.GetInt("ResendLimit", 18750);
 | 
			
		||||
                LandLimit = throttleConfig.GetInt("LandLimit", 29750);
 | 
			
		||||
                WindLimit = throttleConfig.GetInt("WindLimit", 18750);
 | 
			
		||||
                CloudLimit = throttleConfig.GetInt("CloudLimit", 18750);
 | 
			
		||||
                TaskLimit = throttleConfig.GetInt("TaskLimit", 55750);
 | 
			
		||||
                TextureLimit = throttleConfig.GetInt("TextureLimit", 55750);
 | 
			
		||||
                AssetLimit = throttleConfig.GetInt("AssetLimit", 27500);
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception) { }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,160 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 OpenMetaverse;
 | 
			
		||||
 | 
			
		||||
namespace OpenSim.Region.ClientStack.LindenUDP
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Special collection that is optimized for tracking unacknowledged packets
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public sealed class UnackedPacketCollection
 | 
			
		||||
    {
 | 
			
		||||
        /// <summary>Synchronization primitive. A lock must be acquired on this
 | 
			
		||||
        /// object before calling any of the unsafe methods</summary>
 | 
			
		||||
        public object SyncRoot = new object();
 | 
			
		||||
 | 
			
		||||
        /// <summary>Holds the actual unacked packet data, sorted by sequence number</summary>
 | 
			
		||||
        private SortedDictionary<uint, OutgoingPacket> packets = new SortedDictionary<uint, OutgoingPacket>();
 | 
			
		||||
 | 
			
		||||
        /// <summary>Gets the total number of unacked packets</summary>
 | 
			
		||||
        public int Count { get { return packets.Count; } }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Default constructor
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public UnackedPacketCollection()
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Add an unacked packet to the collection
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="packet">Packet that is awaiting acknowledgement</param>
 | 
			
		||||
        /// <returns>True if the packet was successfully added, false if the
 | 
			
		||||
        /// packet already existed in the collection</returns>
 | 
			
		||||
        public bool Add(OutgoingPacket packet)
 | 
			
		||||
        {
 | 
			
		||||
            lock (SyncRoot)
 | 
			
		||||
            {
 | 
			
		||||
                if (!packets.ContainsKey(packet.SequenceNumber))
 | 
			
		||||
                {
 | 
			
		||||
                    packets.Add(packet.SequenceNumber, packet);
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Removes a packet from the collection without attempting to obtain a
 | 
			
		||||
        /// lock first
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="sequenceNumber">Sequence number of the packet to remove</param>
 | 
			
		||||
        /// <returns>True if the packet was found and removed, otherwise false</returns>
 | 
			
		||||
        public bool RemoveUnsafe(uint sequenceNumber)
 | 
			
		||||
        {
 | 
			
		||||
            return packets.Remove(sequenceNumber);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Removes a packet from the collection without attempting to obtain a
 | 
			
		||||
        /// lock first
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="sequenceNumber">Sequence number of the packet to remove</param>
 | 
			
		||||
        /// <param name="packet">Returns the removed packet</param>
 | 
			
		||||
        /// <returns>True if the packet was found and removed, otherwise false</returns>
 | 
			
		||||
        public bool RemoveUnsafe(uint sequenceNumber, out OutgoingPacket packet)
 | 
			
		||||
        {
 | 
			
		||||
            if (packets.TryGetValue(sequenceNumber, out packet))
 | 
			
		||||
            {
 | 
			
		||||
                packets.Remove(sequenceNumber);
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets the packet with the lowest sequence number
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <returns>The packet with the lowest sequence number, or null if the
 | 
			
		||||
        /// collection is empty</returns>
 | 
			
		||||
        public OutgoingPacket GetOldest()
 | 
			
		||||
        {
 | 
			
		||||
            lock (SyncRoot)
 | 
			
		||||
            {
 | 
			
		||||
                using (SortedDictionary<uint, OutgoingPacket>.ValueCollection.Enumerator e = packets.Values.GetEnumerator())
 | 
			
		||||
                {
 | 
			
		||||
                    if (e.MoveNext())
 | 
			
		||||
                        return e.Current;
 | 
			
		||||
                    else
 | 
			
		||||
                        return null;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Returns a list of all of the packets with a TickCount older than
 | 
			
		||||
        /// the specified timeout
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="timeoutMS">Number of ticks (milliseconds) before a
 | 
			
		||||
        /// packet is considered expired</param>
 | 
			
		||||
        /// <returns>A list of all expired packets according to the given
 | 
			
		||||
        /// expiration timeout</returns>
 | 
			
		||||
        public List<OutgoingPacket> GetExpiredPackets(int timeoutMS)
 | 
			
		||||
        {
 | 
			
		||||
            List<OutgoingPacket> expiredPackets = null;
 | 
			
		||||
 | 
			
		||||
            lock (SyncRoot)
 | 
			
		||||
            {
 | 
			
		||||
                int now = Environment.TickCount;
 | 
			
		||||
                foreach (OutgoingPacket packet in packets.Values)
 | 
			
		||||
                {
 | 
			
		||||
                    if (packet.TickCount == 0)
 | 
			
		||||
                        continue;
 | 
			
		||||
 | 
			
		||||
                    if (now - packet.TickCount >= timeoutMS)
 | 
			
		||||
                    {
 | 
			
		||||
                        if (expiredPackets == null)
 | 
			
		||||
                            expiredPackets = new List<OutgoingPacket>();
 | 
			
		||||
                        expiredPackets.Add(packet);
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return expiredPackets;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -323,7 +323,6 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
 | 
			
		|||
            httpThread.IsBackground = true;
 | 
			
		||||
            _finished = false;
 | 
			
		||||
            httpThread.Start();
 | 
			
		||||
            ThreadTracker.Add(httpThread);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /*
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -639,7 +639,6 @@ namespace OpenSim.Region.CoreModules.Scripting.XMLRPC
 | 
			
		|||
            httpThread.IsBackground = true;
 | 
			
		||||
            _finished = false;
 | 
			
		||||
            httpThread.Start();
 | 
			
		||||
            ThreadTracker.Add(httpThread);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /*
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -98,7 +98,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsIn.Asset
 | 
			
		|||
 | 
			
		||||
                m_log.Info("[RegionAssetService]: Starting...");
 | 
			
		||||
 | 
			
		||||
                Object[] args = new Object[] { m_Config, MainServer.Instance };
 | 
			
		||||
                Object[] args = new Object[] { m_Config, MainServer.Instance, string.Empty };
 | 
			
		||||
 | 
			
		||||
                ServerUtils.LoadPlugin<IServiceConnector>("OpenSim.Server.Handlers.dll:AssetServiceConnector", args);
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -98,7 +98,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsIn.Inventory
 | 
			
		|||
 | 
			
		||||
                m_log.Info("[RegionInventoryService]: Starting...");
 | 
			
		||||
 | 
			
		||||
                Object[] args = new Object[] { m_Config, MainServer.Instance };
 | 
			
		||||
                Object[] args = new Object[] { m_Config, MainServer.Instance, String.Empty };
 | 
			
		||||
 | 
			
		||||
                ServerUtils.LoadPlugin<IServiceConnector>("OpenSim.Server.Handlers.dll:InventoryServiceInConnector", args);
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -61,6 +61,10 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
 | 
			
		|||
 | 
			
		||||
        private void OnRegionUp(GridRegion otherRegion)
 | 
			
		||||
        {
 | 
			
		||||
            // This shouldn't happen
 | 
			
		||||
            if (otherRegion == null)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            m_log.DebugFormat("[REGION CACHE]: (on region {0}) Region {1} is up @ {2}-{3}",
 | 
			
		||||
                m_scene.RegionInfo.RegionName, otherRegion.RegionName, otherRegion.RegionLocX, otherRegion.RegionLocY);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -345,7 +345,6 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
 | 
			
		|||
            mapItemReqThread.Priority = ThreadPriority.BelowNormal;
 | 
			
		||||
            mapItemReqThread.SetApartmentState(ApartmentState.MTA);
 | 
			
		||||
            mapItemReqThread.Start();
 | 
			
		||||
            ThreadTracker.Add(mapItemReqThread);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
| 
						 | 
				
			
			@ -447,7 +446,6 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
 | 
			
		|||
                    // end gracefully
 | 
			
		||||
                    if (st.agentID == UUID.Zero)
 | 
			
		||||
                    {
 | 
			
		||||
                        ThreadTracker.Remove(mapItemReqThread);
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1168,6 +1168,7 @@ namespace OpenSim.Region.Framework.Scenes
 | 
			
		|||
 | 
			
		||||
        private void SendInventoryUpdate(IClientAPI client, InventoryFolderBase folder, bool fetchFolders, bool fetchItems)
 | 
			
		||||
        {
 | 
			
		||||
            m_log.DebugFormat("[AGENT INVENTORY]: Send Inventory Folder {0} Update to {1} {2}", folder.Name, client.FirstName, client.LastName);
 | 
			
		||||
            InventoryCollection contents = InventoryService.GetFolderContent(client.AgentId, folder.ID);
 | 
			
		||||
            client.SendInventoryFolderDetails(client.AgentId, folder.ID, contents.Items, contents.Folders, fetchFolders, fetchItems);
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -477,9 +477,9 @@ namespace OpenSim.Region.Framework.Scenes
 | 
			
		|||
        public InventoryCollection HandleFetchInventoryDescendentsCAPS(UUID agentID, UUID folderID, UUID ownerID,
 | 
			
		||||
                                                   bool fetchFolders, bool fetchItems, int sortOrder, out int version)
 | 
			
		||||
        {
 | 
			
		||||
//            m_log.DebugFormat(
 | 
			
		||||
//                "[INVENTORY CACHE]: Fetching folders ({0}), items ({1}) from {2} for agent {3}",
 | 
			
		||||
//                fetchFolders, fetchItems, folderID, agentID);
 | 
			
		||||
            m_log.DebugFormat(
 | 
			
		||||
                "[INVENTORY CACHE]: Fetching folders ({0}), items ({1}) from {2} for agent {3}",
 | 
			
		||||
                fetchFolders, fetchItems, folderID, agentID);
 | 
			
		||||
 | 
			
		||||
            // FIXME MAYBE: We're not handling sortOrder!
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -497,10 +497,11 @@ namespace OpenSim.Region.Framework.Scenes
 | 
			
		|||
                return ret;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            InventoryCollection contents = InventoryService.GetFolderContent(agentID, folderID);
 | 
			
		||||
            InventoryCollection contents = new InventoryCollection();
 | 
			
		||||
 | 
			
		||||
            if (folderID != UUID.Zero)
 | 
			
		||||
            {
 | 
			
		||||
                contents = InventoryService.GetFolderContent(agentID, folderID); 
 | 
			
		||||
                InventoryFolderBase containingFolder = new InventoryFolderBase();
 | 
			
		||||
                containingFolder.ID = folderID;
 | 
			
		||||
                containingFolder.Owner = agentID;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -903,7 +903,6 @@ namespace OpenSim.Region.Framework.Scenes
 | 
			
		|||
            //m_heartbeatTimer.Elapsed += new ElapsedEventHandler(Heartbeat);
 | 
			
		||||
            if (HeartbeatThread != null)
 | 
			
		||||
            {
 | 
			
		||||
                ThreadTracker.Remove(HeartbeatThread);
 | 
			
		||||
                HeartbeatThread.Abort();
 | 
			
		||||
                HeartbeatThread = null;
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -912,7 +911,6 @@ namespace OpenSim.Region.Framework.Scenes
 | 
			
		|||
            HeartbeatThread.SetApartmentState(ApartmentState.MTA);
 | 
			
		||||
            HeartbeatThread.Name = string.Format("Heartbeat for region {0}", RegionInfo.RegionName);
 | 
			
		||||
            HeartbeatThread.Priority = ThreadPriority.AboveNormal;
 | 
			
		||||
            ThreadTracker.Add(HeartbeatThread);
 | 
			
		||||
            HeartbeatThread.Start();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1448,6 +1446,9 @@ namespace OpenSim.Region.Framework.Scenes
 | 
			
		|||
            m_log.Info("[SCENE]: Loading objects from datastore");
 | 
			
		||||
 | 
			
		||||
            List<SceneObjectGroup> PrimsFromDB = m_storageManager.DataStore.LoadObjects(regionID);
 | 
			
		||||
 | 
			
		||||
            m_log.Info("[SCENE]: Loaded " + PrimsFromDB.Count + " objects from the datastore");
 | 
			
		||||
 | 
			
		||||
            foreach (SceneObjectGroup group in PrimsFromDB)
 | 
			
		||||
            {
 | 
			
		||||
                if (group.RootPart == null)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -360,7 +360,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
 | 
			
		|||
                    m_listener.Name = "IRCConnectorListenerThread";
 | 
			
		||||
                    m_listener.IsBackground = true;
 | 
			
		||||
                    m_listener.Start();
 | 
			
		||||
                    ThreadTracker.Add(m_listener);
 | 
			
		||||
 | 
			
		||||
                    // This is the message order recommended by RFC 2812
 | 
			
		||||
                    if (m_password != null)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -152,7 +152,6 @@ namespace OpenSim.Region.OptionalModules.ContentManagement
 | 
			
		|||
                m_thread.Name = "Content Management";
 | 
			
		||||
                m_thread.IsBackground = true;
 | 
			
		||||
                m_thread.Start();
 | 
			
		||||
                ThreadTracker.Add(m_thread);
 | 
			
		||||
                m_state = State.NONE;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -138,7 +138,6 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
 | 
			
		|||
            EventQueueThread.Priority = MyThreadPriority;
 | 
			
		||||
            EventQueueThread.Name = "EventQueueManagerThread_" + ThreadCount;
 | 
			
		||||
            EventQueueThread.Start();
 | 
			
		||||
            ThreadTracker.Add(EventQueueThread);
 | 
			
		||||
 | 
			
		||||
            // Look at this... Don't you wish everyone did that solid
 | 
			
		||||
            // coding everywhere? :P
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -97,7 +97,6 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
 | 
			
		|||
                MaintenanceThreadThread.Name = "ScriptMaintenanceThread";
 | 
			
		||||
                MaintenanceThreadThread.IsBackground = true;
 | 
			
		||||
                MaintenanceThreadThread.Start();
 | 
			
		||||
                ThreadTracker.Add(MaintenanceThreadThread);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -129,10 +129,6 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
 | 
			
		|||
 | 
			
		||||
        public void AddRegion(Scene Sceneworld)
 | 
			
		||||
        {
 | 
			
		||||
            m_log.Info("[" + ScriptEngineName + "]: ScriptEngine initializing");
 | 
			
		||||
 | 
			
		||||
            m_Scene = Sceneworld;
 | 
			
		||||
 | 
			
		||||
            // Make sure we have config
 | 
			
		||||
            if (ConfigSource.Configs[ScriptEngineName] == null)
 | 
			
		||||
                ConfigSource.AddConfig(ScriptEngineName);
 | 
			
		||||
| 
						 | 
				
			
			@ -143,6 +139,10 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
 | 
			
		|||
            if (!m_enabled)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            m_log.Info("[" + ScriptEngineName + "]: ScriptEngine initializing");
 | 
			
		||||
 | 
			
		||||
            m_Scene = Sceneworld;
 | 
			
		||||
 | 
			
		||||
            // Create all objects we'll be using
 | 
			
		||||
            m_EventQueueManager = new EventQueueManager(this);
 | 
			
		||||
            m_EventManager = new EventManager(this, true);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -142,7 +142,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
 | 
			
		|||
                cmdHandlerThread.Priority = ThreadPriority.BelowNormal;
 | 
			
		||||
                cmdHandlerThread.IsBackground = true;
 | 
			
		||||
                cmdHandlerThread.Start();
 | 
			
		||||
                ThreadTracker.Add(cmdHandlerThread);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -260,7 +260,7 @@ namespace OpenSim.Server.Base
 | 
			
		|||
 | 
			
		||||
        public static Dictionary<string, object> ParseXmlResponse(string data)
 | 
			
		||||
        {
 | 
			
		||||
            m_log.DebugFormat("[XXX]: received xml string: {0}", data);
 | 
			
		||||
            //m_log.DebugFormat("[XXX]: received xml string: {0}", data);
 | 
			
		||||
 | 
			
		||||
            Dictionary<string, object> ret = new Dictionary<string, object>();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -77,6 +77,7 @@ namespace OpenSim.Server.Handlers.Inventory
 | 
			
		|||
            m_doLookup = serverConfig.GetBoolean("SessionAuthentication", false);
 | 
			
		||||
 | 
			
		||||
            AddHttpHandlers(server);
 | 
			
		||||
            m_log.Debug("[INVENTORY HANDLER]: handlers initialized");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected virtual void AddHttpHandlers(IHttpServer m_httpServer)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -99,7 +99,7 @@ namespace OpenSim.Services.Connectors
 | 
			
		|||
            sendData["METHOD"] = "register";
 | 
			
		||||
 | 
			
		||||
            string reqString = ServerUtils.BuildQueryString(sendData);
 | 
			
		||||
            //m_log.DebugFormat("[GRID CONNECTOR]: queryString = {0}", reqString);
 | 
			
		||||
            // m_log.DebugFormat("[GRID CONNECTOR]: queryString = {0}", reqString);
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                string reply = SynchronousRestFormsRequester.MakeRequest("POST",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -416,13 +416,6 @@ namespace OpenSim.Services.Connectors
 | 
			
		|||
                     e.Source, e.Message);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            foreach (InventoryItemBase item in items)
 | 
			
		||||
            {
 | 
			
		||||
                InventoryItemBase itm = this.QueryItem(userID, item, sessionID);
 | 
			
		||||
                itm.Name = item.Name;
 | 
			
		||||
                itm.Folder = item.Folder;
 | 
			
		||||
                this.UpdateItem(userID, itm, sessionID);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void MoveItemsCompleted(IAsyncResult iar)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -76,10 +76,12 @@ namespace OpenSim.Services.Connectors
 | 
			
		|||
                // Don't remote-call this instance; that's a startup hickup
 | 
			
		||||
                !((regInfo.ExternalHostName == thisRegion.ExternalHostName) && (regInfo.HttpPort == thisRegion.HttpPort)))
 | 
			
		||||
            {
 | 
			
		||||
                DoHelloNeighbourCall(regInfo, thisRegion);
 | 
			
		||||
                if (!DoHelloNeighbourCall(regInfo, thisRegion))
 | 
			
		||||
                    return null;
 | 
			
		||||
            }
 | 
			
		||||
            //else
 | 
			
		||||
            //    m_log.Warn("[REST COMMS]: Region not found " + regionHandle);
 | 
			
		||||
            else
 | 
			
		||||
                return null;
 | 
			
		||||
 | 
			
		||||
            return regInfo;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -102,6 +104,7 @@ namespace OpenSim.Services.Connectors
 | 
			
		|||
            catch (Exception e)
 | 
			
		||||
            {
 | 
			
		||||
                m_log.Debug("[REST COMMS]: PackRegionInfoData failed with exception: " + e.Message);
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            // Add the regionhandle of the destination region
 | 
			
		||||
            args["destination_handle"] = OSD.FromString(region.RegionHandle.ToString());
 | 
			
		||||
| 
						 | 
				
			
			@ -118,7 +121,7 @@ namespace OpenSim.Services.Connectors
 | 
			
		|||
            catch (Exception e)
 | 
			
		||||
            {
 | 
			
		||||
                m_log.WarnFormat("[REST COMMS]: Exception thrown on serialization of HelloNeighbour: {0}", e.Message);
 | 
			
		||||
                // ignore. buffer will be empty, caller should check.
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Stream os = null;
 | 
			
		||||
| 
						 | 
				
			
			@ -127,20 +130,23 @@ namespace OpenSim.Services.Connectors
 | 
			
		|||
                HelloNeighbourRequest.ContentLength = buffer.Length;   //Count bytes to send
 | 
			
		||||
                os = HelloNeighbourRequest.GetRequestStream();
 | 
			
		||||
                os.Write(buffer, 0, strBuffer.Length);         //Send it
 | 
			
		||||
                os.Close();
 | 
			
		||||
                //m_log.InfoFormat("[REST COMMS]: Posted HelloNeighbour request to remote sim {0}", uri);
 | 
			
		||||
            }
 | 
			
		||||
            //catch (WebException ex)
 | 
			
		||||
            catch
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
                //m_log.InfoFormat("[REST COMMS]: Bad send on HelloNeighbour {0}", ex.Message);
 | 
			
		||||
 | 
			
		||||
                m_log.InfoFormat("[REST COMMS]: Unable to send HelloNeighbour to {0}: {1}", region.RegionName, ex.Message);
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            finally
 | 
			
		||||
            {
 | 
			
		||||
                if (os != null)
 | 
			
		||||
                    os.Close();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Let's wait for the response
 | 
			
		||||
            //m_log.Info("[REST COMMS]: Waiting for a reply after DoHelloNeighbourCall");
 | 
			
		||||
 | 
			
		||||
            StreamReader sr = null;
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                WebResponse webResponse = HelloNeighbourRequest.GetResponse();
 | 
			
		||||
| 
						 | 
				
			
			@ -149,17 +155,21 @@ namespace OpenSim.Services.Connectors
 | 
			
		|||
                    m_log.Info("[REST COMMS]: Null reply on DoHelloNeighbourCall post");
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                StreamReader sr = new StreamReader(webResponse.GetResponseStream());
 | 
			
		||||
                sr = new StreamReader(webResponse.GetResponseStream());
 | 
			
		||||
                //reply = sr.ReadToEnd().Trim();
 | 
			
		||||
                sr.ReadToEnd().Trim();
 | 
			
		||||
                sr.Close();
 | 
			
		||||
                //m_log.InfoFormat("[REST COMMS]: DoHelloNeighbourCall reply was {0} ", reply);
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
            catch (WebException ex)
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
                m_log.InfoFormat("[REST COMMS]: exception on reply of DoHelloNeighbourCall {0}", ex.Message);
 | 
			
		||||
                // ignore, really
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            finally
 | 
			
		||||
            {
 | 
			
		||||
                if (sr != null)
 | 
			
		||||
                    sr.Close();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -200,6 +200,7 @@ namespace OpenSim.Services.GridService
 | 
			
		|||
            rdata.RegionName = rinfo.RegionName;
 | 
			
		||||
            rdata.Data = rinfo.ToKeyValuePairs();
 | 
			
		||||
            rdata.Data["regionHandle"] = Utils.UIntsToLong((uint)rdata.posX, (uint)rdata.posY);
 | 
			
		||||
            rdata.Data["owner_uuid"] = rinfo.EstateOwner.ToString();
 | 
			
		||||
            return rdata;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -140,6 +140,14 @@ namespace OpenSim.Services.Interfaces
 | 
			
		|||
        }
 | 
			
		||||
        protected int m_regionLocY;
 | 
			
		||||
 | 
			
		||||
        protected UUID m_estateOwner;
 | 
			
		||||
 | 
			
		||||
        public UUID EstateOwner
 | 
			
		||||
        {
 | 
			
		||||
            get { return m_estateOwner; }
 | 
			
		||||
            set { m_estateOwner = value; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public UUID RegionID = UUID.Zero;
 | 
			
		||||
        public UUID ScopeID = UUID.Zero;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -191,6 +199,7 @@ namespace OpenSim.Services.Interfaces
 | 
			
		|||
            Access = ConvertFrom.AccessLevel;
 | 
			
		||||
            Maturity = ConvertFrom.RegionSettings.Maturity;
 | 
			
		||||
            RegionSecret = ConvertFrom.regionSecret;
 | 
			
		||||
            EstateOwner = ConvertFrom.EstateSettings.EstateOwner;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public GridRegion(GridRegion ConvertFrom)
 | 
			
		||||
| 
						 | 
				
			
			@ -207,6 +216,7 @@ namespace OpenSim.Services.Interfaces
 | 
			
		|||
            Access = ConvertFrom.Access;
 | 
			
		||||
            Maturity = ConvertFrom.Maturity;
 | 
			
		||||
            RegionSecret = ConvertFrom.RegionSecret;
 | 
			
		||||
            EstateOwner = ConvertFrom.EstateOwner;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <value>
 | 
			
		||||
| 
						 | 
				
			
			@ -291,6 +301,7 @@ namespace OpenSim.Services.Interfaces
 | 
			
		|||
            kvp["regionMapTexture"] = TerrainImage.ToString();
 | 
			
		||||
            kvp["access"] = Access.ToString();
 | 
			
		||||
            kvp["regionSecret"] = RegionSecret;
 | 
			
		||||
            kvp["owner_uuid"] = EstateOwner.ToString();
 | 
			
		||||
            // Maturity doesn't seem to exist in the DB
 | 
			
		||||
            return kvp;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -345,6 +356,9 @@ namespace OpenSim.Services.Interfaces
 | 
			
		|||
            if (kvp.ContainsKey("regionSecret"))
 | 
			
		||||
                RegionSecret =(string)kvp["regionSecret"];
 | 
			
		||||
 | 
			
		||||
            if (kvp.ContainsKey("owner_uuid"))
 | 
			
		||||
                EstateOwner = new UUID(kvp["owner_uuid"].ToString());
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -115,7 +115,6 @@ namespace OpenSim.TestSuite
 | 
			
		|||
            m_td[pos].IsBackground = true;
 | 
			
		||||
            m_td[pos].Start();
 | 
			
		||||
            m_lBot.Add(pb);
 | 
			
		||||
            ThreadTracker.Add(m_td[pos]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -149,7 +149,6 @@ namespace pCampBot
 | 
			
		|||
            m_td[pos].IsBackground = true;
 | 
			
		||||
            m_td[pos].Start();
 | 
			
		||||
            m_lBot.Add(pb);
 | 
			
		||||
            ThreadTracker.Add(m_td[pos]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										10
									
								
								prebuild.xml
								
								
								
								
							
							
						
						
									
										10
									
								
								prebuild.xml
								
								
								
								
							| 
						 | 
				
			
			@ -131,6 +131,7 @@
 | 
			
		|||
 | 
			
		||||
      <ReferencePath>../../bin/</ReferencePath>
 | 
			
		||||
      <Reference name="System"/>
 | 
			
		||||
      <Reference name="System.Core"/>
 | 
			
		||||
      <Reference name="System.Xml"/>
 | 
			
		||||
      <Reference name="System.Data"/>
 | 
			
		||||
      <Reference name="System.Drawing"/>
 | 
			
		||||
| 
						 | 
				
			
			@ -724,7 +725,6 @@
 | 
			
		|||
      <Reference name="System"/>
 | 
			
		||||
      <Reference name="System.Xml"/>
 | 
			
		||||
      <Reference name="System.Drawing"/>
 | 
			
		||||
      <Reference name="System.Runtime.Remoting"/>
 | 
			
		||||
      <Reference name="System.Web"/>
 | 
			
		||||
      <Reference name="OpenMetaverseTypes.dll"/>
 | 
			
		||||
      <Reference name="OpenMetaverse.StructuredData.dll"/>
 | 
			
		||||
| 
						 | 
				
			
			@ -805,7 +805,6 @@
 | 
			
		|||
      <Reference name="System"/>
 | 
			
		||||
      <Reference name="System.Xml"/>
 | 
			
		||||
      <Reference name="System.Data"/>
 | 
			
		||||
      <Reference name="System.Runtime.Remoting"/>
 | 
			
		||||
      <Reference name="OpenSim.Framework"/>
 | 
			
		||||
      <Reference name="OpenSim.Data" />
 | 
			
		||||
      <Reference name="OpenSim.Framework.Communications" />
 | 
			
		||||
| 
						 | 
				
			
			@ -1539,7 +1538,6 @@
 | 
			
		|||
      <Reference name="System"/>
 | 
			
		||||
      <Reference name="System.Xml"/>
 | 
			
		||||
      <Reference name="System.Drawing"/>
 | 
			
		||||
      <Reference name="System.Runtime.Remoting"/>
 | 
			
		||||
      <Reference name="System.Web"/>
 | 
			
		||||
      <Reference name="OpenMetaverseTypes.dll"/>
 | 
			
		||||
      <Reference name="OpenMetaverse.StructuredData.dll"/>
 | 
			
		||||
| 
						 | 
				
			
			@ -1624,7 +1622,6 @@
 | 
			
		|||
      <Reference name="System"/>
 | 
			
		||||
      <Reference name="System.Xml"/>
 | 
			
		||||
      <Reference name="System.Drawing"/>
 | 
			
		||||
      <Reference name="System.Runtime.Remoting"/>
 | 
			
		||||
      <Reference name="System.Web"/>
 | 
			
		||||
      <Reference name="OpenMetaverseTypes.dll"/>
 | 
			
		||||
      <Reference name="OpenMetaverse.StructuredData.dll"/>
 | 
			
		||||
| 
						 | 
				
			
			@ -1682,7 +1679,6 @@
 | 
			
		|||
      <ReferencePath>../../../../bin/</ReferencePath>
 | 
			
		||||
      <Reference name="System"/>
 | 
			
		||||
      <Reference name="System.Drawing"/>
 | 
			
		||||
      <Reference name="System.Runtime.Remoting"/>
 | 
			
		||||
      <Reference name="System.Xml"/>
 | 
			
		||||
      <Reference name="OpenSim.Data"/>
 | 
			
		||||
      <Reference name="OpenSim.Framework"/>
 | 
			
		||||
| 
						 | 
				
			
			@ -1755,6 +1751,7 @@
 | 
			
		|||
 | 
			
		||||
      <ReferencePath>../../../../bin/</ReferencePath>
 | 
			
		||||
      <Reference name="System"/>
 | 
			
		||||
      <Reference name="System.Core"/>
 | 
			
		||||
      <Reference name="System.Xml"/>
 | 
			
		||||
      <Reference name="OpenMetaverseTypes.dll"/>
 | 
			
		||||
      <Reference name="OpenMetaverse.StructuredData.dll"/>
 | 
			
		||||
| 
						 | 
				
			
			@ -3590,7 +3587,6 @@
 | 
			
		|||
      <Reference name="System"/>
 | 
			
		||||
      <Reference name="System.Xml"/>
 | 
			
		||||
      <Reference name="System.Drawing"/>
 | 
			
		||||
      <Reference name="System.Runtime.Remoting"/>
 | 
			
		||||
      <Reference name="OpenMetaverseTypes.dll"/>
 | 
			
		||||
      <Reference name="OpenMetaverse.dll"/>
 | 
			
		||||
      <Reference name="OpenSim.Data"/>
 | 
			
		||||
| 
						 | 
				
			
			@ -3695,6 +3691,7 @@
 | 
			
		|||
      </Files>
 | 
			
		||||
    </Project>
 | 
			
		||||
 | 
			
		||||
    <!-- Commented for now until new unit tests are written for the new LLUDP implementation
 | 
			
		||||
    <Project frameworkVersion="v3_5" name="OpenSim.Region.ClientStack.LindenUDP.Tests" path="OpenSim/Region/ClientStack/LindenUDP/Tests" type="Library">
 | 
			
		||||
      <Configuration name="Debug">
 | 
			
		||||
        <Options>
 | 
			
		||||
| 
						 | 
				
			
			@ -3728,6 +3725,7 @@
 | 
			
		|||
        <Match pattern="*.cs" recurse="false"/>
 | 
			
		||||
      </Files>
 | 
			
		||||
    </Project>
 | 
			
		||||
    -->
 | 
			
		||||
 | 
			
		||||
    <Project frameworkVersion="v3_5" name="OpenSim.Region.ScriptEngine.Tests" path="OpenSim/Region/ScriptEngine" type="Library">
 | 
			
		||||
      <Configuration name="Debug">
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue