* Rewrote ClientManager to remove Lindenisms from OpenSim core, improve performance by removing locks, and replace LLUDPClientCollection
* Removed the confusing (and LL-specific) shutdowncircuit parameter from IClientAPI.Close() * Updated the LLUDP code to only use ClientManager instead of trying to synchronize ClientManager and m_clients * Remove clients asynchronously since it is a very slow operation (including a 2000ms sleep)prioritization
							parent
							
								
									c893761319
								
							
						
					
					
						commit
						23a334b9f5
					
				| 
						 | 
				
			
			@ -774,6 +774,11 @@ namespace OpenSim.Client.MXP.ClientStack
 | 
			
		|||
            get { return m_sessionID.CRC(); }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public IPEndPoint RemoteEndPoint
 | 
			
		||||
        {
 | 
			
		||||
            get { return Session.RemoteEndPoint; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SetDebugPacketLevel(int newDebug)
 | 
			
		||||
        {
 | 
			
		||||
            //m_debugLevel = newDebug;
 | 
			
		||||
| 
						 | 
				
			
			@ -798,9 +803,9 @@ namespace OpenSim.Client.MXP.ClientStack
 | 
			
		|||
                OnConnectionClosed(this);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Close(bool ShutdownCircuit)
 | 
			
		||||
        public void Close()
 | 
			
		||||
        {
 | 
			
		||||
            m_log.Info("[MXP ClientStack] Close Called with SC=" + ShutdownCircuit);
 | 
			
		||||
            m_log.Info("[MXP ClientStack] Close Called");
 | 
			
		||||
 | 
			
		||||
            // Tell the client to go
 | 
			
		||||
            SendLogoutPacket();
 | 
			
		||||
| 
						 | 
				
			
			@ -815,7 +820,7 @@ namespace OpenSim.Client.MXP.ClientStack
 | 
			
		|||
 | 
			
		||||
        public void Kick(string message)
 | 
			
		||||
        {
 | 
			
		||||
            Close(false);
 | 
			
		||||
            Close();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Start()
 | 
			
		||||
| 
						 | 
				
			
			@ -1448,7 +1453,7 @@ namespace OpenSim.Client.MXP.ClientStack
 | 
			
		|||
 | 
			
		||||
        public void Terminate()
 | 
			
		||||
        {
 | 
			
		||||
            Close(false);
 | 
			
		||||
            Close();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SendSetFollowCamProperties(UUID objectID, SortedDictionary<int, float> parameters)
 | 
			
		||||
| 
						 | 
				
			
			@ -1615,12 +1620,12 @@ namespace OpenSim.Client.MXP.ClientStack
 | 
			
		|||
        public void Disconnect(string reason)
 | 
			
		||||
        {
 | 
			
		||||
            Kick(reason);
 | 
			
		||||
            Close(true);
 | 
			
		||||
            Close();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Disconnect()
 | 
			
		||||
        {
 | 
			
		||||
            Close(true);
 | 
			
		||||
            Close();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        #endregion
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -341,7 +341,7 @@ namespace OpenSim.Client.MXP.PacketHandler
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
                                m_log.Debug("[MXP ClientStack]: Adding ClientView to Scene...");
 | 
			
		||||
                                scene.ClientManager.Add(client.CircuitCode, client);
 | 
			
		||||
                                scene.ClientManager.Add(client.AgentId, client.RemoteEndPoint, client);
 | 
			
		||||
                                m_log.Debug("[MXP ClientStack]: Added ClientView to Scene.");
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -415,7 +415,7 @@ namespace OpenSim.Client.VWoHTTP.ClientStack
 | 
			
		|||
            throw new System.NotImplementedException();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Close(bool ShutdownCircuit)
 | 
			
		||||
        public void Close()
 | 
			
		||||
        {
 | 
			
		||||
            throw new System.NotImplementedException();
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,56 +28,174 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using log4net;
 | 
			
		||||
using System.Net;
 | 
			
		||||
using BclExtras.Collections;
 | 
			
		||||
using OpenMetaverse;
 | 
			
		||||
using OpenMetaverse.Packets;
 | 
			
		||||
 | 
			
		||||
namespace OpenSim.Framework
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Maps from client AgentID and RemoteEndPoint values to IClientAPI
 | 
			
		||||
    /// references for all of the connected clients
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public class ClientManager
 | 
			
		||||
    {
 | 
			
		||||
        private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
 | 
			
		||||
        #region IComparers
 | 
			
		||||
 | 
			
		||||
        private Dictionary<uint, IClientAPI> m_clients = new Dictionary<uint, IClientAPI>();
 | 
			
		||||
 | 
			
		||||
        public void Add(uint circuitCode, IClientAPI client)
 | 
			
		||||
        private sealed class UUIDComparer : IComparer<UUID>
 | 
			
		||||
        {
 | 
			
		||||
            lock (m_clients)
 | 
			
		||||
                m_clients.Add(circuitCode, client);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public bool Remove(uint circuitCode)
 | 
			
		||||
        {
 | 
			
		||||
            lock (m_clients)
 | 
			
		||||
                return m_clients.Remove(circuitCode);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public bool TryGetClient(uint circuitCode, out IClientAPI user)
 | 
			
		||||
        {
 | 
			
		||||
            lock (m_clients)
 | 
			
		||||
                return m_clients.TryGetValue(circuitCode, out user);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void ForEachClient(Action<IClientAPI> action)
 | 
			
		||||
        {
 | 
			
		||||
            IClientAPI[] LocalClients;
 | 
			
		||||
            lock (m_clients)
 | 
			
		||||
            public int Compare(UUID x, UUID y)
 | 
			
		||||
            {
 | 
			
		||||
                LocalClients = new IClientAPI[m_clients.Count];
 | 
			
		||||
                m_clients.Values.CopyTo(LocalClients, 0);
 | 
			
		||||
                return x.CompareTo(y);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            for (int i = 0; i < LocalClients.Length; i++)
 | 
			
		||||
        private sealed class IPEndPointComparer : IComparer<IPEndPoint>
 | 
			
		||||
        {
 | 
			
		||||
            public int Compare(IPEndPoint x, IPEndPoint y)
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                if (x == null && y == null)
 | 
			
		||||
                    return 0;
 | 
			
		||||
                else if (x == null)
 | 
			
		||||
                    return -1;
 | 
			
		||||
                else if (y == null)
 | 
			
		||||
                    return 1;
 | 
			
		||||
 | 
			
		||||
                int result = x.Address.Address.CompareTo(y.Address.Address);
 | 
			
		||||
                if (result == 0) result = x.Port.CompareTo(y.Port);
 | 
			
		||||
 | 
			
		||||
                return result;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        #endregion IComparers
 | 
			
		||||
 | 
			
		||||
        /// <summary>An immutable dictionary mapping from <seealso cref="UUID"/>
 | 
			
		||||
        /// to <seealso cref="IClientAPI"/> references</summary>
 | 
			
		||||
        private ImmutableMap<UUID, IClientAPI> m_dict;
 | 
			
		||||
        /// <summary>An immutable dictionary mapping from <seealso cref="IPEndPoint"/>
 | 
			
		||||
        /// to <seealso cref="IClientAPI"/> references</summary>
 | 
			
		||||
        private ImmutableMap<IPEndPoint, IClientAPI> m_dict2;
 | 
			
		||||
        /// <summary>Immutability grants thread safety for concurrent reads and
 | 
			
		||||
        /// read-writes, but not concurrent writes</summary>
 | 
			
		||||
        private object m_writeLock = new object();
 | 
			
		||||
 | 
			
		||||
        /// <summary>Number of clients in the collection</summary>
 | 
			
		||||
        public int Count { get { return m_dict.Count; } }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Default constructor
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public ClientManager()
 | 
			
		||||
        {
 | 
			
		||||
            m_dict = new ImmutableMap<UUID, IClientAPI>(new UUIDComparer());
 | 
			
		||||
            m_dict2 = new ImmutableMap<IPEndPoint, IClientAPI>(new IPEndPointComparer());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Add a client reference to the collection if it does not already
 | 
			
		||||
        /// exist
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="key">UUID of the client</param>
 | 
			
		||||
        /// <param name="key2">Remote endpoint of the client</param>
 | 
			
		||||
        /// <param name="value">Reference to the client object</param>
 | 
			
		||||
        /// <returns>True if the client reference was successfully added,
 | 
			
		||||
        /// otherwise false if the given key already existed in the collection</returns>
 | 
			
		||||
        public bool Add(UUID key, IPEndPoint key2, IClientAPI value)
 | 
			
		||||
        {
 | 
			
		||||
            lock (m_writeLock)
 | 
			
		||||
            {
 | 
			
		||||
                if (!m_dict.ContainsKey(key) && !m_dict2.ContainsKey(key2))
 | 
			
		||||
                {
 | 
			
		||||
                    action(LocalClients[i]);
 | 
			
		||||
                    m_dict = m_dict.Add(key, value);
 | 
			
		||||
                    m_dict2 = m_dict2.Add(key2, value);
 | 
			
		||||
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception e)
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    m_log.Warn("[CLIENT]: Unable to do ForEachClient for one of the clients" + "\n Reason: " + e.ToString());
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Remove a client from the collection
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="key">UUID of the client</param>
 | 
			
		||||
        /// <param name="key2">Remote endpoint of the client</param>
 | 
			
		||||
        public void Remove(UUID key, IPEndPoint key2)
 | 
			
		||||
        {
 | 
			
		||||
            lock (m_writeLock)
 | 
			
		||||
            {
 | 
			
		||||
                m_dict = m_dict.Delete(key);
 | 
			
		||||
                m_dict2 = m_dict2.Delete(key2);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Resets the client collection
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public void Clear()
 | 
			
		||||
        {
 | 
			
		||||
            lock (m_writeLock)
 | 
			
		||||
            {
 | 
			
		||||
                m_dict = new ImmutableMap<UUID, IClientAPI>(new UUIDComparer());
 | 
			
		||||
                m_dict2 = new ImmutableMap<IPEndPoint, IClientAPI>(new IPEndPointComparer());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Checks if a UUID is in the collection
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="key">UUID to check for</param>
 | 
			
		||||
        /// <returns>True if the UUID was found in the collection, otherwise false</returns>
 | 
			
		||||
        public bool ContainsKey(UUID key)
 | 
			
		||||
        {
 | 
			
		||||
            return m_dict.ContainsKey(key);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Checks if an endpoint is in the collection
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="key">Endpoint to check for</param>
 | 
			
		||||
        /// <returns>True if the endpoint was found in the collection, otherwise false</returns>
 | 
			
		||||
        public bool ContainsKey(IPEndPoint key)
 | 
			
		||||
        {
 | 
			
		||||
            return m_dict2.ContainsKey(key);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Attempts to fetch a value out of the collection
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="key">UUID of the client to retrieve</param>
 | 
			
		||||
        /// <param name="value">Retrieved client, or null on lookup failure</param>
 | 
			
		||||
        /// <returns>True if the lookup succeeded, otherwise false</returns>
 | 
			
		||||
        public bool TryGetValue(UUID key, out IClientAPI value)
 | 
			
		||||
        {
 | 
			
		||||
            return m_dict.TryGetValue(key, out value);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Attempts to fetch a value out of the collection
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="key">Endpoint of the client to retrieve</param>
 | 
			
		||||
        /// <param name="value">Retrieved client, or null on lookup failure</param>
 | 
			
		||||
        /// <returns>True if the lookup succeeded, otherwise false</returns>
 | 
			
		||||
        public bool TryGetValue(IPEndPoint key, out IClientAPI value)
 | 
			
		||||
        {
 | 
			
		||||
            return m_dict2.TryGetValue(key, out value);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Performs a given task in parallel for each of the elements in the
 | 
			
		||||
        /// collection
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="action">Action to perform on each element</param>
 | 
			
		||||
        public void ForEach(Action<IClientAPI> action)
 | 
			
		||||
        {
 | 
			
		||||
            Parallel.ForEach<IClientAPI>(m_dict.Values, action);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -802,7 +802,7 @@ namespace OpenSim.Framework
 | 
			
		|||
 | 
			
		||||
        void InPacket(object NewPack);
 | 
			
		||||
        void ProcessInPacket(Packet NewPack);
 | 
			
		||||
        void Close(bool ShutdownCircuit);
 | 
			
		||||
        void Close();
 | 
			
		||||
        void Kick(string message);
 | 
			
		||||
        
 | 
			
		||||
        /// <summary>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -403,39 +403,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP
 | 
			
		|||
        #region Client Methods
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Close down the client view.  This *must* be the last method called, since the last  #
 | 
			
		||||
        /// statement of CloseCleanup() aborts the thread.
 | 
			
		||||
        /// Shut down the client view
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="shutdownCircuit"></param>
 | 
			
		||||
        public void Close(bool shutdownCircuit)
 | 
			
		||||
        public void Close()
 | 
			
		||||
        {
 | 
			
		||||
            m_log.DebugFormat(
 | 
			
		||||
                "[CLIENT]: Close has been called with shutdownCircuit = {0} for {1} attached to scene {2}",
 | 
			
		||||
                shutdownCircuit, Name, m_scene.RegionInfo.RegionName);
 | 
			
		||||
                "[CLIENT]: Close has been called for {0} attached to scene {1}",
 | 
			
		||||
                Name, m_scene.RegionInfo.RegionName);
 | 
			
		||||
 | 
			
		||||
            // Remove ourselves from the scene
 | 
			
		||||
            m_scene.ClientManager.Remove(m_agentId, m_udpClient.RemoteEndPoint);
 | 
			
		||||
 | 
			
		||||
            if (m_imageManager != null)
 | 
			
		||||
            {
 | 
			
		||||
                m_imageManager.Close();
 | 
			
		||||
                m_imageManager = null;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (m_udpServer != null)
 | 
			
		||||
            {
 | 
			
		||||
                m_udpServer.Flush();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // raise an event on the packet server to Shutdown the circuit
 | 
			
		||||
            // Now, if we raise the event then the packet server will call this method itself, so don't try cleanup
 | 
			
		||||
            // here otherwise we'll end up calling it twice.
 | 
			
		||||
            // FIXME: In truth, I might be wrong but this whole business of calling this method twice (with different args) looks
 | 
			
		||||
            // horribly tangly.  Hopefully it should be possible to greatly simplify it.
 | 
			
		||||
            if (shutdownCircuit)
 | 
			
		||||
            {
 | 
			
		||||
                if (OnConnectionClosed != null)
 | 
			
		||||
                    OnConnectionClosed(this);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                CloseCleanup(shutdownCircuit);
 | 
			
		||||
            }
 | 
			
		||||
            if (OnConnectionClosed != null)
 | 
			
		||||
                OnConnectionClosed(this);
 | 
			
		||||
 | 
			
		||||
            CloseCleanup();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void CloseCleanup(bool shutdownCircuit)
 | 
			
		||||
        private void CloseCleanup()
 | 
			
		||||
        {
 | 
			
		||||
            m_scene.RemoveClient(AgentId);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -459,43 +455,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
 | 
			
		|||
                lock (m_primFullUpdateTimer)
 | 
			
		||||
                    m_primFullUpdateTimer.Stop();
 | 
			
		||||
 | 
			
		||||
            // This is just to give the client a reasonable chance of
 | 
			
		||||
            // flushing out all it's packets.  There should probably
 | 
			
		||||
            // be a better mechanism here
 | 
			
		||||
 | 
			
		||||
            // We can't reach into other scenes and close the connection
 | 
			
		||||
            // We need to do this over grid communications
 | 
			
		||||
            //m_scene.CloseAllAgents(CircuitCode);
 | 
			
		||||
 | 
			
		||||
            // If we're not shutting down the circuit, then this is the last time we'll go here.
 | 
			
		||||
            // If we are shutting down the circuit, the UDP Server will come back here with
 | 
			
		||||
            // ShutDownCircuit = false
 | 
			
		||||
            if (!(shutdownCircuit))
 | 
			
		||||
            {
 | 
			
		||||
                GC.Collect();
 | 
			
		||||
                m_imageManager = null;
 | 
			
		||||
                // Sends a KillPacket object, with which, the
 | 
			
		||||
                // blockingqueue dequeues and sees it's a killpacket
 | 
			
		||||
                // and terminates within the context of the client thread.
 | 
			
		||||
                // This ensures that it's done from within the context
 | 
			
		||||
                // of the client thread regardless of where Close() is called.
 | 
			
		||||
                KillEndDone();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            IsActive = false;
 | 
			
		||||
 | 
			
		||||
            m_avatarTerseUpdateTimer.Close();
 | 
			
		||||
            m_primTerseUpdateTimer.Close();
 | 
			
		||||
            m_primFullUpdateTimer.Close();
 | 
			
		||||
            m_avatarTerseUpdateTimer.Dispose();
 | 
			
		||||
            m_primTerseUpdateTimer.Dispose();
 | 
			
		||||
            m_primFullUpdateTimer.Dispose();
 | 
			
		||||
 | 
			
		||||
            //m_udpServer.OnPacketStats -= PopulateStats;
 | 
			
		||||
            // Disable UDP handling for this client
 | 
			
		||||
            m_udpClient.Shutdown();
 | 
			
		||||
 | 
			
		||||
            // wait for thread stoped
 | 
			
		||||
            // m_clientThread.Join();
 | 
			
		||||
 | 
			
		||||
            // delete circuit code
 | 
			
		||||
            //m_networkServer.CloseClient(this);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Kick(string message)
 | 
			
		||||
| 
						 | 
				
			
			@ -10225,7 +10196,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
 | 
			
		|||
 | 
			
		||||
        public void KillEndDone()
 | 
			
		||||
        {
 | 
			
		||||
            m_udpClient.Shutdown();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        #region IClientCore
 | 
			
		||||
| 
						 | 
				
			
			@ -10268,15 +10238,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
 | 
			
		|||
        {
 | 
			
		||||
            Kick(reason);
 | 
			
		||||
            Thread.Sleep(1000);
 | 
			
		||||
            Close(true);
 | 
			
		||||
            Close();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Disconnect()
 | 
			
		||||
        {
 | 
			
		||||
            Close(true);
 | 
			
		||||
            Close();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        #endregion
 | 
			
		||||
 | 
			
		||||
        public void RefreshGroupMembership()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -181,7 +181,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
 | 
			
		|||
        /// </summary>
 | 
			
		||||
        public void Shutdown()
 | 
			
		||||
        {
 | 
			
		||||
            // TODO: Do we need to invalidate the circuit?
 | 
			
		||||
            IsConnected = false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,137 +0,0 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) Contributors, http://opensimulator.org/
 | 
			
		||||
 * See CONTRIBUTORS.TXT for a full list of copyright holders.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms, with or without
 | 
			
		||||
 * modification, are permitted provided that the following conditions are met:
 | 
			
		||||
 *     * Redistributions of source code must retain the above copyright
 | 
			
		||||
 *       notice, this list of conditions and the following disclaimer.
 | 
			
		||||
 *     * Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
 *       notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
 *       documentation and/or other materials provided with the distribution.
 | 
			
		||||
 *     * Neither the name of the OpenSimulator Project nor the
 | 
			
		||||
 *       names of its contributors may be used to endorse or promote products
 | 
			
		||||
 *       derived from this software without specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
 | 
			
		||||
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 | 
			
		||||
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | 
			
		||||
 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
 | 
			
		||||
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 | 
			
		||||
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 | 
			
		||||
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 | 
			
		||||
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
			
		||||
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 | 
			
		||||
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Net;
 | 
			
		||||
using OpenSim.Framework;
 | 
			
		||||
using OpenMetaverse;
 | 
			
		||||
using BclExtras.Collections;
 | 
			
		||||
 | 
			
		||||
using ReaderWriterLockImpl = OpenMetaverse.ReaderWriterLockSlim;
 | 
			
		||||
 | 
			
		||||
namespace OpenSim.Region.ClientStack.LindenUDP
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// A thread safe mapping from endpoints to client references
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public sealed class UDPClientCollection
 | 
			
		||||
    {
 | 
			
		||||
        #region IComparers
 | 
			
		||||
 | 
			
		||||
        private sealed class IPEndPointComparer : IComparer<IPEndPoint>
 | 
			
		||||
        {
 | 
			
		||||
            public int Compare(IPEndPoint x, IPEndPoint y)
 | 
			
		||||
            {
 | 
			
		||||
                int result = x.Address.Address.CompareTo(y.Address.Address);
 | 
			
		||||
                if (result == 0) result = x.Port.CompareTo(y.Port);
 | 
			
		||||
                return result;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        #endregion IComparers
 | 
			
		||||
 | 
			
		||||
        /// <summary>An immutable dictionary mapping from <seealso cref="IPEndPoint"/>
 | 
			
		||||
        /// to <seealso cref="LLUDPClient"/> references</summary>
 | 
			
		||||
        private ImmutableMap<IPEndPoint, LLUDPClient> m_dict;
 | 
			
		||||
        /// <summary>Immutability grants thread safety for concurrent reads and
 | 
			
		||||
        /// read-writes, but not concurrent writes</summary>
 | 
			
		||||
        private object m_writeLock = new object();
 | 
			
		||||
 | 
			
		||||
        /// <summary>Number of clients in the collection</summary>
 | 
			
		||||
        public int Count { get { return m_dict.Count; } }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Default constructor
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public UDPClientCollection()
 | 
			
		||||
        {
 | 
			
		||||
            m_dict = new ImmutableMap<IPEndPoint, LLUDPClient>(new IPEndPointComparer());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Add a client reference to the collection
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="key">Remote endpoint of the client</param>
 | 
			
		||||
        /// <param name="value">Reference to the client object</param>
 | 
			
		||||
        public void Add(IPEndPoint key, LLUDPClient value)
 | 
			
		||||
        {
 | 
			
		||||
            lock (m_writeLock)
 | 
			
		||||
                m_dict = m_dict.Add(key, value);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Remove a client from the collection
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="key">Remote endpoint of the client</param>
 | 
			
		||||
        public void Remove(IPEndPoint key)
 | 
			
		||||
        {
 | 
			
		||||
            lock (m_writeLock)
 | 
			
		||||
                m_dict = m_dict.Delete(key);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Resets the client collection
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public void Clear()
 | 
			
		||||
        {
 | 
			
		||||
            lock (m_writeLock)
 | 
			
		||||
                m_dict = new ImmutableMap<IPEndPoint, LLUDPClient>(new IPEndPointComparer());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Checks if an endpoint is in the collection
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="key">Endpoint to check for</param>
 | 
			
		||||
        /// <returns>True if the endpoint was found in the collection, otherwise false</returns>
 | 
			
		||||
        public bool ContainsKey(IPEndPoint key)
 | 
			
		||||
        {
 | 
			
		||||
            return m_dict.ContainsKey(key);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Attempts to fetch a value out of the collection
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="key">Endpoint of the client to retrieve</param>
 | 
			
		||||
        /// <param name="value">Retrieved client, or null on lookup failure</param>
 | 
			
		||||
        /// <returns>True if the lookup succeeded, otherwise false</returns>
 | 
			
		||||
        public bool TryGetValue(IPEndPoint key, out LLUDPClient value)
 | 
			
		||||
        {
 | 
			
		||||
            return m_dict.TryGetValue(key, out value);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Performs a given task in parallel for each of the elements in the
 | 
			
		||||
        /// collection
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="action">Action to perform on each element</param>
 | 
			
		||||
        public void ForEach(Action<LLUDPClient> action)
 | 
			
		||||
        {
 | 
			
		||||
            Parallel.ForEach<LLUDPClient>(m_dict.Values, action);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -96,7 +96,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
 | 
			
		|||
        /// <summary>Incoming packets that are awaiting handling</summary>
 | 
			
		||||
        private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>();
 | 
			
		||||
        /// <summary></summary>
 | 
			
		||||
        private UDPClientCollection m_clients = new UDPClientCollection();
 | 
			
		||||
        //private UDPClientCollection m_clients = new UDPClientCollection();
 | 
			
		||||
        /// <summary>Bandwidth throttle for this UDP server</summary>
 | 
			
		||||
        private TokenBucket m_throttle;
 | 
			
		||||
        /// <summary>Bandwidth throttle rates for this UDP server</summary>
 | 
			
		||||
| 
						 | 
				
			
			@ -181,23 +181,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
 | 
			
		|||
            return x == m_location;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void RemoveClient(LLUDPClient udpClient)
 | 
			
		||||
        {
 | 
			
		||||
            m_log.Debug("[LLUDPSERVER]: Removing LLUDPClient for " + udpClient.AgentID);
 | 
			
		||||
 | 
			
		||||
            // Shut down the IClientAPI and remove it from the scene
 | 
			
		||||
            IClientAPI client;
 | 
			
		||||
            if (m_scene.ClientManager.TryGetClient(udpClient.CircuitCode, out client))
 | 
			
		||||
            {
 | 
			
		||||
                client.Close(false);
 | 
			
		||||
                m_scene.ClientManager.Remove(udpClient.CircuitCode);
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            // Shut down the LLUDPClient and remove it from the list of UDP clients
 | 
			
		||||
            udpClient.Shutdown();
 | 
			
		||||
            m_clients.Remove(udpClient.RemoteEndPoint);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting)
 | 
			
		||||
        {
 | 
			
		||||
            // CoarseLocationUpdate packets cannot be split in an automated way
 | 
			
		||||
| 
						 | 
				
			
			@ -215,17 +198,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
 | 
			
		|||
                for (int i = 0; i < packetCount; i++)
 | 
			
		||||
                {
 | 
			
		||||
                    byte[] data = datas[i];
 | 
			
		||||
                    m_clients.ForEach(
 | 
			
		||||
                        delegate(LLUDPClient client)
 | 
			
		||||
                        { SendPacketData(client, data, packet.Type, category); });
 | 
			
		||||
                    m_scene.ClientManager.ForEach(
 | 
			
		||||
                        delegate(IClientAPI client)
 | 
			
		||||
                        {
 | 
			
		||||
                            if (client is LLClientView)
 | 
			
		||||
                                SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category);
 | 
			
		||||
                        }
 | 
			
		||||
                    );
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                byte[] data = packet.ToBytes();
 | 
			
		||||
                m_clients.ForEach(
 | 
			
		||||
                    delegate(LLUDPClient client)
 | 
			
		||||
                    { SendPacketData(client, data, packet.Type, category); });
 | 
			
		||||
                m_scene.ClientManager.ForEach(
 | 
			
		||||
                    delegate(IClientAPI client)
 | 
			
		||||
                    {
 | 
			
		||||
                        if (client is LLClientView)
 | 
			
		||||
                            SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category);
 | 
			
		||||
                    }
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -475,7 +466,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
 | 
			
		|||
            //try { Thread.CurrentThread.Name = "PacketReceived (" + m_scene.RegionInfo.RegionName + ")"; }
 | 
			
		||||
            //catch (Exception) { }
 | 
			
		||||
 | 
			
		||||
            LLUDPClient client = null;
 | 
			
		||||
            LLUDPClient udpClient = null;
 | 
			
		||||
            Packet packet = null;
 | 
			
		||||
            int packetEnd = buffer.DataLength - 1;
 | 
			
		||||
            IPEndPoint address = (IPEndPoint)buffer.RemoteEndPoint;
 | 
			
		||||
| 
						 | 
				
			
			@ -512,30 +503,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP
 | 
			
		|||
            }
 | 
			
		||||
 | 
			
		||||
            // Determine which agent this packet came from
 | 
			
		||||
            if (!m_clients.TryGetValue(address, out client))
 | 
			
		||||
            IClientAPI client;
 | 
			
		||||
            if (!m_scene.ClientManager.TryGetValue(address, out client) || !(client is LLClientView))
 | 
			
		||||
            {
 | 
			
		||||
                m_log.Warn("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address +
 | 
			
		||||
                    " in " + m_scene.RegionInfo.RegionName + ", currently tracking " + m_clients.Count + " clients");
 | 
			
		||||
                    " in " + m_scene.RegionInfo.RegionName + ", currently tracking " + m_scene.ClientManager.Count + " clients");
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            udpClient = ((LLClientView)client).UDPClient;
 | 
			
		||||
 | 
			
		||||
            #endregion Packet to Client Mapping
 | 
			
		||||
 | 
			
		||||
            // Stats tracking
 | 
			
		||||
            Interlocked.Increment(ref client.PacketsReceived);
 | 
			
		||||
            Interlocked.Increment(ref udpClient.PacketsReceived);
 | 
			
		||||
 | 
			
		||||
            #region ACK Receiving
 | 
			
		||||
 | 
			
		||||
            int now = Environment.TickCount;
 | 
			
		||||
            client.TickLastPacketReceived = now;
 | 
			
		||||
            udpClient.TickLastPacketReceived = now;
 | 
			
		||||
 | 
			
		||||
            // Handle appended ACKs
 | 
			
		||||
            if (packet.Header.AppendedAcks && packet.Header.AckList != null)
 | 
			
		||||
            {
 | 
			
		||||
                lock (client.NeedAcks.SyncRoot)
 | 
			
		||||
                lock (udpClient.NeedAcks.SyncRoot)
 | 
			
		||||
                {
 | 
			
		||||
                    for (int i = 0; i < packet.Header.AckList.Length; i++)
 | 
			
		||||
                        AcknowledgePacket(client, packet.Header.AckList[i], now, packet.Header.Resent);
 | 
			
		||||
                        AcknowledgePacket(udpClient, packet.Header.AckList[i], now, packet.Header.Resent);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -544,10 +538,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
 | 
			
		|||
            {
 | 
			
		||||
                PacketAckPacket ackPacket = (PacketAckPacket)packet;
 | 
			
		||||
 | 
			
		||||
                lock (client.NeedAcks.SyncRoot)
 | 
			
		||||
                lock (udpClient.NeedAcks.SyncRoot)
 | 
			
		||||
                {
 | 
			
		||||
                    for (int i = 0; i < ackPacket.Packets.Length; i++)
 | 
			
		||||
                        AcknowledgePacket(client, ackPacket.Packets[i].ID, now, packet.Header.Resent);
 | 
			
		||||
                        AcknowledgePacket(udpClient, ackPacket.Packets[i].ID, now, packet.Header.Resent);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -556,27 +550,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
 | 
			
		|||
            #region ACK Sending
 | 
			
		||||
 | 
			
		||||
            if (packet.Header.Reliable)
 | 
			
		||||
                client.PendingAcks.Enqueue(packet.Header.Sequence);
 | 
			
		||||
                udpClient.PendingAcks.Enqueue(packet.Header.Sequence);
 | 
			
		||||
 | 
			
		||||
            // This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out,
 | 
			
		||||
            // add the current received bytes to it, test if 2*MTU bytes have been sent, if so remove
 | 
			
		||||
            // 2*MTU bytes from the value and send ACKs, and finally add the local value back to
 | 
			
		||||
            // client.BytesSinceLastACK. Lockless thread safety
 | 
			
		||||
            int bytesSinceLastACK = Interlocked.Exchange(ref client.BytesSinceLastACK, 0);
 | 
			
		||||
            int bytesSinceLastACK = Interlocked.Exchange(ref udpClient.BytesSinceLastACK, 0);
 | 
			
		||||
            bytesSinceLastACK += buffer.DataLength;
 | 
			
		||||
            if (bytesSinceLastACK > Packet.MTU * 2)
 | 
			
		||||
            {
 | 
			
		||||
                bytesSinceLastACK -= Packet.MTU * 2;
 | 
			
		||||
                SendAcks(client);
 | 
			
		||||
                SendAcks(udpClient);
 | 
			
		||||
            }
 | 
			
		||||
            Interlocked.Add(ref client.BytesSinceLastACK, bytesSinceLastACK);
 | 
			
		||||
            Interlocked.Add(ref udpClient.BytesSinceLastACK, bytesSinceLastACK);
 | 
			
		||||
 | 
			
		||||
            #endregion ACK Sending
 | 
			
		||||
 | 
			
		||||
            #region Incoming Packet Accounting
 | 
			
		||||
 | 
			
		||||
            // Check the archive of received reliable packet IDs to see whether we already received this packet
 | 
			
		||||
            if (packet.Header.Reliable && !client.PacketArchive.TryEnqueue(packet.Header.Sequence))
 | 
			
		||||
            if (packet.Header.Reliable && !udpClient.PacketArchive.TryEnqueue(packet.Header.Sequence))
 | 
			
		||||
            {
 | 
			
		||||
                if (packet.Header.Resent)
 | 
			
		||||
                    m_log.Debug("[LLUDPSERVER]: Received a resend of already processed packet #" + packet.Header.Sequence + ", type: " + packet.Type);
 | 
			
		||||
| 
						 | 
				
			
			@ -593,7 +587,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
 | 
			
		|||
            if (packet.Type != PacketType.PacketAck)
 | 
			
		||||
            {
 | 
			
		||||
                // Inbox insertion
 | 
			
		||||
                packetInbox.Enqueue(new IncomingPacket(client, packet));
 | 
			
		||||
                packetInbox.Enqueue(new IncomingPacket(udpClient, packet));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -613,31 +607,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP
 | 
			
		|||
 | 
			
		||||
        private void AddNewClient(UseCircuitCodePacket useCircuitCode, IPEndPoint remoteEndPoint)
 | 
			
		||||
        {
 | 
			
		||||
            UUID agentID = useCircuitCode.CircuitCode.ID;
 | 
			
		||||
            UUID sessionID = useCircuitCode.CircuitCode.SessionID;
 | 
			
		||||
            uint circuitCode = useCircuitCode.CircuitCode.Code;
 | 
			
		||||
 | 
			
		||||
            if (m_scene.RegionStatus != RegionStatus.SlaveScene)
 | 
			
		||||
            {
 | 
			
		||||
                if (!m_clients.ContainsKey(remoteEndPoint))
 | 
			
		||||
                AuthenticateResponse sessionInfo;
 | 
			
		||||
                if (IsClientAuthorized(useCircuitCode, out sessionInfo))
 | 
			
		||||
                {
 | 
			
		||||
                    AuthenticateResponse sessionInfo;
 | 
			
		||||
                    if (IsClientAuthorized(useCircuitCode, out sessionInfo))
 | 
			
		||||
                    {
 | 
			
		||||
                        UUID agentID = useCircuitCode.CircuitCode.ID;
 | 
			
		||||
                        UUID sessionID = useCircuitCode.CircuitCode.SessionID;
 | 
			
		||||
                        uint circuitCode = useCircuitCode.CircuitCode.Code;
 | 
			
		||||
 | 
			
		||||
                        AddClient(circuitCode, agentID, sessionID, remoteEndPoint, sessionInfo);
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        // Don't create circuits for unauthorized clients
 | 
			
		||||
                        m_log.WarnFormat(
 | 
			
		||||
                            "[LLUDPSERVER]: Connection request for client {0} connecting with unnotified circuit code {1} from {2}",
 | 
			
		||||
                            useCircuitCode.CircuitCode.ID, useCircuitCode.CircuitCode.Code, remoteEndPoint);
 | 
			
		||||
                    }
 | 
			
		||||
                    AddClient(circuitCode, agentID, sessionID, remoteEndPoint, sessionInfo);
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    // Ignore repeated UseCircuitCode packets
 | 
			
		||||
                    m_log.Debug("[LLUDPSERVER]: Ignoring UseCircuitCode for already established circuit " + useCircuitCode.CircuitCode.Code);
 | 
			
		||||
                    // Don't create circuits for unauthorized clients
 | 
			
		||||
                    m_log.WarnFormat(
 | 
			
		||||
                        "[LLUDPSERVER]: Connection request for client {0} connecting with unnotified circuit code {1} from {2}",
 | 
			
		||||
                        useCircuitCode.CircuitCode.ID, useCircuitCode.CircuitCode.Code, remoteEndPoint);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
| 
						 | 
				
			
			@ -652,17 +638,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP
 | 
			
		|||
            // Create the LLUDPClient
 | 
			
		||||
            LLUDPClient udpClient = new LLUDPClient(this, m_throttleRates, m_throttle, circuitCode, agentID, remoteEndPoint);
 | 
			
		||||
 | 
			
		||||
            // Create the LLClientView
 | 
			
		||||
            LLClientView clientApi = new LLClientView(remoteEndPoint, m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
 | 
			
		||||
            clientApi.OnLogout += LogoutHandler;
 | 
			
		||||
            clientApi.OnConnectionClosed += ConnectionClosedHandler;
 | 
			
		||||
            if (!m_scene.ClientManager.ContainsKey(agentID))
 | 
			
		||||
            {
 | 
			
		||||
                // Create the LLClientView
 | 
			
		||||
                LLClientView client = new LLClientView(remoteEndPoint, m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
 | 
			
		||||
                client.OnLogout += LogoutHandler;
 | 
			
		||||
                client.OnConnectionClosed += ConnectionClosedHandler;
 | 
			
		||||
 | 
			
		||||
            // Start the IClientAPI
 | 
			
		||||
            m_scene.ClientManager.Add(circuitCode, clientApi);
 | 
			
		||||
            clientApi.Start();
 | 
			
		||||
                m_scene.ClientManager.Add(agentID, remoteEndPoint, client);
 | 
			
		||||
 | 
			
		||||
            // Add the new client to our list of tracked clients
 | 
			
		||||
            m_clients.Add(udpClient.RemoteEndPoint, udpClient);
 | 
			
		||||
                // Start the IClientAPI
 | 
			
		||||
                m_scene.ClientManager.Add(agentID, remoteEndPoint, client);
 | 
			
		||||
                client.Start();
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                m_log.Debug("[LLUDPSERVER]: Ignoring a repeated UseCircuitCode from " + udpClient.AgentID);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void RemoveClient(LLUDPClient udpClient)
 | 
			
		||||
        {
 | 
			
		||||
            // Remove this client from the scene ClientManager
 | 
			
		||||
            IClientAPI client;
 | 
			
		||||
            if (m_scene.ClientManager.TryGetValue(udpClient.AgentID, out client))
 | 
			
		||||
                Util.FireAndForget(delegate(object o) { client.Close(); });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void AcknowledgePacket(LLUDPClient client, uint ack, int currentTime, bool fromResend)
 | 
			
		||||
| 
						 | 
				
			
			@ -740,20 +740,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
 | 
			
		|||
                    elapsed500MS = 0;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                m_clients.ForEach(
 | 
			
		||||
                    delegate(LLUDPClient client)
 | 
			
		||||
                m_scene.ClientManager.ForEach(
 | 
			
		||||
                    delegate(IClientAPI client)
 | 
			
		||||
                    {
 | 
			
		||||
                        if (client.DequeueOutgoing())
 | 
			
		||||
                            packetSent = true;
 | 
			
		||||
                        if (resendUnacked)
 | 
			
		||||
                            ResendUnacked(client);
 | 
			
		||||
                        if (sendAcks)
 | 
			
		||||
                        if (client is LLClientView)
 | 
			
		||||
                        {
 | 
			
		||||
                            SendAcks(client);
 | 
			
		||||
                            client.SendPacketStats();
 | 
			
		||||
                            LLUDPClient udpClient = ((LLClientView)client).UDPClient;
 | 
			
		||||
 | 
			
		||||
                            if (udpClient.DequeueOutgoing())
 | 
			
		||||
                                packetSent = true;
 | 
			
		||||
                            if (resendUnacked)
 | 
			
		||||
                                ResendUnacked(udpClient);
 | 
			
		||||
                            if (sendAcks)
 | 
			
		||||
                            {
 | 
			
		||||
                                SendAcks(udpClient);
 | 
			
		||||
                                udpClient.SendPacketStats();
 | 
			
		||||
                            }
 | 
			
		||||
                            if (sendPings)
 | 
			
		||||
                                SendPing(udpClient);
 | 
			
		||||
                        }
 | 
			
		||||
                        if (sendPings)
 | 
			
		||||
                            SendPing(client);
 | 
			
		||||
                    }
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -777,7 +782,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
 | 
			
		|||
            }
 | 
			
		||||
 | 
			
		||||
            // Make sure this client is still alive
 | 
			
		||||
            if (m_scene.ClientManager.TryGetClient(udpClient.CircuitCode, out client))
 | 
			
		||||
            if (m_scene.ClientManager.TryGetValue(udpClient.AgentID, out client))
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,6 +36,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods
 | 
			
		|||
{
 | 
			
		||||
    public class GodsModule : IRegionModule, IGodsModule
 | 
			
		||||
    {
 | 
			
		||||
        /// <summary>Special UUID for actions that apply to all agents</summary>
 | 
			
		||||
        private static readonly UUID ALL_AGENTS = new UUID("44e87126-e794-4ded-05b3-7c42da3d5cdb");
 | 
			
		||||
 | 
			
		||||
        protected Scene m_scene;
 | 
			
		||||
        protected IDialogModule m_dialogModule;
 | 
			
		||||
        
 | 
			
		||||
| 
						 | 
				
			
			@ -99,8 +102,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods
 | 
			
		|||
        /// <param name="reason">The message to send to the user after it's been turned into a field</param>
 | 
			
		||||
        public void KickUser(UUID godID, UUID sessionID, UUID agentID, uint kickflags, byte[] reason)
 | 
			
		||||
        {
 | 
			
		||||
            // For some reason the client sends this seemingly hard coded UUID for kicking everyone.   Dun-know.
 | 
			
		||||
            UUID kickUserID = new UUID("44e87126e7944ded05b37c42da3d5cdb");
 | 
			
		||||
            UUID kickUserID = ALL_AGENTS;
 | 
			
		||||
            
 | 
			
		||||
            ScenePresence sp = m_scene.GetScenePresence(agentID);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -110,15 +112,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods
 | 
			
		|||
                {
 | 
			
		||||
                    if (agentID == kickUserID)
 | 
			
		||||
                    {
 | 
			
		||||
                        m_scene.ClientManager.ForEachClient(
 | 
			
		||||
                        string reasonStr = Utils.BytesToString(reason);
 | 
			
		||||
 | 
			
		||||
                        m_scene.ClientManager.ForEach(
 | 
			
		||||
                            delegate(IClientAPI controller)
 | 
			
		||||
                            {
 | 
			
		||||
                                if (controller.AgentId != godID)
 | 
			
		||||
                                    controller.Kick(Utils.BytesToString(reason));
 | 
			
		||||
                                    controller.Kick(reasonStr);
 | 
			
		||||
                            }
 | 
			
		||||
                        );
 | 
			
		||||
 | 
			
		||||
                        // This is a bit crude.   It seems the client will be null before it actually stops the thread
 | 
			
		||||
                        // This is a bit crude. It seems the client will be null before it actually stops the thread
 | 
			
		||||
                        // The thread will kill itself eventually :/
 | 
			
		||||
                        // Is there another way to make sure *all* clients get this 'inter region' message?
 | 
			
		||||
                        m_scene.ForEachScenePresence(
 | 
			
		||||
| 
						 | 
				
			
			@ -128,7 +132,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods
 | 
			
		|||
                                {
 | 
			
		||||
                                    // Possibly this should really be p.Close() though that method doesn't send a close
 | 
			
		||||
                                    // to the client
 | 
			
		||||
                                    p.ControllingClient.Close(true);
 | 
			
		||||
                                    p.ControllingClient.Close();
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        );
 | 
			
		||||
| 
						 | 
				
			
			@ -138,7 +142,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods
 | 
			
		|||
                        m_scene.SceneGraph.removeUserCount(!sp.IsChildAgent);
 | 
			
		||||
 | 
			
		||||
                        sp.ControllingClient.Kick(Utils.BytesToString(reason));
 | 
			
		||||
                        sp.ControllingClient.Close(true);
 | 
			
		||||
                        sp.ControllingClient.Close();
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1267,7 +1267,7 @@ namespace OpenSim.Region.CoreModules.InterGrid
 | 
			
		|||
                if (avToBeKilled.IsChildAgent)
 | 
			
		||||
                {
 | 
			
		||||
                    m_mod.DeleteOGPState(avUUID);
 | 
			
		||||
                    avToBeKilled.ControllingClient.Close(true);
 | 
			
		||||
                    avToBeKilled.ControllingClient.Close();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -813,7 +813,7 @@ namespace OpenSim.Region.Examples.SimpleModule
 | 
			
		|||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Close(bool ShutdownCircuit)
 | 
			
		||||
        public void Close()
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -408,7 +408,7 @@ namespace OpenSim.Region.Framework.Scenes
 | 
			
		|||
            }
 | 
			
		||||
            ViewerEffectPacket.EffectBlock[] effectBlockArray = effectBlock.ToArray();
 | 
			
		||||
 | 
			
		||||
            ClientManager.ForEachClient(
 | 
			
		||||
            ClientManager.ForEach(
 | 
			
		||||
                delegate(IClientAPI client)
 | 
			
		||||
                {
 | 
			
		||||
                    if (client.AgentId != remoteClient.AgentId)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -867,7 +867,7 @@ namespace OpenSim.Region.Framework.Scenes
 | 
			
		|||
            Thread.Sleep(500);
 | 
			
		||||
 | 
			
		||||
            // Stop all client threads.
 | 
			
		||||
            ForEachScenePresence(delegate(ScenePresence avatar) { avatar.ControllingClient.Close(true); });
 | 
			
		||||
            ForEachScenePresence(delegate(ScenePresence avatar) { avatar.ControllingClient.Close(); });
 | 
			
		||||
 | 
			
		||||
            // Stop updating the scene objects and agents.
 | 
			
		||||
            //m_heartbeatTimer.Close();
 | 
			
		||||
| 
						 | 
				
			
			@ -3372,7 +3372,7 @@ namespace OpenSim.Region.Framework.Scenes
 | 
			
		|||
                    loggingOffUser.ControllingClient.Kick(message);
 | 
			
		||||
                    // Give them a second to receive the message!
 | 
			
		||||
                    Thread.Sleep(1000);
 | 
			
		||||
                    loggingOffUser.ControllingClient.Close(true);
 | 
			
		||||
                    loggingOffUser.ControllingClient.Close();
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
| 
						 | 
				
			
			@ -3543,7 +3543,7 @@ namespace OpenSim.Region.Framework.Scenes
 | 
			
		|||
                        presence.ControllingClient.SendShutdownConnectionNotice();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                presence.ControllingClient.Close(true);
 | 
			
		||||
                presence.ControllingClient.Close();
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -64,7 +64,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView
 | 
			
		|||
        void user_OnIRCReady(IRCClientView cv)
 | 
			
		||||
        {
 | 
			
		||||
            m_log.Info("[IRCd] Adding user...");
 | 
			
		||||
            m_scene.ClientManager.Add(cv.CircuitCode, cv);
 | 
			
		||||
            m_scene.ClientManager.Add(cv.AgentId, cv.RemoteEndPoint, cv);
 | 
			
		||||
            cv.Start();
 | 
			
		||||
            m_log.Info("[IRCd] Added user to Scene");
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -634,6 +634,12 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
 | 
			
		|||
        {
 | 
			
		||||
            get { return (uint)Util.RandomClass.Next(0,int.MaxValue); }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public IPEndPoint RemoteEndPoint
 | 
			
		||||
        {
 | 
			
		||||
            get { return (IPEndPoint)m_client.Client.RemoteEndPoint; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
#pragma warning disable 67
 | 
			
		||||
        public event GenericMessage OnGenericMessage;
 | 
			
		||||
        public event ImprovedInstantMessage OnInstantMessage;
 | 
			
		||||
| 
						 | 
				
			
			@ -843,7 +849,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
 | 
			
		|||
            
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Close(bool ShutdownCircuit)
 | 
			
		||||
        public void Close()
 | 
			
		||||
        {
 | 
			
		||||
            Disconnect();
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -183,8 +183,9 @@ namespace OpenSim.Region.OptionalModules.ContentManagement
 | 
			
		|||
        public virtual void HideFromAll()
 | 
			
		||||
        {
 | 
			
		||||
            foreach (SceneObjectPart part in m_Entity.Children.Values)
 | 
			
		||||
                m_Entity.Scene.ClientManager.ForEachClient(delegate(IClientAPI controller)
 | 
			
		||||
                                                           { controller.SendKillObject(m_Entity.RegionHandle, part.LocalId); }
 | 
			
		||||
                m_Entity.Scene.ClientManager.ForEach(
 | 
			
		||||
                    delegate(IClientAPI controller)
 | 
			
		||||
                    { controller.SendKillObject(m_Entity.RegionHandle, part.LocalId); }
 | 
			
		||||
                );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -201,8 +202,9 @@ namespace OpenSim.Region.OptionalModules.ContentManagement
 | 
			
		|||
 | 
			
		||||
        public void SendFullUpdateToAll()
 | 
			
		||||
        {
 | 
			
		||||
            m_Entity.Scene.ClientManager.ForEachClient(delegate(IClientAPI controller)
 | 
			
		||||
                                                       { m_Entity.SendFullUpdateToClient(controller); }
 | 
			
		||||
            m_Entity.Scene.ClientManager.ForEach(
 | 
			
		||||
                delegate(IClientAPI controller)
 | 
			
		||||
                { m_Entity.SendFullUpdateToClient(controller); }
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -825,7 +825,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
 | 
			
		|||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Close(bool ShutdownCircuit)
 | 
			
		||||
        public void Close()
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -838,11 +838,21 @@ namespace OpenSim.Region.OptionalModules.World.NPC
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        private uint m_circuitCode;
 | 
			
		||||
        private IPEndPoint m_remoteEndPoint;
 | 
			
		||||
 | 
			
		||||
        public uint CircuitCode
 | 
			
		||||
        {
 | 
			
		||||
            get { return m_circuitCode; }
 | 
			
		||||
            set { m_circuitCode = value; }
 | 
			
		||||
            set
 | 
			
		||||
            {
 | 
			
		||||
                m_circuitCode = value;
 | 
			
		||||
                m_remoteEndPoint = new IPEndPoint(IPAddress.Loopback, (ushort)m_circuitCode);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public IPEndPoint RemoteEndPoint
 | 
			
		||||
        {
 | 
			
		||||
            get { return m_remoteEndPoint; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SendBlueBoxMessage(UUID FromAvatarID, String FromAvatarName, String Message)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -155,7 +155,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
 | 
			
		|||
                    NPCAvatar npcAvatar = new NPCAvatar(p_firstname, p_lastname, p_position, p_scene);
 | 
			
		||||
                    npcAvatar.CircuitCode = (uint) Util.RandomClass.Next(0, int.MaxValue);
 | 
			
		||||
 | 
			
		||||
                    p_scene.ClientManager.Add(npcAvatar.CircuitCode, npcAvatar);
 | 
			
		||||
                    p_scene.ClientManager.Add(npcAvatar.AgentId, npcAvatar.RemoteEndPoint, npcAvatar);
 | 
			
		||||
                    p_scene.AddNewClient(npcAvatar);
 | 
			
		||||
 | 
			
		||||
                    ScenePresence sp;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -865,7 +865,7 @@ namespace OpenSim.Tests.Common.Mock
 | 
			
		|||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Close(bool ShutdownCircuit)
 | 
			
		||||
        public void Close()
 | 
			
		||||
        {
 | 
			
		||||
            m_scene.RemoveClient(AgentId);
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -135,6 +135,7 @@
 | 
			
		|||
      <Reference name="System.Xml"/>
 | 
			
		||||
      <Reference name="System.Data"/>
 | 
			
		||||
      <Reference name="System.Drawing"/>
 | 
			
		||||
      <Reference name="BclExtras.dll"/>
 | 
			
		||||
      <Reference name="OpenMetaverseTypes.dll"/>
 | 
			
		||||
      <Reference name="OpenMetaverse.dll"/>
 | 
			
		||||
      <Reference name="OpenMetaverse.StructuredData.dll"/>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue