From 23a334b9f54a1ef5df3b503c165e7b76b746a2b1 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Tue, 13 Oct 2009 14:50:03 -0700 Subject: [PATCH] * 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) --- .../Client/MXP/ClientStack/MXPClientView.cs | 17 +- .../MXP/PacketHandler/MXPPacketServer.cs | 2 +- .../VWoHTTP/ClientStack/VWHClientView.cs | 2 +- OpenSim/Framework/ClientManager.cs | 182 +++++++++++++++--- OpenSim/Framework/IClientAPI.cs | 2 +- .../ClientStack/LindenUDP/LLClientView.cs | 77 +++----- .../ClientStack/LindenUDP/LLUDPClient.cs | 1 - .../LindenUDP/LLUDPClientCollection.cs | 137 ------------- .../ClientStack/LindenUDP/LLUDPServer.cs | 163 ++++++++-------- .../CoreModules/Avatar/Gods/GodsModule.cs | 18 +- .../InterGrid/OpenGridProtocolModule.cs | 2 +- .../Examples/SimpleModule/MyNpcCharacter.cs | 2 +- .../Framework/Scenes/Scene.PacketHandlers.cs | 2 +- OpenSim/Region/Framework/Scenes/Scene.cs | 6 +- .../InternetRelayClientView/IRCStackModule.cs | 2 +- .../Server/IRCClientView.cs | 8 +- .../ContentManagementSystem/MetaEntity.cs | 10 +- .../OptionalModules/World/NPC/NPCAvatar.cs | 14 +- .../OptionalModules/World/NPC/NPCModule.cs | 2 +- OpenSim/Tests/Common/Mock/TestClient.cs | 2 +- prebuild.xml | 1 + 21 files changed, 317 insertions(+), 335 deletions(-) delete mode 100644 OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs diff --git a/OpenSim/Client/MXP/ClientStack/MXPClientView.cs b/OpenSim/Client/MXP/ClientStack/MXPClientView.cs index bc1b2e5445..bc02bc4186 100644 --- a/OpenSim/Client/MXP/ClientStack/MXPClientView.cs +++ b/OpenSim/Client/MXP/ClientStack/MXPClientView.cs @@ -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 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 diff --git a/OpenSim/Client/MXP/PacketHandler/MXPPacketServer.cs b/OpenSim/Client/MXP/PacketHandler/MXPPacketServer.cs index 4910ab1749..d5dc18f332 100644 --- a/OpenSim/Client/MXP/PacketHandler/MXPPacketServer.cs +++ b/OpenSim/Client/MXP/PacketHandler/MXPPacketServer.cs @@ -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."); diff --git a/OpenSim/Client/VWoHTTP/ClientStack/VWHClientView.cs b/OpenSim/Client/VWoHTTP/ClientStack/VWHClientView.cs index c649c5ab2a..9c24da5f92 100644 --- a/OpenSim/Client/VWoHTTP/ClientStack/VWHClientView.cs +++ b/OpenSim/Client/VWoHTTP/ClientStack/VWHClientView.cs @@ -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(); } diff --git a/OpenSim/Framework/ClientManager.cs b/OpenSim/Framework/ClientManager.cs index 5ebbbc1266..4edfabe6e5 100644 --- a/OpenSim/Framework/ClientManager.cs +++ b/OpenSim/Framework/ClientManager.cs @@ -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 { + /// + /// Maps from client AgentID and RemoteEndPoint values to IClientAPI + /// references for all of the connected clients + /// public class ClientManager { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + #region IComparers - private Dictionary m_clients = new Dictionary(); - - public void Add(uint circuitCode, IClientAPI client) + private sealed class UUIDComparer : IComparer { - 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 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 + { + 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 + + /// An immutable dictionary mapping from + /// to references + private ImmutableMap m_dict; + /// An immutable dictionary mapping from + /// to references + private ImmutableMap m_dict2; + /// Immutability grants thread safety for concurrent reads and + /// read-writes, but not concurrent writes + private object m_writeLock = new object(); + + /// Number of clients in the collection + public int Count { get { return m_dict.Count; } } + + /// + /// Default constructor + /// + public ClientManager() + { + m_dict = new ImmutableMap(new UUIDComparer()); + m_dict2 = new ImmutableMap(new IPEndPointComparer()); + } + + /// + /// Add a client reference to the collection if it does not already + /// exist + /// + /// UUID of the client + /// Remote endpoint of the client + /// Reference to the client object + /// True if the client reference was successfully added, + /// otherwise false if the given key already existed in the collection + 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; } } } + + /// + /// Remove a client from the collection + /// + /// UUID of the client + /// Remote endpoint of the client + public void Remove(UUID key, IPEndPoint key2) + { + lock (m_writeLock) + { + m_dict = m_dict.Delete(key); + m_dict2 = m_dict2.Delete(key2); + } + } + + /// + /// Resets the client collection + /// + public void Clear() + { + lock (m_writeLock) + { + m_dict = new ImmutableMap(new UUIDComparer()); + m_dict2 = new ImmutableMap(new IPEndPointComparer()); + } + } + + /// + /// Checks if a UUID is in the collection + /// + /// UUID to check for + /// True if the UUID was found in the collection, otherwise false + public bool ContainsKey(UUID key) + { + return m_dict.ContainsKey(key); + } + + /// + /// Checks if an endpoint is in the collection + /// + /// Endpoint to check for + /// True if the endpoint was found in the collection, otherwise false + public bool ContainsKey(IPEndPoint key) + { + return m_dict2.ContainsKey(key); + } + + /// + /// Attempts to fetch a value out of the collection + /// + /// UUID of the client to retrieve + /// Retrieved client, or null on lookup failure + /// True if the lookup succeeded, otherwise false + public bool TryGetValue(UUID key, out IClientAPI value) + { + return m_dict.TryGetValue(key, out value); + } + + /// + /// Attempts to fetch a value out of the collection + /// + /// Endpoint of the client to retrieve + /// Retrieved client, or null on lookup failure + /// True if the lookup succeeded, otherwise false + public bool TryGetValue(IPEndPoint key, out IClientAPI value) + { + return m_dict2.TryGetValue(key, out value); + } + + /// + /// Performs a given task in parallel for each of the elements in the + /// collection + /// + /// Action to perform on each element + public void ForEach(Action action) + { + Parallel.ForEach(m_dict.Values, action); + } } } diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index d3bd9e7f1e..99ea0d5112 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs @@ -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); /// diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index bc9cfcf7d8..86d0112322 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -403,39 +403,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP #region Client Methods /// - /// 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 /// - /// - 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() diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index 10e22d5a74..e5b2594078 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs @@ -181,7 +181,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// public void Shutdown() { - // TODO: Do we need to invalidate the circuit? IsConnected = false; } diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs deleted file mode 100644 index 4f375e4850..0000000000 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs +++ /dev/null @@ -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 -{ - /// - /// A thread safe mapping from endpoints to client references - /// - public sealed class UDPClientCollection - { - #region IComparers - - private sealed class IPEndPointComparer : IComparer - { - 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 - - /// An immutable dictionary mapping from - /// to references - private ImmutableMap m_dict; - /// Immutability grants thread safety for concurrent reads and - /// read-writes, but not concurrent writes - private object m_writeLock = new object(); - - /// Number of clients in the collection - public int Count { get { return m_dict.Count; } } - - /// - /// Default constructor - /// - public UDPClientCollection() - { - m_dict = new ImmutableMap(new IPEndPointComparer()); - } - - /// - /// Add a client reference to the collection - /// - /// Remote endpoint of the client - /// Reference to the client object - public void Add(IPEndPoint key, LLUDPClient value) - { - lock (m_writeLock) - m_dict = m_dict.Add(key, value); - } - - /// - /// Remove a client from the collection - /// - /// Remote endpoint of the client - public void Remove(IPEndPoint key) - { - lock (m_writeLock) - m_dict = m_dict.Delete(key); - } - - /// - /// Resets the client collection - /// - public void Clear() - { - lock (m_writeLock) - m_dict = new ImmutableMap(new IPEndPointComparer()); - } - - /// - /// Checks if an endpoint is in the collection - /// - /// Endpoint to check for - /// True if the endpoint was found in the collection, otherwise false - public bool ContainsKey(IPEndPoint key) - { - return m_dict.ContainsKey(key); - } - - /// - /// Attempts to fetch a value out of the collection - /// - /// Endpoint of the client to retrieve - /// Retrieved client, or null on lookup failure - /// True if the lookup succeeded, otherwise false - public bool TryGetValue(IPEndPoint key, out LLUDPClient value) - { - return m_dict.TryGetValue(key, out value); - } - - /// - /// Performs a given task in parallel for each of the elements in the - /// collection - /// - /// Action to perform on each element - public void ForEach(Action action) - { - Parallel.ForEach(m_dict.Values, action); - } - } -} diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 04c9cb1c0b..8ec143abc3 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -96,7 +96,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Incoming packets that are awaiting handling private OpenMetaverse.BlockingQueue packetInbox = new OpenMetaverse.BlockingQueue(); /// - private UDPClientCollection m_clients = new UDPClientCollection(); + //private UDPClientCollection m_clients = new UDPClientCollection(); /// Bandwidth throttle for this UDP server private TokenBucket m_throttle; /// Bandwidth throttle rates for this UDP server @@ -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 { diff --git a/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs index f94172883a..7855862f5f 100644 --- a/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs @@ -36,6 +36,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods { public class GodsModule : IRegionModule, IGodsModule { + /// Special UUID for actions that apply to all agents + 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 /// The message to send to the user after it's been turned into a field 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 diff --git a/OpenSim/Region/CoreModules/InterGrid/OpenGridProtocolModule.cs b/OpenSim/Region/CoreModules/InterGrid/OpenGridProtocolModule.cs index 7d6f1509a3..d636b1c943 100644 --- a/OpenSim/Region/CoreModules/InterGrid/OpenGridProtocolModule.cs +++ b/OpenSim/Region/CoreModules/InterGrid/OpenGridProtocolModule.cs @@ -1267,7 +1267,7 @@ namespace OpenSim.Region.CoreModules.InterGrid if (avToBeKilled.IsChildAgent) { m_mod.DeleteOGPState(avUUID); - avToBeKilled.ControllingClient.Close(true); + avToBeKilled.ControllingClient.Close(); } } } diff --git a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs index 8ad4844c7a..dcee824fef 100644 --- a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs +++ b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs @@ -813,7 +813,7 @@ namespace OpenSim.Region.Examples.SimpleModule { } - public void Close(bool ShutdownCircuit) + public void Close() { } diff --git a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs index dbbf67962b..ac89f7b7c5 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs @@ -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) diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index e81b07b513..bb718960af 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -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; } diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/IRCStackModule.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/IRCStackModule.cs index 4b199ac1fa..c962329a45 100644 --- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/IRCStackModule.cs +++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/IRCStackModule.cs @@ -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"); } diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs index 4364627190..a8acf0d6c6 100644 --- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs +++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs @@ -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(); } diff --git a/OpenSim/Region/OptionalModules/ContentManagementSystem/MetaEntity.cs b/OpenSim/Region/OptionalModules/ContentManagementSystem/MetaEntity.cs index d6dacbc6dd..b6513e2c4f 100644 --- a/OpenSim/Region/OptionalModules/ContentManagementSystem/MetaEntity.cs +++ b/OpenSim/Region/OptionalModules/ContentManagementSystem/MetaEntity.cs @@ -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); } ); } diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs index ac8b98c8d6..f7c63ace61 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs @@ -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) diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs index 30a2675ea4..eb7b0d77dd 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs @@ -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; diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs index 2b548905e0..ad90817ac1 100644 --- a/OpenSim/Tests/Common/Mock/TestClient.cs +++ b/OpenSim/Tests/Common/Mock/TestClient.cs @@ -865,7 +865,7 @@ namespace OpenSim.Tests.Common.Mock { } - public void Close(bool ShutdownCircuit) + public void Close() { m_scene.RemoveClient(AgentId); } diff --git a/prebuild.xml b/prebuild.xml index 028e5e734c..f15fadfe74 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -135,6 +135,7 @@ +