diff options
author | John Hurliman | 2009-10-13 11:14:45 -0700 |
---|---|---|
committer | John Hurliman | 2009-10-13 11:14:45 -0700 |
commit | 82ace481c9ea180e7e5b9d6d7c7c191e438fdbe1 (patch) | |
tree | 28e18708a64cbbf25a3b36c7341061d2aff8289a /OpenSim/Region | |
parent | * Eliminated unnecessary parameters from LLUDPServer.SendPacketData() (diff) | |
download | opensim-SC_OLD-82ace481c9ea180e7e5b9d6d7c7c191e438fdbe1.zip opensim-SC_OLD-82ace481c9ea180e7e5b9d6d7c7c191e438fdbe1.tar.gz opensim-SC_OLD-82ace481c9ea180e7e5b9d6d7c7c191e438fdbe1.tar.bz2 opensim-SC_OLD-82ace481c9ea180e7e5b9d6d7c7c191e438fdbe1.tar.xz |
* 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
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs | 2 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs | 134 |
2 files changed, 77 insertions, 59 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index 871e8e8..10e22d5 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs | |||
@@ -82,8 +82,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
82 | /// <summary>ACKs that are queued up, waiting to be sent to the client</summary> | 82 | /// <summary>ACKs that are queued up, waiting to be sent to the client</summary> |
83 | public readonly LocklessQueue<uint> PendingAcks = new LocklessQueue<uint>(); | 83 | public readonly LocklessQueue<uint> PendingAcks = new LocklessQueue<uint>(); |
84 | 84 | ||
85 | /// <summary>Reference to the IClientAPI for this client</summary> | ||
86 | public LLClientView ClientAPI; | ||
87 | /// <summary>Current packet sequence number</summary> | 85 | /// <summary>Current packet sequence number</summary> |
88 | public int CurrentSequence; | 86 | public int CurrentSequence; |
89 | /// <summary>Current ping sequence number</summary> | 87 | /// <summary>Current ping sequence number</summary> |
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 | |||
183 | 183 | ||
184 | public void RemoveClient(LLUDPClient udpClient) | 184 | public void RemoveClient(LLUDPClient udpClient) |
185 | { | 185 | { |
186 | m_log.Debug("[LLUDPSERVER]: Removing LLUDPClient for " + udpClient.ClientAPI.Name); | 186 | m_log.Debug("[LLUDPSERVER]: Removing LLUDPClient for " + udpClient.AgentID); |
187 | 187 | ||
188 | m_scene.ClientManager.Remove(udpClient.CircuitCode); | 188 | // Shut down the IClientAPI and remove it from the scene |
189 | udpClient.ClientAPI.Close(false); | 189 | IClientAPI client; |
190 | if (m_scene.ClientManager.TryGetClient(udpClient.CircuitCode, out client)) | ||
191 | { | ||
192 | client.Close(false); | ||
193 | m_scene.ClientManager.Remove(udpClient.CircuitCode); | ||
194 | } | ||
195 | |||
196 | // Shut down the LLUDPClient and remove it from the list of UDP clients | ||
190 | udpClient.Shutdown(); | 197 | udpClient.Shutdown(); |
191 | m_clients.Remove(udpClient.RemoteEndPoint); | 198 | m_clients.Remove(udpClient.RemoteEndPoint); |
192 | } | 199 | } |
@@ -222,7 +229,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
222 | } | 229 | } |
223 | } | 230 | } |
224 | 231 | ||
225 | public void SendPacket(LLUDPClient client, Packet packet, ThrottleOutPacketType category, bool allowSplitting) | 232 | public void SendPacket(LLUDPClient udpClient, Packet packet, ThrottleOutPacketType category, bool allowSplitting) |
226 | { | 233 | { |
227 | // CoarseLocationUpdate packets cannot be split in an automated way | 234 | // CoarseLocationUpdate packets cannot be split in an automated way |
228 | if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting) | 235 | if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting) |
@@ -239,17 +246,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
239 | for (int i = 0; i < packetCount; i++) | 246 | for (int i = 0; i < packetCount; i++) |
240 | { | 247 | { |
241 | byte[] data = datas[i]; | 248 | byte[] data = datas[i]; |
242 | SendPacketData(client, data, packet.Type, category); | 249 | SendPacketData(udpClient, data, packet.Type, category); |
243 | } | 250 | } |
244 | } | 251 | } |
245 | else | 252 | else |
246 | { | 253 | { |
247 | byte[] data = packet.ToBytes(); | 254 | byte[] data = packet.ToBytes(); |
248 | SendPacketData(client, data, packet.Type, category); | 255 | SendPacketData(udpClient, data, packet.Type, category); |
249 | } | 256 | } |
250 | } | 257 | } |
251 | 258 | ||
252 | public void SendPacketData(LLUDPClient client, byte[] data, PacketType type, ThrottleOutPacketType category) | 259 | public void SendPacketData(LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category) |
253 | { | 260 | { |
254 | int dataLength = data.Length; | 261 | int dataLength = data.Length; |
255 | bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0; | 262 | bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0; |
@@ -260,7 +267,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
260 | // to accomodate for both common scenarios and provide ample room for ACK appending in both | 267 | // to accomodate for both common scenarios and provide ample room for ACK appending in both |
261 | int bufferSize = (dataLength > 180) ? Packet.MTU : 200; | 268 | int bufferSize = (dataLength > 180) ? Packet.MTU : 200; |
262 | 269 | ||
263 | UDPPacketBuffer buffer = new UDPPacketBuffer(client.RemoteEndPoint, bufferSize); | 270 | UDPPacketBuffer buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize); |
264 | 271 | ||
265 | // Zerocode if needed | 272 | // Zerocode if needed |
266 | if (doZerocode) | 273 | if (doZerocode) |
@@ -285,7 +292,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
285 | #region Queue or Send | 292 | #region Queue or Send |
286 | 293 | ||
287 | // Look up the UDPClient this is going to | 294 | // Look up the UDPClient this is going to |
288 | OutgoingPacket outgoingPacket = new OutgoingPacket(client, buffer, category); | 295 | OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category); |
289 | 296 | ||
290 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) | 297 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) |
291 | SendPacketFinal(outgoingPacket); | 298 | SendPacketFinal(outgoingPacket); |
@@ -293,18 +300,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
293 | #endregion Queue or Send | 300 | #endregion Queue or Send |
294 | } | 301 | } |
295 | 302 | ||
296 | public void SendAcks(LLUDPClient client) | 303 | public void SendAcks(LLUDPClient udpClient) |
297 | { | 304 | { |
298 | uint ack; | 305 | uint ack; |
299 | 306 | ||
300 | if (client.PendingAcks.Dequeue(out ack)) | 307 | if (udpClient.PendingAcks.Dequeue(out ack)) |
301 | { | 308 | { |
302 | List<PacketAckPacket.PacketsBlock> blocks = new List<PacketAckPacket.PacketsBlock>(); | 309 | List<PacketAckPacket.PacketsBlock> blocks = new List<PacketAckPacket.PacketsBlock>(); |
303 | PacketAckPacket.PacketsBlock block = new PacketAckPacket.PacketsBlock(); | 310 | PacketAckPacket.PacketsBlock block = new PacketAckPacket.PacketsBlock(); |
304 | block.ID = ack; | 311 | block.ID = ack; |
305 | blocks.Add(block); | 312 | blocks.Add(block); |
306 | 313 | ||
307 | while (client.PendingAcks.Dequeue(out ack)) | 314 | while (udpClient.PendingAcks.Dequeue(out ack)) |
308 | { | 315 | { |
309 | block = new PacketAckPacket.PacketsBlock(); | 316 | block = new PacketAckPacket.PacketsBlock(); |
310 | block.ID = ack; | 317 | block.ID = ack; |
@@ -315,22 +322,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
315 | packet.Header.Reliable = false; | 322 | packet.Header.Reliable = false; |
316 | packet.Packets = blocks.ToArray(); | 323 | packet.Packets = blocks.ToArray(); |
317 | 324 | ||
318 | SendPacket(client, packet, ThrottleOutPacketType.Unknown, true); | 325 | SendPacket(udpClient, packet, ThrottleOutPacketType.Unknown, true); |
319 | } | 326 | } |
320 | } | 327 | } |
321 | 328 | ||
322 | public void SendPing(LLUDPClient client) | 329 | public void SendPing(LLUDPClient udpClient) |
323 | { | 330 | { |
324 | IClientAPI api = client.ClientAPI; | 331 | StartPingCheckPacket pc = (StartPingCheckPacket)PacketPool.Instance.GetPacket(PacketType.StartPingCheck); |
325 | if (api != null) | 332 | pc.Header.Reliable = false; |
326 | api.SendStartPingCheck(client.CurrentPingSequence++); | 333 | |
334 | OutgoingPacket oldestPacket = udpClient.NeedAcks.GetOldest(); | ||
335 | |||
336 | pc.PingID.PingID = (byte)udpClient.CurrentPingSequence++; | ||
337 | pc.PingID.OldestUnacked = (oldestPacket != null) ? oldestPacket.SequenceNumber : 0; | ||
338 | |||
339 | SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false); | ||
327 | } | 340 | } |
328 | 341 | ||
329 | public void ResendUnacked(LLUDPClient client) | 342 | public void ResendUnacked(LLUDPClient udpClient) |
330 | { | 343 | { |
331 | if (client.NeedAcks.Count > 0) | 344 | if (udpClient.NeedAcks.Count > 0) |
332 | { | 345 | { |
333 | List<OutgoingPacket> expiredPackets = client.NeedAcks.GetExpiredPackets(client.RTO); | 346 | List<OutgoingPacket> expiredPackets = udpClient.NeedAcks.GetExpiredPackets(udpClient.RTO); |
334 | 347 | ||
335 | if (expiredPackets != null) | 348 | if (expiredPackets != null) |
336 | { | 349 | { |
@@ -366,18 +379,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
366 | m_log.DebugFormat("[LLUDPSERVER]: Dropping packet #{0} for agent {1} after {2} failed attempts", | 379 | m_log.DebugFormat("[LLUDPSERVER]: Dropping packet #{0} for agent {1} after {2} failed attempts", |
367 | outgoingPacket.SequenceNumber, outgoingPacket.Client.RemoteEndPoint, outgoingPacket.ResendCount); | 380 | outgoingPacket.SequenceNumber, outgoingPacket.Client.RemoteEndPoint, outgoingPacket.ResendCount); |
368 | 381 | ||
369 | lock (client.NeedAcks.SyncRoot) | 382 | lock (udpClient.NeedAcks.SyncRoot) |
370 | client.NeedAcks.RemoveUnsafe(outgoingPacket.SequenceNumber); | 383 | udpClient.NeedAcks.RemoveUnsafe(outgoingPacket.SequenceNumber); |
371 | 384 | ||
372 | //Interlocked.Increment(ref Stats.DroppedPackets); | 385 | //Interlocked.Increment(ref Stats.DroppedPackets); |
373 | 386 | ||
374 | // Disconnect an agent if no packets are received for some time | 387 | // Disconnect an agent if no packets are received for some time |
375 | //FIXME: Make 60 an .ini setting | 388 | //FIXME: Make 60 an .ini setting |
376 | if (Environment.TickCount - client.TickLastPacketReceived > 1000 * 60) | 389 | if (Environment.TickCount - udpClient.TickLastPacketReceived > 1000 * 60) |
377 | { | 390 | { |
378 | m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + client.ClientAPI.Name); | 391 | m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + udpClient.AgentID); |
379 | 392 | ||
380 | RemoveClient(client); | 393 | RemoveClient(udpClient); |
381 | return; | 394 | return; |
382 | } | 395 | } |
383 | } | 396 | } |
@@ -397,7 +410,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
397 | byte flags = buffer.Data[0]; | 410 | byte flags = buffer.Data[0]; |
398 | bool isResend = (flags & Helpers.MSG_RESENT) != 0; | 411 | bool isResend = (flags & Helpers.MSG_RESENT) != 0; |
399 | bool isReliable = (flags & Helpers.MSG_RELIABLE) != 0; | 412 | bool isReliable = (flags & Helpers.MSG_RELIABLE) != 0; |
400 | LLUDPClient client = outgoingPacket.Client; | 413 | LLUDPClient udpClient = outgoingPacket.Client; |
401 | 414 | ||
402 | // Keep track of when this packet was sent out (right now) | 415 | // Keep track of when this packet was sent out (right now) |
403 | outgoingPacket.TickCount = Environment.TickCount; | 416 | outgoingPacket.TickCount = Environment.TickCount; |
@@ -410,7 +423,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
410 | // no more ACKs to append | 423 | // no more ACKs to append |
411 | uint ackCount = 0; | 424 | uint ackCount = 0; |
412 | uint ack; | 425 | uint ack; |
413 | while (dataLength + 5 < buffer.Data.Length && client.PendingAcks.Dequeue(out ack)) | 426 | while (dataLength + 5 < buffer.Data.Length && udpClient.PendingAcks.Dequeue(out ack)) |
414 | { | 427 | { |
415 | Utils.UIntToBytesBig(ack, buffer.Data, dataLength); | 428 | Utils.UIntToBytesBig(ack, buffer.Data, dataLength); |
416 | dataLength += 4; | 429 | dataLength += 4; |
@@ -429,24 +442,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
429 | 442 | ||
430 | #endregion ACK Appending | 443 | #endregion ACK Appending |
431 | 444 | ||
445 | #region Sequence Number Assignment | ||
446 | |||
432 | if (!isResend) | 447 | if (!isResend) |
433 | { | 448 | { |
434 | // Not a resend, assign a new sequence number | 449 | // Not a resend, assign a new sequence number |
435 | uint sequenceNumber = (uint)Interlocked.Increment(ref client.CurrentSequence); | 450 | uint sequenceNumber = (uint)Interlocked.Increment(ref udpClient.CurrentSequence); |
436 | Utils.UIntToBytesBig(sequenceNumber, buffer.Data, 1); | 451 | Utils.UIntToBytesBig(sequenceNumber, buffer.Data, 1); |
437 | outgoingPacket.SequenceNumber = sequenceNumber; | 452 | outgoingPacket.SequenceNumber = sequenceNumber; |
438 | 453 | ||
439 | if (isReliable) | 454 | if (isReliable) |
440 | { | 455 | { |
441 | // Add this packet to the list of ACK responses we are waiting on from the server | 456 | // Add this packet to the list of ACK responses we are waiting on from the server |
442 | client.NeedAcks.Add(outgoingPacket); | 457 | udpClient.NeedAcks.Add(outgoingPacket); |
443 | } | 458 | } |
444 | } | 459 | } |
445 | 460 | ||
461 | #endregion Sequence Number Assignment | ||
462 | |||
446 | // Stats tracking | 463 | // Stats tracking |
447 | Interlocked.Increment(ref client.PacketsSent); | 464 | Interlocked.Increment(ref udpClient.PacketsSent); |
448 | if (isReliable) | 465 | if (isReliable) |
449 | Interlocked.Add(ref client.UnackedBytes, outgoingPacket.Buffer.DataLength); | 466 | Interlocked.Add(ref udpClient.UnackedBytes, outgoingPacket.Buffer.DataLength); |
450 | 467 | ||
451 | // Put the UDP payload on the wire | 468 | // Put the UDP payload on the wire |
452 | AsyncBeginSend(buffer); | 469 | AsyncBeginSend(buffer); |
@@ -455,7 +472,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
455 | protected override void PacketReceived(UDPPacketBuffer buffer) | 472 | protected override void PacketReceived(UDPPacketBuffer buffer) |
456 | { | 473 | { |
457 | // Debugging/Profiling | 474 | // Debugging/Profiling |
458 | //try { Thread.CurrentThread.Name = "PacketReceived (" + scene.RegionName + ")"; } | 475 | //try { Thread.CurrentThread.Name = "PacketReceived (" + m_scene.RegionInfo.RegionName + ")"; } |
459 | //catch (Exception) { } | 476 | //catch (Exception) { } |
460 | 477 | ||
461 | LLUDPClient client = null; | 478 | LLUDPClient client = null; |
@@ -484,9 +501,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
484 | return; | 501 | return; |
485 | } | 502 | } |
486 | 503 | ||
487 | //Stats.RecvBytes += (ulong)buffer.DataLength; | ||
488 | //++Stats.RecvPackets; | ||
489 | |||
490 | #endregion Decoding | 504 | #endregion Decoding |
491 | 505 | ||
492 | #region UseCircuitCode Handling | 506 | #region UseCircuitCode Handling |
@@ -508,7 +522,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
508 | if (!m_clients.TryGetValue(address, out client)) | 522 | if (!m_clients.TryGetValue(address, out client)) |
509 | { | 523 | { |
510 | m_log.Warn("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + | 524 | m_log.Warn("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + |
511 | ", currently tracking " + m_clients.Count + " clients"); | 525 | " in " + m_scene.RegionInfo.RegionName + ", currently tracking " + m_clients.Count + " clients"); |
512 | return; | 526 | return; |
513 | } | 527 | } |
514 | 528 | ||
@@ -549,7 +563,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
549 | #region ACK Sending | 563 | #region ACK Sending |
550 | 564 | ||
551 | if (packet.Header.Reliable) | 565 | if (packet.Header.Reliable) |
552 | client.PendingAcks.Enqueue((uint)packet.Header.Sequence); | 566 | client.PendingAcks.Enqueue(packet.Header.Sequence); |
553 | 567 | ||
554 | // This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out, | 568 | // This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out, |
555 | // add the current received bytes to it, test if 2*MTU bytes have been sent, if so remove | 569 | // 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 | |||
648 | m_scene.ClientManager.Add(circuitCode, clientApi); | 662 | m_scene.ClientManager.Add(circuitCode, clientApi); |
649 | clientApi.Start(); | 663 | clientApi.Start(); |
650 | 664 | ||
651 | // Give LLUDPClient a reference to IClientAPI | ||
652 | udpClient.ClientAPI = clientApi; | ||
653 | |||
654 | // Add the new client to our list of tracked clients | 665 | // Add the new client to our list of tracked clients |
655 | m_clients.Add(udpClient.RemoteEndPoint, udpClient); | 666 | m_clients.Add(udpClient.RemoteEndPoint, udpClient); |
656 | } | 667 | } |
@@ -756,31 +767,40 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
756 | { | 767 | { |
757 | IncomingPacket incomingPacket = (IncomingPacket)state; | 768 | IncomingPacket incomingPacket = (IncomingPacket)state; |
758 | Packet packet = incomingPacket.Packet; | 769 | Packet packet = incomingPacket.Packet; |
759 | LLUDPClient client = incomingPacket.Client; | 770 | LLUDPClient udpClient = incomingPacket.Client; |
771 | IClientAPI client; | ||
760 | 772 | ||
761 | // Sanity check | 773 | // Sanity check |
762 | if (packet == null || client == null || client.ClientAPI == null) | 774 | if (packet == null || udpClient == null) |
763 | { | 775 | { |
764 | m_log.WarnFormat("[LLUDPSERVER]: Processing a packet with incomplete state. Packet=\"{0}\", Client=\"{1}\", Client.ClientAPI=\"{2}\"", | 776 | m_log.WarnFormat("[LLUDPSERVER]: Processing a packet with incomplete state. Packet=\"{0}\", UDPClient=\"{1}\"", |
765 | packet, client, (client != null) ? client.ClientAPI : null); | 777 | packet, udpClient); |
766 | } | 778 | } |
767 | 779 | ||
768 | try | 780 | // Make sure this client is still alive |
781 | if (m_scene.ClientManager.TryGetClient(udpClient.CircuitCode, out client)) | ||
769 | { | 782 | { |
770 | // Process this packet | 783 | try |
771 | client.ClientAPI.ProcessInPacket(packet); | 784 | { |
772 | } | 785 | // Process this packet |
773 | catch (ThreadAbortException) | 786 | client.ProcessInPacket(packet); |
774 | { | 787 | } |
775 | // If something is trying to abort the packet processing thread, take that as a hint that it's time to shut down | 788 | catch (ThreadAbortException) |
776 | m_log.Info("[LLUDPSERVER]: Caught a thread abort, shutting down the LLUDP server"); | 789 | { |
777 | Stop(); | 790 | // If something is trying to abort the packet processing thread, take that as a hint that it's time to shut down |
791 | m_log.Info("[LLUDPSERVER]: Caught a thread abort, shutting down the LLUDP server"); | ||
792 | Stop(); | ||
793 | } | ||
794 | catch (Exception e) | ||
795 | { | ||
796 | // Don't let a failure in an individual client thread crash the whole sim. | ||
797 | m_log.ErrorFormat("[LLUDPSERVER]: Client packet handler for {0} for packet {1} threw an exception", udpClient.AgentID, packet.Type); | ||
798 | m_log.Error(e.Message, e); | ||
799 | } | ||
778 | } | 800 | } |
779 | catch (Exception e) | 801 | else |
780 | { | 802 | { |
781 | // Don't let a failure in an individual client thread crash the whole sim. | 803 | m_log.DebugFormat("[LLUDPSERVER]: Dropping incoming {0} packet for dead client {1}", packet.Type, udpClient.AgentID); |
782 | m_log.ErrorFormat("[LLUDPSERVER]: Client packet handler for {0} for packet {1} threw an exception", client.AgentID, packet.Type); | ||
783 | m_log.Error(e.Message, e); | ||
784 | } | 804 | } |
785 | } | 805 | } |
786 | 806 | ||