* 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 LLClientViewprioritization
parent
3828b3c0e8
commit
82ace481c9
|
@ -82,8 +82,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
/// <summary>ACKs that are queued up, waiting to be sent to the client</summary>
|
||||
public readonly LocklessQueue<uint> PendingAcks = new LocklessQueue<uint>();
|
||||
|
||||
/// <summary>Reference to the IClientAPI for this client</summary>
|
||||
public LLClientView ClientAPI;
|
||||
/// <summary>Current packet sequence number</summary>
|
||||
public int CurrentSequence;
|
||||
/// <summary>Current ping sequence number</summary>
|
||||
|
|
|
@ -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<PacketAckPacket.PacketsBlock> blocks = new List<PacketAckPacket.PacketsBlock>();
|
||||
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<OutgoingPacket> expiredPackets = client.NeedAcks.GetExpiredPackets(client.RTO);
|
||||
List<OutgoingPacket> 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);
|
||||
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 (ThreadAbortException)
|
||||
else
|
||||
{
|
||||
// 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", 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue