* 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>
|
/// <summary>ACKs that are queued up, waiting to be sent to the client</summary>
|
||||||
public readonly LocklessQueue<uint> PendingAcks = new LocklessQueue<uint>();
|
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>
|
/// <summary>Current packet sequence number</summary>
|
||||||
public int CurrentSequence;
|
public int CurrentSequence;
|
||||||
/// <summary>Current ping sequence number</summary>
|
/// <summary>Current ping sequence number</summary>
|
||||||
|
|
|
@ -183,10 +183,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
|
|
||||||
public void RemoveClient(LLUDPClient udpClient)
|
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);
|
// Shut down the IClientAPI and remove it from the scene
|
||||||
udpClient.ClientAPI.Close(false);
|
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();
|
udpClient.Shutdown();
|
||||||
m_clients.Remove(udpClient.RemoteEndPoint);
|
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
|
// CoarseLocationUpdate packets cannot be split in an automated way
|
||||||
if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting)
|
if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting)
|
||||||
|
@ -239,17 +246,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
for (int i = 0; i < packetCount; i++)
|
for (int i = 0; i < packetCount; i++)
|
||||||
{
|
{
|
||||||
byte[] data = datas[i];
|
byte[] data = datas[i];
|
||||||
SendPacketData(client, data, packet.Type, category);
|
SendPacketData(udpClient, data, packet.Type, category);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
byte[] data = packet.ToBytes();
|
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;
|
int dataLength = data.Length;
|
||||||
bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0;
|
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
|
// to accomodate for both common scenarios and provide ample room for ACK appending in both
|
||||||
int bufferSize = (dataLength > 180) ? Packet.MTU : 200;
|
int bufferSize = (dataLength > 180) ? Packet.MTU : 200;
|
||||||
|
|
||||||
UDPPacketBuffer buffer = new UDPPacketBuffer(client.RemoteEndPoint, bufferSize);
|
UDPPacketBuffer buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize);
|
||||||
|
|
||||||
// Zerocode if needed
|
// Zerocode if needed
|
||||||
if (doZerocode)
|
if (doZerocode)
|
||||||
|
@ -285,7 +292,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
#region Queue or Send
|
#region Queue or Send
|
||||||
|
|
||||||
// Look up the UDPClient this is going to
|
// 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))
|
if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket))
|
||||||
SendPacketFinal(outgoingPacket);
|
SendPacketFinal(outgoingPacket);
|
||||||
|
@ -293,18 +300,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
#endregion Queue or Send
|
#endregion Queue or Send
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendAcks(LLUDPClient client)
|
public void SendAcks(LLUDPClient udpClient)
|
||||||
{
|
{
|
||||||
uint ack;
|
uint ack;
|
||||||
|
|
||||||
if (client.PendingAcks.Dequeue(out ack))
|
if (udpClient.PendingAcks.Dequeue(out ack))
|
||||||
{
|
{
|
||||||
List<PacketAckPacket.PacketsBlock> blocks = new List<PacketAckPacket.PacketsBlock>();
|
List<PacketAckPacket.PacketsBlock> blocks = new List<PacketAckPacket.PacketsBlock>();
|
||||||
PacketAckPacket.PacketsBlock block = new PacketAckPacket.PacketsBlock();
|
PacketAckPacket.PacketsBlock block = new PacketAckPacket.PacketsBlock();
|
||||||
block.ID = ack;
|
block.ID = ack;
|
||||||
blocks.Add(block);
|
blocks.Add(block);
|
||||||
|
|
||||||
while (client.PendingAcks.Dequeue(out ack))
|
while (udpClient.PendingAcks.Dequeue(out ack))
|
||||||
{
|
{
|
||||||
block = new PacketAckPacket.PacketsBlock();
|
block = new PacketAckPacket.PacketsBlock();
|
||||||
block.ID = ack;
|
block.ID = ack;
|
||||||
|
@ -315,22 +322,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
packet.Header.Reliable = false;
|
packet.Header.Reliable = false;
|
||||||
packet.Packets = blocks.ToArray();
|
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;
|
StartPingCheckPacket pc = (StartPingCheckPacket)PacketPool.Instance.GetPacket(PacketType.StartPingCheck);
|
||||||
if (api != null)
|
pc.Header.Reliable = false;
|
||||||
api.SendStartPingCheck(client.CurrentPingSequence++);
|
|
||||||
|
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)
|
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",
|
m_log.DebugFormat("[LLUDPSERVER]: Dropping packet #{0} for agent {1} after {2} failed attempts",
|
||||||
outgoingPacket.SequenceNumber, outgoingPacket.Client.RemoteEndPoint, outgoingPacket.ResendCount);
|
outgoingPacket.SequenceNumber, outgoingPacket.Client.RemoteEndPoint, outgoingPacket.ResendCount);
|
||||||
|
|
||||||
lock (client.NeedAcks.SyncRoot)
|
lock (udpClient.NeedAcks.SyncRoot)
|
||||||
client.NeedAcks.RemoveUnsafe(outgoingPacket.SequenceNumber);
|
udpClient.NeedAcks.RemoveUnsafe(outgoingPacket.SequenceNumber);
|
||||||
|
|
||||||
//Interlocked.Increment(ref Stats.DroppedPackets);
|
//Interlocked.Increment(ref Stats.DroppedPackets);
|
||||||
|
|
||||||
// Disconnect an agent if no packets are received for some time
|
// Disconnect an agent if no packets are received for some time
|
||||||
//FIXME: Make 60 an .ini setting
|
//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;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -397,7 +410,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
byte flags = buffer.Data[0];
|
byte flags = buffer.Data[0];
|
||||||
bool isResend = (flags & Helpers.MSG_RESENT) != 0;
|
bool isResend = (flags & Helpers.MSG_RESENT) != 0;
|
||||||
bool isReliable = (flags & Helpers.MSG_RELIABLE) != 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)
|
// Keep track of when this packet was sent out (right now)
|
||||||
outgoingPacket.TickCount = Environment.TickCount;
|
outgoingPacket.TickCount = Environment.TickCount;
|
||||||
|
@ -410,7 +423,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
// no more ACKs to append
|
// no more ACKs to append
|
||||||
uint ackCount = 0;
|
uint ackCount = 0;
|
||||||
uint ack;
|
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);
|
Utils.UIntToBytesBig(ack, buffer.Data, dataLength);
|
||||||
dataLength += 4;
|
dataLength += 4;
|
||||||
|
@ -429,24 +442,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
|
|
||||||
#endregion ACK Appending
|
#endregion ACK Appending
|
||||||
|
|
||||||
|
#region Sequence Number Assignment
|
||||||
|
|
||||||
if (!isResend)
|
if (!isResend)
|
||||||
{
|
{
|
||||||
// Not a resend, assign a new sequence number
|
// 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);
|
Utils.UIntToBytesBig(sequenceNumber, buffer.Data, 1);
|
||||||
outgoingPacket.SequenceNumber = sequenceNumber;
|
outgoingPacket.SequenceNumber = sequenceNumber;
|
||||||
|
|
||||||
if (isReliable)
|
if (isReliable)
|
||||||
{
|
{
|
||||||
// Add this packet to the list of ACK responses we are waiting on from the server
|
// 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
|
// Stats tracking
|
||||||
Interlocked.Increment(ref client.PacketsSent);
|
Interlocked.Increment(ref udpClient.PacketsSent);
|
||||||
if (isReliable)
|
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
|
// Put the UDP payload on the wire
|
||||||
AsyncBeginSend(buffer);
|
AsyncBeginSend(buffer);
|
||||||
|
@ -455,7 +472,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
protected override void PacketReceived(UDPPacketBuffer buffer)
|
protected override void PacketReceived(UDPPacketBuffer buffer)
|
||||||
{
|
{
|
||||||
// Debugging/Profiling
|
// Debugging/Profiling
|
||||||
//try { Thread.CurrentThread.Name = "PacketReceived (" + scene.RegionName + ")"; }
|
//try { Thread.CurrentThread.Name = "PacketReceived (" + m_scene.RegionInfo.RegionName + ")"; }
|
||||||
//catch (Exception) { }
|
//catch (Exception) { }
|
||||||
|
|
||||||
LLUDPClient client = null;
|
LLUDPClient client = null;
|
||||||
|
@ -484,9 +501,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Stats.RecvBytes += (ulong)buffer.DataLength;
|
|
||||||
//++Stats.RecvPackets;
|
|
||||||
|
|
||||||
#endregion Decoding
|
#endregion Decoding
|
||||||
|
|
||||||
#region UseCircuitCode Handling
|
#region UseCircuitCode Handling
|
||||||
|
@ -508,7 +522,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
if (!m_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 +
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -549,7 +563,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
#region ACK Sending
|
#region ACK Sending
|
||||||
|
|
||||||
if (packet.Header.Reliable)
|
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,
|
// 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
|
// 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);
|
m_scene.ClientManager.Add(circuitCode, clientApi);
|
||||||
clientApi.Start();
|
clientApi.Start();
|
||||||
|
|
||||||
// Give LLUDPClient a reference to IClientAPI
|
|
||||||
udpClient.ClientAPI = clientApi;
|
|
||||||
|
|
||||||
// Add the new client to our list of tracked clients
|
// Add the new client to our list of tracked clients
|
||||||
m_clients.Add(udpClient.RemoteEndPoint, udpClient);
|
m_clients.Add(udpClient.RemoteEndPoint, udpClient);
|
||||||
}
|
}
|
||||||
|
@ -756,31 +767,40 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
{
|
{
|
||||||
IncomingPacket incomingPacket = (IncomingPacket)state;
|
IncomingPacket incomingPacket = (IncomingPacket)state;
|
||||||
Packet packet = incomingPacket.Packet;
|
Packet packet = incomingPacket.Packet;
|
||||||
LLUDPClient client = incomingPacket.Client;
|
LLUDPClient udpClient = incomingPacket.Client;
|
||||||
|
IClientAPI client;
|
||||||
|
|
||||||
// Sanity check
|
// 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}\"",
|
m_log.WarnFormat("[LLUDPSERVER]: Processing a packet with incomplete state. Packet=\"{0}\", UDPClient=\"{1}\"",
|
||||||
packet, client, (client != null) ? client.ClientAPI : null);
|
packet, udpClient);
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
// Make sure this client is still alive
|
||||||
|
if (m_scene.ClientManager.TryGetClient(udpClient.CircuitCode, out client))
|
||||||
{
|
{
|
||||||
// Process this packet
|
try
|
||||||
client.ClientAPI.ProcessInPacket(packet);
|
{
|
||||||
|
// 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.DebugFormat("[LLUDPSERVER]: Dropping incoming {0} packet for dead client {1}", packet.Type, udpClient.AgentID);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue