From 56a27c37d3e84495988e423be7b52007cea595cc Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Thu, 8 Oct 2009 21:51:53 -0700 Subject: Simplified LLUDPClientCollection from three collections down to one. This will prevent any potential problems from inconsistency between the internal collections --- .../Region/ClientStack/LindenUDP/LLUDPServer.cs | 46 ++++++++-------------- 1 file changed, 16 insertions(+), 30 deletions(-) (limited to 'OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 1e6927f..a6aa048 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -181,22 +181,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP return x == m_location; } - public void RemoveClient(IClientAPI client) + public void RemoveClient(LLUDPClient udpClient) { - m_scene.ClientManager.Remove(client.CircuitCode); - client.Close(false); + m_log.Debug("[LLUDPSERVER]: Removing LLUDPClient for " + udpClient.ClientAPI.Name); - LLUDPClient udpClient; - if (clients.TryGetValue(client.AgentId, out udpClient)) - { - m_log.Debug("[LLUDPSERVER]: Removing LLUDPClient for " + client.Name); - udpClient.Shutdown(); - clients.Remove(client.AgentId, udpClient.RemoteEndPoint); - } - else - { - m_log.Warn("[LLUDPSERVER]: Failed to remove LLUDPClient for " + client.Name); - } + m_scene.ClientManager.Remove(udpClient.CircuitCode); + udpClient.ClientAPI.Close(false); + udpClient.Shutdown(); + clients.Remove(udpClient.RemoteEndPoint); } public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting) @@ -230,15 +222,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } - public void SendPacket(UUID agentID, Packet packet, ThrottleOutPacketType category, bool allowSplitting) - { - LLUDPClient client; - if (clients.TryGetValue(agentID, out client)) - SendPacket(client, packet, category, allowSplitting); - else - m_log.Warn("[LLUDPSERVER]: Attempted to send a packet to unknown agentID " + agentID); - } - public void SendPacket(LLUDPClient client, Packet packet, ThrottleOutPacketType category, bool allowSplitting) { // CoarseLocationUpdate packets cannot be split in an automated way @@ -391,7 +374,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP { m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + client.ClientAPI.Name); - RemoveClient(client.ClientAPI); + RemoveClient(client); return; } } @@ -647,23 +630,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP private void AddClient(uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo) { // Create the LLUDPClient - LLUDPClient client = new LLUDPClient(this, m_throttleRates, m_throttle, circuitCode, agentID, remoteEndPoint); + LLUDPClient udpClient = new LLUDPClient(this, m_throttleRates, m_throttle, circuitCode, agentID, remoteEndPoint); // Create the LLClientView - LLClientView clientApi = new LLClientView(remoteEndPoint, m_scene, this, client, sessionInfo, agentID, sessionID, circuitCode); + LLClientView clientApi = new LLClientView(remoteEndPoint, m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); clientApi.OnViewerEffect += m_scene.ClientManager.ViewerEffectHandler; clientApi.OnLogout += LogoutHandler; - clientApi.OnConnectionClosed += RemoveClient; + clientApi.OnConnectionClosed += + delegate(IClientAPI client) + { if (client is LLClientView) RemoveClient(((LLClientView)client).UDPClient); }; // Start the IClientAPI m_scene.ClientManager.Add(circuitCode, clientApi); clientApi.Start(); // Give LLUDPClient a reference to IClientAPI - client.ClientAPI = clientApi; + udpClient.ClientAPI = clientApi; // Add the new client to our list of tracked clients - clients.Add(agentID, client.RemoteEndPoint, client); + clients.Add(udpClient.RemoteEndPoint, udpClient); } private void AcknowledgePacket(LLUDPClient client, uint ack, int currentTime, bool fromResend) @@ -798,7 +783,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP private void LogoutHandler(IClientAPI client) { client.SendLogoutPacket(); - RemoveClient(client); + if (client is LLClientView) + RemoveClient(((LLClientView)client).UDPClient); } } } -- cgit v1.1 From a5b9971fd77c0c4bf70656be7f3e7999f59d9f85 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Fri, 9 Oct 2009 01:53:06 -0700 Subject: * Added a lock object for the write functions in LLUDPClientCollection (immutable != concurrent write safety) * Allow the UDP server to bind to a user-specified port again * Updated to a newer version of OpenSimUDPBase that streamlines the code even more. This also reintroduces the highly concurrent packet handling which needs more testing --- OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index a6aa048..9aeea9a 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 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 @@ -115,7 +115,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP public Socket Server { get { return null; } } public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) - : base((int)port) + : base(listenIP, (int)port) { #region Environment.TickCount Measurement @@ -143,7 +143,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP public new void Start() { if (m_scene == null) - throw new InvalidOperationException("Cannot LLUDPServer.Start() without an IScene reference"); + throw new InvalidOperationException("[LLUDPSERVER]: Cannot LLUDPServer.Start() without an IScene reference"); base.Start(); @@ -188,7 +188,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_scene.ClientManager.Remove(udpClient.CircuitCode); udpClient.ClientAPI.Close(false); udpClient.Shutdown(); - clients.Remove(udpClient.RemoteEndPoint); + m_clients.Remove(udpClient.RemoteEndPoint); } public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting) @@ -208,7 +208,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP for (int i = 0; i < packetCount; i++) { byte[] data = datas[i]; - clients.ForEach( + m_clients.ForEach( delegate(LLUDPClient client) { SendPacketData(client, data, data.Length, packet.Type, packet.Header.Zerocoded, category); }); } @@ -216,7 +216,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP else { byte[] data = packet.ToBytes(); - clients.ForEach( + m_clients.ForEach( delegate(LLUDPClient client) { SendPacketData(client, data, data.Length, packet.Type, packet.Header.Zerocoded, category); }); } @@ -502,7 +502,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } // Determine which agent this packet came from - if (!clients.TryGetValue(address, out client)) + if (!m_clients.TryGetValue(address, out client)) { m_log.Warn("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address); return; @@ -606,7 +606,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (m_scene.RegionStatus != RegionStatus.SlaveScene) { AuthenticateResponse sessionInfo; - bool isNewCircuit = !clients.ContainsKey(remoteEndPoint); + bool isNewCircuit = !m_clients.ContainsKey(remoteEndPoint); if (!IsClientAuthorized(useCircuitCode, out sessionInfo)) { @@ -648,7 +648,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP udpClient.ClientAPI = clientApi; // Add the new client to our list of tracked clients - clients.Add(udpClient.RemoteEndPoint, udpClient); + m_clients.Add(udpClient.RemoteEndPoint, udpClient); } private void AcknowledgePacket(LLUDPClient client, uint ack, int currentTime, bool fromResend) @@ -726,7 +726,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP elapsed500MS = 0; } - clients.ForEach( + m_clients.ForEach( delegate(LLUDPClient client) { if (client.DequeueOutgoing()) -- cgit v1.1 From a3e31cdeafbcfd371291213413b6d0d97a71c13b Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Fri, 9 Oct 2009 02:13:21 -0700 Subject: Added more debugging output to the "unrecognized source" warning --- OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 9aeea9a..7052e0e 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -504,7 +504,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Determine which agent this packet came from if (!m_clients.TryGetValue(address, out client)) { - m_log.Warn("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address); + m_log.Warn("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + + ", currently tracking " + m_clients.Count + " clients"); return; } -- cgit v1.1 From 29543514e6a8ad91a90e244a9488e9d0408f45bf Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Fri, 9 Oct 2009 16:33:50 -0700 Subject: * Changed the "Packet exceeded buffer size" log line to debug and include the packet type. This message is normal, but could be evidence of a message marked for zerocoding that probably shouldn't be * Changing OpenSimUDPBase back to high concurrency. High concurrency mode seems to make other problems happen faster, so it's helpful for working out other bugs and will probably --- OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 7052e0e..fcb2cd0 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -268,7 +268,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP // The packet grew larger than the bufferSize while zerocoding. // Remove the MSG_ZEROCODED flag and send the unencoded data // instead - m_log.Info("[LLUDPSERVER]: Packet exceeded buffer size during zerocoding. Removing MSG_ZEROCODED flag"); + m_log.Debug("[LLUDPSERVER]: Packet exceeded buffer size during zerocoding for " + type + ". Removing MSG_ZEROCODED flag"); data[0] = (byte)(data[0] & ~Helpers.MSG_ZEROCODED); Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); } -- cgit v1.1 From 3828b3c0e86bbb444dabadcc6e509675b058639e Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Tue, 13 Oct 2009 10:38:35 -0700 Subject: * Eliminated unnecessary parameters from LLUDPServer.SendPacketData() * Changed PrimMesher's Quat.Identity to return <0,0,0,1> instead of <0,0,0,1.1> --- OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index fcb2cd0..07764cb 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -210,7 +210,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP byte[] data = datas[i]; m_clients.ForEach( delegate(LLUDPClient client) - { SendPacketData(client, data, data.Length, packet.Type, packet.Header.Zerocoded, category); }); + { SendPacketData(client, data, packet.Type, category); }); } } else @@ -218,7 +218,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP byte[] data = packet.ToBytes(); m_clients.ForEach( delegate(LLUDPClient client) - { SendPacketData(client, data, data.Length, packet.Type, packet.Header.Zerocoded, category); }); + { SendPacketData(client, data, packet.Type, category); }); } } @@ -239,18 +239,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP for (int i = 0; i < packetCount; i++) { byte[] data = datas[i]; - SendPacketData(client, data, data.Length, packet.Type, packet.Header.Zerocoded, category); + SendPacketData(client, data, packet.Type, category); } } else { byte[] data = packet.ToBytes(); - SendPacketData(client, data, data.Length, packet.Type, packet.Header.Zerocoded, category); + SendPacketData(client, data, packet.Type, category); } } - public void SendPacketData(LLUDPClient client, byte[] data, int dataLength, PacketType type, bool doZerocode, ThrottleOutPacketType category) + public void SendPacketData(LLUDPClient client, byte[] data, PacketType type, ThrottleOutPacketType category) { + int dataLength = data.Length; + bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0; + // Frequency analysis of outgoing packet sizes shows a large clump of packets at each end of the spectrum. // The vast majority of packets are less than 200 bytes, although due to asset transfers and packet splitting // there are a decent number of packets in the 1000-1140 byte range. We allocate one of two sizes of data here -- cgit v1.1 From 82ace481c9ea180e7e5b9d6d7c7c191e438fdbe1 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Tue, 13 Oct 2009 11:14:45 -0700 Subject: * Broke the circular reference between LLClientView and LLUDPClient. This should speed up garbage collection on the large LLClientView objects, and also prevents handling packets for disconnected clients * Renamed local LLUDPClient variables to udpClient to avoid naming confusion between LLUDPClient and LLClientView --- .../Region/ClientStack/LindenUDP/LLUDPServer.cs | 134 ++++++++++++--------- 1 file changed, 77 insertions(+), 57 deletions(-) (limited to 'OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 07764cb..0b5b51d 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -183,10 +183,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP public void RemoveClient(LLUDPClient udpClient) { - m_log.Debug("[LLUDPSERVER]: Removing LLUDPClient for " + udpClient.ClientAPI.Name); + m_log.Debug("[LLUDPSERVER]: Removing LLUDPClient for " + udpClient.AgentID); - m_scene.ClientManager.Remove(udpClient.CircuitCode); - udpClient.ClientAPI.Close(false); + // 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); } @@ -222,7 +229,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } - public void SendPacket(LLUDPClient client, Packet packet, ThrottleOutPacketType category, bool allowSplitting) + public void SendPacket(LLUDPClient udpClient, Packet packet, ThrottleOutPacketType category, bool allowSplitting) { // CoarseLocationUpdate packets cannot be split in an automated way if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting) @@ -239,17 +246,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP for (int i = 0; i < packetCount; i++) { byte[] data = datas[i]; - SendPacketData(client, data, packet.Type, category); + SendPacketData(udpClient, data, packet.Type, category); } } else { byte[] data = packet.ToBytes(); - SendPacketData(client, data, packet.Type, category); + SendPacketData(udpClient, data, packet.Type, category); } } - public void SendPacketData(LLUDPClient client, byte[] data, PacketType type, ThrottleOutPacketType category) + public void SendPacketData(LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category) { int dataLength = data.Length; bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0; @@ -260,7 +267,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP // to accomodate for both common scenarios and provide ample room for ACK appending in both int bufferSize = (dataLength > 180) ? Packet.MTU : 200; - UDPPacketBuffer buffer = new UDPPacketBuffer(client.RemoteEndPoint, bufferSize); + UDPPacketBuffer buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize); // Zerocode if needed if (doZerocode) @@ -285,7 +292,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP #region Queue or Send // Look up the UDPClient this is going to - OutgoingPacket outgoingPacket = new OutgoingPacket(client, buffer, category); + OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category); if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) SendPacketFinal(outgoingPacket); @@ -293,18 +300,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP #endregion Queue or Send } - public void SendAcks(LLUDPClient client) + public void SendAcks(LLUDPClient udpClient) { uint ack; - if (client.PendingAcks.Dequeue(out ack)) + if (udpClient.PendingAcks.Dequeue(out ack)) { List blocks = new List(); PacketAckPacket.PacketsBlock block = new PacketAckPacket.PacketsBlock(); block.ID = ack; blocks.Add(block); - while (client.PendingAcks.Dequeue(out ack)) + while (udpClient.PendingAcks.Dequeue(out ack)) { block = new PacketAckPacket.PacketsBlock(); block.ID = ack; @@ -315,22 +322,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP packet.Header.Reliable = false; packet.Packets = blocks.ToArray(); - SendPacket(client, packet, ThrottleOutPacketType.Unknown, true); + SendPacket(udpClient, packet, ThrottleOutPacketType.Unknown, true); } } - public void SendPing(LLUDPClient client) + public void SendPing(LLUDPClient udpClient) { - IClientAPI api = client.ClientAPI; - if (api != null) - api.SendStartPingCheck(client.CurrentPingSequence++); + StartPingCheckPacket pc = (StartPingCheckPacket)PacketPool.Instance.GetPacket(PacketType.StartPingCheck); + pc.Header.Reliable = false; + + OutgoingPacket oldestPacket = udpClient.NeedAcks.GetOldest(); + + pc.PingID.PingID = (byte)udpClient.CurrentPingSequence++; + pc.PingID.OldestUnacked = (oldestPacket != null) ? oldestPacket.SequenceNumber : 0; + + SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false); } - public void ResendUnacked(LLUDPClient client) + public void ResendUnacked(LLUDPClient udpClient) { - if (client.NeedAcks.Count > 0) + if (udpClient.NeedAcks.Count > 0) { - List expiredPackets = client.NeedAcks.GetExpiredPackets(client.RTO); + List expiredPackets = udpClient.NeedAcks.GetExpiredPackets(udpClient.RTO); if (expiredPackets != null) { @@ -366,18 +379,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_log.DebugFormat("[LLUDPSERVER]: Dropping packet #{0} for agent {1} after {2} failed attempts", outgoingPacket.SequenceNumber, outgoingPacket.Client.RemoteEndPoint, outgoingPacket.ResendCount); - lock (client.NeedAcks.SyncRoot) - client.NeedAcks.RemoveUnsafe(outgoingPacket.SequenceNumber); + lock (udpClient.NeedAcks.SyncRoot) + udpClient.NeedAcks.RemoveUnsafe(outgoingPacket.SequenceNumber); //Interlocked.Increment(ref Stats.DroppedPackets); // Disconnect an agent if no packets are received for some time //FIXME: Make 60 an .ini setting - if (Environment.TickCount - client.TickLastPacketReceived > 1000 * 60) + if (Environment.TickCount - udpClient.TickLastPacketReceived > 1000 * 60) { - m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + client.ClientAPI.Name); + m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + udpClient.AgentID); - RemoveClient(client); + RemoveClient(udpClient); return; } } @@ -397,7 +410,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP byte flags = buffer.Data[0]; bool isResend = (flags & Helpers.MSG_RESENT) != 0; bool isReliable = (flags & Helpers.MSG_RELIABLE) != 0; - LLUDPClient client = outgoingPacket.Client; + LLUDPClient udpClient = outgoingPacket.Client; // Keep track of when this packet was sent out (right now) outgoingPacket.TickCount = Environment.TickCount; @@ -410,7 +423,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP // no more ACKs to append uint ackCount = 0; uint ack; - while (dataLength + 5 < buffer.Data.Length && client.PendingAcks.Dequeue(out ack)) + while (dataLength + 5 < buffer.Data.Length && udpClient.PendingAcks.Dequeue(out ack)) { Utils.UIntToBytesBig(ack, buffer.Data, dataLength); dataLength += 4; @@ -429,24 +442,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP #endregion ACK Appending + #region Sequence Number Assignment + if (!isResend) { // Not a resend, assign a new sequence number - uint sequenceNumber = (uint)Interlocked.Increment(ref client.CurrentSequence); + uint sequenceNumber = (uint)Interlocked.Increment(ref udpClient.CurrentSequence); Utils.UIntToBytesBig(sequenceNumber, buffer.Data, 1); outgoingPacket.SequenceNumber = sequenceNumber; if (isReliable) { // Add this packet to the list of ACK responses we are waiting on from the server - client.NeedAcks.Add(outgoingPacket); + udpClient.NeedAcks.Add(outgoingPacket); } } + #endregion Sequence Number Assignment + // Stats tracking - Interlocked.Increment(ref client.PacketsSent); + Interlocked.Increment(ref udpClient.PacketsSent); if (isReliable) - Interlocked.Add(ref client.UnackedBytes, outgoingPacket.Buffer.DataLength); + Interlocked.Add(ref udpClient.UnackedBytes, outgoingPacket.Buffer.DataLength); // Put the UDP payload on the wire AsyncBeginSend(buffer); @@ -455,7 +472,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP protected override void PacketReceived(UDPPacketBuffer buffer) { // Debugging/Profiling - //try { Thread.CurrentThread.Name = "PacketReceived (" + scene.RegionName + ")"; } + //try { Thread.CurrentThread.Name = "PacketReceived (" + m_scene.RegionInfo.RegionName + ")"; } //catch (Exception) { } LLUDPClient client = null; @@ -484,9 +501,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP return; } - //Stats.RecvBytes += (ulong)buffer.DataLength; - //++Stats.RecvPackets; - #endregion Decoding #region UseCircuitCode Handling @@ -508,7 +522,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (!m_clients.TryGetValue(address, out client)) { m_log.Warn("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + - ", currently tracking " + m_clients.Count + " clients"); + " in " + m_scene.RegionInfo.RegionName + ", currently tracking " + m_clients.Count + " clients"); return; } @@ -549,7 +563,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP #region ACK Sending if (packet.Header.Reliable) - client.PendingAcks.Enqueue((uint)packet.Header.Sequence); + client.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 @@ -648,9 +662,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_scene.ClientManager.Add(circuitCode, clientApi); clientApi.Start(); - // Give LLUDPClient a reference to IClientAPI - udpClient.ClientAPI = clientApi; - // Add the new client to our list of tracked clients m_clients.Add(udpClient.RemoteEndPoint, udpClient); } @@ -756,31 +767,40 @@ namespace OpenSim.Region.ClientStack.LindenUDP { IncomingPacket incomingPacket = (IncomingPacket)state; Packet packet = incomingPacket.Packet; - LLUDPClient client = incomingPacket.Client; + LLUDPClient udpClient = incomingPacket.Client; + IClientAPI client; // Sanity check - if (packet == null || client == null || client.ClientAPI == null) + if (packet == null || udpClient == null) { - m_log.WarnFormat("[LLUDPSERVER]: Processing a packet with incomplete state. Packet=\"{0}\", Client=\"{1}\", Client.ClientAPI=\"{2}\"", - packet, client, (client != null) ? client.ClientAPI : null); + m_log.WarnFormat("[LLUDPSERVER]: Processing a packet with incomplete state. Packet=\"{0}\", UDPClient=\"{1}\"", + packet, udpClient); } - try + // Make sure this client is still alive + if (m_scene.ClientManager.TryGetClient(udpClient.CircuitCode, out client)) { - // Process this packet - client.ClientAPI.ProcessInPacket(packet); - } - catch (ThreadAbortException) - { - // If something is trying to abort the packet processing thread, take that as a hint that it's time to shut down - m_log.Info("[LLUDPSERVER]: Caught a thread abort, shutting down the LLUDP server"); - Stop(); + try + { + // Process this packet + client.ProcessInPacket(packet); + } + catch (ThreadAbortException) + { + // If something is trying to abort the packet processing thread, take that as a hint that it's time to shut down + m_log.Info("[LLUDPSERVER]: Caught a thread abort, shutting down the LLUDP server"); + Stop(); + } + catch (Exception e) + { + // Don't let a failure in an individual client thread crash the whole sim. + m_log.ErrorFormat("[LLUDPSERVER]: Client packet handler for {0} for packet {1} threw an exception", udpClient.AgentID, packet.Type); + m_log.Error(e.Message, e); + } } - catch (Exception e) + else { - // Don't let a failure in an individual client thread crash the whole sim. - m_log.ErrorFormat("[LLUDPSERVER]: Client packet handler for {0} for packet {1} threw an exception", client.AgentID, packet.Type); - m_log.Error(e.Message, e); + m_log.DebugFormat("[LLUDPSERVER]: Dropping incoming {0} packet for dead client {1}", packet.Type, udpClient.AgentID); } } -- cgit v1.1 From f55b282078e4e7c5ee7d0ca613891302d2b9957d Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Tue, 13 Oct 2009 11:28:08 -0700 Subject: Avoid checking m_clients collection twice when a UseCircuitCode packet is received --- .../Region/ClientStack/LindenUDP/LLUDPServer.cs | 56 +++++++++++----------- 1 file changed, 29 insertions(+), 27 deletions(-) (limited to 'OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 0b5b51d..2228f39 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -503,19 +503,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP #endregion Decoding - #region UseCircuitCode Handling + #region Packet to Client Mapping + // UseCircuitCode handling if (packet.Type == PacketType.UseCircuitCode) { - UseCircuitCodePacket useCircuitCode = (UseCircuitCodePacket)packet; - IClientAPI newuser; - uint circuitCode = useCircuitCode.CircuitCode.Code; - - // Check if the client is already established - if (!m_scene.ClientManager.TryGetClient(circuitCode, out newuser)) - { - AddNewClient(useCircuitCode, (IPEndPoint)buffer.RemoteEndPoint); - } + AddNewClient((UseCircuitCodePacket)packet, (IPEndPoint)buffer.RemoteEndPoint); } // Determine which agent this packet came from @@ -526,7 +519,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP return; } - #endregion UseCircuitCode Handling + #endregion Packet to Client Mapping // Stats tracking Interlocked.Increment(ref client.PacketsReceived); @@ -620,29 +613,38 @@ namespace OpenSim.Region.ClientStack.LindenUDP private void AddNewClient(UseCircuitCodePacket useCircuitCode, IPEndPoint remoteEndPoint) { - //Slave regions don't accept new clients if (m_scene.RegionStatus != RegionStatus.SlaveScene) { - AuthenticateResponse sessionInfo; - bool isNewCircuit = !m_clients.ContainsKey(remoteEndPoint); - - if (!IsClientAuthorized(useCircuitCode, out sessionInfo)) + if (!m_clients.ContainsKey(remoteEndPoint)) { - m_log.WarnFormat( - "[CONNECTION FAILURE]: Connection request for client {0} connecting with unnotified circuit code {1} from {2}", - useCircuitCode.CircuitCode.ID, useCircuitCode.CircuitCode.Code, remoteEndPoint); - return; - } + AuthenticateResponse sessionInfo; + if (IsClientAuthorized(useCircuitCode, out sessionInfo)) + { + UUID agentID = useCircuitCode.CircuitCode.ID; + UUID sessionID = useCircuitCode.CircuitCode.SessionID; + uint circuitCode = useCircuitCode.CircuitCode.Code; - if (isNewCircuit) + 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); + } + } + else { - UUID agentID = useCircuitCode.CircuitCode.ID; - UUID sessionID = useCircuitCode.CircuitCode.SessionID; - uint circuitCode = useCircuitCode.CircuitCode.Code; - - AddClient(circuitCode, agentID, sessionID, remoteEndPoint, sessionInfo); + // Ignore repeated UseCircuitCode packets + m_log.Debug("[LLUDPSERVER]: Ignoring UseCircuitCode for already established circuit " + useCircuitCode.CircuitCode.Code); } } + else + { + // Slave regions don't accept new clients + m_log.Debug("[LLUDPSERVER]: Slave region " + m_scene.RegionInfo.RegionName + " ignoring UseCircuitCode packet"); + } } private void AddClient(uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo) -- cgit v1.1 From c893761319f7e61d13b2d2301180d0f227fde1a9 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Tue, 13 Oct 2009 12:50:59 -0700 Subject: * Unregister event handlers in LLUDPServer when a client logs out and disconnects * Move ViewerEffect handling to Scene.PacketHandlers * Removing the unused CloseAllAgents function * Trimming ClientManager down. This class needs to be reworked to keep LLUDP circuit codes from intruding into the abstract OpenSim core code --- OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 2228f39..04c9cb1 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -419,7 +419,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP int dataLength = buffer.DataLength; - // Keep appending ACKs until there is no room left in the packet or there are + // Keep appending ACKs until there is no room left in the buffer or there are // no more ACKs to append uint ackCount = 0; uint ack; @@ -654,11 +654,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Create the LLClientView LLClientView clientApi = new LLClientView(remoteEndPoint, m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); - clientApi.OnViewerEffect += m_scene.ClientManager.ViewerEffectHandler; clientApi.OnLogout += LogoutHandler; - clientApi.OnConnectionClosed += - delegate(IClientAPI client) - { if (client is LLClientView) RemoveClient(((LLClientView)client).UDPClient); }; + clientApi.OnConnectionClosed += ConnectionClosedHandler; // Start the IClientAPI m_scene.ClientManager.Add(circuitCode, clientApi); @@ -808,7 +805,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP private void LogoutHandler(IClientAPI client) { + client.OnLogout -= LogoutHandler; + client.SendLogoutPacket(); + + if (client is LLClientView) + RemoveClient(((LLClientView)client).UDPClient); + } + + private void ConnectionClosedHandler(IClientAPI client) + { + client.OnConnectionClosed -= ConnectionClosedHandler; + if (client is LLClientView) RemoveClient(((LLClientView)client).UDPClient); } -- cgit v1.1 From 23a334b9f54a1ef5df3b503c165e7b76b746a2b1 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Tue, 13 Oct 2009 14:50:03 -0700 Subject: * 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) --- .../Region/ClientStack/LindenUDP/LLUDPServer.cs | 163 +++++++++++---------- 1 file changed, 84 insertions(+), 79 deletions(-) (limited to 'OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 04c9cb1..8ec143a 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 { -- cgit v1.1 From 395a8680c3633ca131e7481f765517311ef51710 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Tue, 13 Oct 2009 16:53:19 -0700 Subject: * Fixed a bug where clients were being added to ClientManager twice * Changed the ClientManager interface to reduce potential errors with duplicate or mismatched keys * Added IClientAPI.RemoteEndPoint, which can (hopefully) eventually replace IClientAPI.CircuitCode * Changed the order of operations during client shutdown --- OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 8ec143a..22c275c 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -390,7 +390,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } - public void Flush() + public void Flush(LLUDPClient udpClient) { // FIXME: Implement? } @@ -645,15 +645,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP client.OnLogout += LogoutHandler; client.OnConnectionClosed += ConnectionClosedHandler; - m_scene.ClientManager.Add(agentID, remoteEndPoint, client); - // Start the IClientAPI - m_scene.ClientManager.Add(agentID, remoteEndPoint, client); + m_scene.ClientManager.Add(client); client.Start(); } else { - m_log.Debug("[LLUDPSERVER]: Ignoring a repeated UseCircuitCode from " + udpClient.AgentID); + m_log.WarnFormat("[LLUDPSERVER]: Ignoring a repeated UseCircuitCode from {0} at {1} for circuit {2}", + udpClient.AgentID, remoteEndPoint, circuitCode); } } -- cgit v1.1 From dc11643c007adf7a640ec4fbabe25995352aaa18 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Tue, 13 Oct 2009 17:33:45 -0700 Subject: * Consolidated adding / removing ClientManager IClientAPIs to two places in Scene * Added some missing implementations of IClientAPI.RemoteEndPoint * Added a ClientManager.Remove(UUID) overload * Removed a reference to a missing project from prebuild.xml --- OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) (limited to 'OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 22c275c..8689af3 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -646,7 +646,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP client.OnConnectionClosed += ConnectionClosedHandler; // Start the IClientAPI - m_scene.ClientManager.Add(client); client.Start(); } else @@ -658,10 +657,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP private void RemoveClient(LLUDPClient udpClient) { - // Remove this client from the scene ClientManager + // Remove this client from the scene IClientAPI client; if (m_scene.ClientManager.TryGetValue(udpClient.AgentID, out client)) - Util.FireAndForget(delegate(object o) { client.Close(); }); + client.Close(); } private void AcknowledgePacket(LLUDPClient client, uint ack, int currentTime, bool fromResend) @@ -810,19 +809,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP private void LogoutHandler(IClientAPI client) { client.OnLogout -= LogoutHandler; - client.SendLogoutPacket(); - - if (client is LLClientView) - RemoveClient(((LLClientView)client).UDPClient); } private void ConnectionClosedHandler(IClientAPI client) { client.OnConnectionClosed -= ConnectionClosedHandler; - - if (client is LLClientView) - RemoveClient(((LLClientView)client).UDPClient); + RemoveClient(((LLClientView)client).UDPClient); } } } -- cgit v1.1 From e8c1e69a0dbab1a7db894eeff6b052bbd350a8f5 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Tue, 13 Oct 2009 18:56:54 -0700 Subject: * Copied LocklessQueue.cs into OpenSim.Framework and added the .Count property and .Clear() method * Changed the way the QueueEmpty callback is fired. It will be fired asynchronously as soon as an empty queue is detected (this can happen immediately following a dequeue), and will not be fired again until at least one packet is dequeued from that queue. This will give callbacks advanced notice of an empty queue and prevent callbacks from stacking up while the queue is empty * Added LLUDPClient.IsConnected checks in several places to prevent unwanted network activity after a client disconnects * Prevent LLClientView.Close() from being called twice every disconnect * Removed the packet resend limit and improved the client timeout check --- .../Region/ClientStack/LindenUDP/LLUDPServer.cs | 107 +++++++++------------ 1 file changed, 48 insertions(+), 59 deletions(-) (limited to 'OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 8689af3..57fee59 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -332,8 +332,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP public void ResendUnacked(LLUDPClient udpClient) { - if (udpClient.NeedAcks.Count > 0) + if (udpClient.IsConnected && udpClient.NeedAcks.Count > 0) { + // Disconnect an agent if no packets are received for some time + //FIXME: Make 60 an .ini setting + if (Environment.TickCount - udpClient.TickLastPacketReceived > 1000 * 60) + { + m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + udpClient.AgentID); + + RemoveClient(udpClient); + return; + } + + // Get a list of all of the packets that have been sitting unacked longer than udpClient.RTO List expiredPackets = udpClient.NeedAcks.GetExpiredPackets(udpClient.RTO); if (expiredPackets != null) @@ -343,48 +354,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP { OutgoingPacket outgoingPacket = expiredPackets[i]; - // FIXME: Make this an .ini setting - if (outgoingPacket.ResendCount < 3) - { - //Logger.Debug(String.Format("Resending packet #{0} (attempt {1}), {2}ms have passed", - // outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount)); + //m_log.DebugFormat("[LLUDPSERVER]: Resending packet #{0} (attempt {1}), {2}ms have passed", + // outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount); - // Set the resent flag - outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT); - outgoingPacket.Category = ThrottleOutPacketType.Resend; + // Set the resent flag + outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT); + outgoingPacket.Category = ThrottleOutPacketType.Resend; - // The TickCount will be set to the current time when the packet - // is actually sent out again - outgoingPacket.TickCount = 0; + // The TickCount will be set to the current time when the packet + // is actually sent out again + outgoingPacket.TickCount = 0; - // Bump up the resend count on this packet - Interlocked.Increment(ref outgoingPacket.ResendCount); - //Interlocked.Increment(ref Stats.ResentPackets); + // Bump up the resend count on this packet + Interlocked.Increment(ref outgoingPacket.ResendCount); + //Interlocked.Increment(ref Stats.ResentPackets); - // Queue or (re)send the packet - if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) - SendPacketFinal(outgoingPacket); - } - else - { - m_log.DebugFormat("[LLUDPSERVER]: Dropping packet #{0} for agent {1} after {2} failed attempts", - outgoingPacket.SequenceNumber, outgoingPacket.Client.RemoteEndPoint, outgoingPacket.ResendCount); - - lock (udpClient.NeedAcks.SyncRoot) - udpClient.NeedAcks.RemoveUnsafe(outgoingPacket.SequenceNumber); - - //Interlocked.Increment(ref Stats.DroppedPackets); - - // Disconnect an agent if no packets are received for some time - //FIXME: Make 60 an .ini setting - if (Environment.TickCount - udpClient.TickLastPacketReceived > 1000 * 60) - { - m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + udpClient.AgentID); - - RemoveClient(udpClient); - return; - } - } + // Requeue or resend the packet + if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) + SendPacketFinal(outgoingPacket); } } } @@ -403,6 +390,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP bool isReliable = (flags & Helpers.MSG_RELIABLE) != 0; LLUDPClient udpClient = outgoingPacket.Client; + if (!udpClient.IsConnected) + return; + // Keep track of when this packet was sent out (right now) outgoingPacket.TickCount = Environment.TickCount; @@ -481,14 +471,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP } catch (MalformedDataException) { - m_log.ErrorFormat("[LLUDPSERVER]: Malformed data, cannot parse packet:\n{0}", - Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)); + m_log.ErrorFormat("[LLUDPSERVER]: Malformed data, cannot parse packet from {0}:\n{1}", + buffer.RemoteEndPoint, Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)); } // Fail-safe check if (packet == null) { - m_log.Warn("[LLUDPSERVER]: Couldn't build a message from the incoming data"); + m_log.Warn("[LLUDPSERVER]: Couldn't build a message from incoming data " + buffer.DataLength + + " bytes long from " + buffer.RemoteEndPoint); return; } @@ -513,6 +504,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP udpClient = ((LLClientView)client).UDPClient; + if (!udpClient.IsConnected) + return; + #endregion Packet to Client Mapping // Stats tracking @@ -643,7 +637,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP // 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 client.Start(); @@ -745,17 +738,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP { LLUDPClient udpClient = ((LLClientView)client).UDPClient; - if (udpClient.DequeueOutgoing()) - packetSent = true; - if (resendUnacked) - ResendUnacked(udpClient); - if (sendAcks) + if (udpClient.IsConnected) { - SendAcks(udpClient); - udpClient.SendPacketStats(); + if (udpClient.DequeueOutgoing()) + packetSent = true; + if (resendUnacked) + ResendUnacked(udpClient); + if (sendAcks) + { + SendAcks(udpClient); + udpClient.SendPacketStats(); + } + if (sendPings) + SendPing(udpClient); } - if (sendPings) - SendPing(udpClient); } } ); @@ -808,14 +804,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP private void LogoutHandler(IClientAPI client) { - client.OnLogout -= LogoutHandler; client.SendLogoutPacket(); } - - private void ConnectionClosedHandler(IClientAPI client) - { - client.OnConnectionClosed -= ConnectionClosedHandler; - RemoveClient(((LLClientView)client).UDPClient); - } } } -- cgit v1.1 From 0d2e6463d714bce8a6a628bd647c625feeeae8f6 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Wed, 14 Oct 2009 11:43:31 -0700 Subject: * Minimized the number of times textures are pulled off the priority queue * OnQueueEmpty is still called async, but will not be called for a given category if the previous callback for that category is still running. This is the most balanced behavior I could find, and seems to work well * Added support for the old [ClientStack.LindenUDP] settings (including setting the receive buffer size) and added the new token bucket and global throttle settings * Added the AssetLoaderEnabled config variable to optionally disable loading assets from XML every startup. This gives a dramatic improvement in startup times for those who don't need the functionality every startup --- OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 57fee59..1cfde91 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -109,6 +109,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP private Location m_location; /// The measured resolution of Environment.TickCount private float m_tickCountResolution; + /// The size of the receive buffer for the UDP socket. This value + /// is passed up to the operating system and used in the system networking + /// stack. Use zero to leave this value as the default + private int m_recvBufferSize; /// The measured resolution of Environment.TickCount public float TickCountResolution { get { return m_tickCountResolution; } } @@ -135,6 +139,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_circuitManager = circuitManager; + IConfig config = configSource.Configs["ClientStack.LindenUDP"]; + if (config != null) + { + m_recvBufferSize = config.GetInt("client_socket_rcvbuf_size", 0); + } + // TODO: Config support for throttling the entire connection m_throttle = new TokenBucket(null, 0, 0); m_throttleRates = new ThrottleRates(configSource); @@ -145,7 +155,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (m_scene == null) throw new InvalidOperationException("[LLUDPSERVER]: Cannot LLUDPServer.Start() without an IScene reference"); - base.Start(); + base.Start(m_recvBufferSize); // Start the incoming packet processing thread Thread incomingThread = new Thread(IncomingPacketHandler); -- cgit v1.1 From c033477d2faf1449685d471db243651f132a7632 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Wed, 14 Oct 2009 11:52:48 -0700 Subject: * Read scene_throttle_bps from the config file and use it * Minor formatting cleanup --- OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 1cfde91..384eda7 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -138,15 +138,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP #endregion Environment.TickCount Measurement m_circuitManager = circuitManager; + int sceneThrottleBps = 0; IConfig config = configSource.Configs["ClientStack.LindenUDP"]; if (config != null) { m_recvBufferSize = config.GetInt("client_socket_rcvbuf_size", 0); + sceneThrottleBps = config.GetInt("scene_throttle_max_bps", 0); } // TODO: Config support for throttling the entire connection - m_throttle = new TokenBucket(null, 0, 0); + m_throttle = new TokenBucket(null, sceneThrottleBps, sceneThrottleBps); m_throttleRates = new ThrottleRates(configSource); } -- cgit v1.1 From 1e9e9df0b3c2c6fad5e94db96c799bb31c193af1 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Wed, 14 Oct 2009 14:25:58 -0700 Subject: * Switched to a plain lock for the ClientManager collections and protected the TryGetValues with try/catch instead of a lock * Added ClientManager.ForEachSync() for operations that need to run synchronously, such as "show connections" --- OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 384eda7..09845d6 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -152,7 +152,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_throttleRates = new ThrottleRates(configSource); } - public new void Start() + public void Start() { if (m_scene == null) throw new InvalidOperationException("[LLUDPSERVER]: Cannot LLUDPServer.Start() without an IScene reference"); @@ -817,6 +817,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP private void LogoutHandler(IClientAPI client) { client.SendLogoutPacket(); + if (client.IsActive) + RemoveClient(((LLClientView)client).UDPClient); } } } -- cgit v1.1 From 82012ec4e3c441021795c66112a66e002d459e73 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Wed, 14 Oct 2009 16:21:48 -0700 Subject: * Clean up the SetThrottle() code and add a maxBurstRate parameter to allow more tweaking in the future --- OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs | 1 - 1 file changed, 1 deletion(-) (limited to 'OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 09845d6..890f701 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -147,7 +147,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP sceneThrottleBps = config.GetInt("scene_throttle_max_bps", 0); } - // TODO: Config support for throttling the entire connection m_throttle = new TokenBucket(null, sceneThrottleBps, sceneThrottleBps); m_throttleRates = new ThrottleRates(configSource); } -- cgit v1.1 From 06990b074c17c2201ed379bf1ae4c7191ab3187f Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Wed, 14 Oct 2009 16:48:27 -0700 Subject: Allow the LLUDP server to run in either synchronous or asynchronous mode with a config setting, defaulting to synchronous mode --- OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 890f701..545a0bc 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -113,6 +113,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// is passed up to the operating system and used in the system networking /// stack. Use zero to leave this value as the default private int m_recvBufferSize; + /// Flag to process packets asynchronously or synchronously + private bool m_asyncPacketHandling; /// The measured resolution of Environment.TickCount public float TickCountResolution { get { return m_tickCountResolution; } } @@ -143,6 +145,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP IConfig config = configSource.Configs["ClientStack.LindenUDP"]; if (config != null) { + m_asyncPacketHandling = config.GetBoolean("async_packet_handling", false); m_recvBufferSize = config.GetInt("client_socket_rcvbuf_size", 0); sceneThrottleBps = config.GetInt("scene_throttle_max_bps", 0); } @@ -156,7 +159,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (m_scene == null) throw new InvalidOperationException("[LLUDPSERVER]: Cannot LLUDPServer.Start() without an IScene reference"); - base.Start(m_recvBufferSize); + m_log.Info("[LLUDPSERVER]: Starting the LLUDP server in " + (m_asyncPacketHandling ? "asynchronous" : "synchronous") + " mode"); + + base.Start(m_recvBufferSize, m_asyncPacketHandling); // Start the incoming packet processing thread Thread incomingThread = new Thread(IncomingPacketHandler); -- cgit v1.1