aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs')
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs628
1 files changed, 545 insertions, 83 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
index 4154ef2..50dae2a 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -34,6 +34,7 @@ using System.Net.Sockets;
34using System.Reflection; 34using System.Reflection;
35using System.Threading; 35using System.Threading;
36using log4net; 36using log4net;
37using NDesk.Options;
37using Nini.Config; 38using Nini.Config;
38using OpenMetaverse.Packets; 39using OpenMetaverse.Packets;
39using OpenSim.Framework; 40using OpenSim.Framework;
@@ -62,20 +63,41 @@ namespace OpenSim.Region.ClientStack.LindenUDP
62 m_udpServer = new LLUDPServer(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager); 63 m_udpServer = new LLUDPServer(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager);
63 } 64 }
64 65
65 public void NetworkStop()
66 {
67 m_udpServer.Stop();
68 }
69
70 public void AddScene(IScene scene) 66 public void AddScene(IScene scene)
71 { 67 {
72 m_udpServer.AddScene(scene); 68 m_udpServer.AddScene(scene);
73 69
74 StatsManager.RegisterStat( 70 StatsManager.RegisterStat(
75 new Stat( 71 new Stat(
72 "ClientLogoutsDueToNoReceives",
73 "Number of times a client has been logged out because no packets were received before the timeout.",
74 "",
75 "",
76 "clientstack",
77 scene.Name,
78 StatType.Pull,
79 MeasuresOfInterest.None,
80 stat => stat.Value = m_udpServer.ClientLogoutsDueToNoReceives,
81 StatVerbosity.Debug));
82
83 StatsManager.RegisterStat(
84 new Stat(
85 "IncomingUDPReceivesCount",
86 "Number of UDP receives performed",
87 "",
88 "",
89 "clientstack",
90 scene.Name,
91 StatType.Pull,
92 MeasuresOfInterest.AverageChangeOverTime,
93 stat => stat.Value = m_udpServer.UdpReceives,
94 StatVerbosity.Debug));
95
96 StatsManager.RegisterStat(
97 new Stat(
76 "IncomingPacketsProcessedCount", 98 "IncomingPacketsProcessedCount",
77 "Number of inbound UDP packets processed", 99 "Number of inbound LL protocol packets processed",
78 "Number of inbound UDP packets processed", 100 "",
79 "", 101 "",
80 "clientstack", 102 "clientstack",
81 scene.Name, 103 scene.Name,
@@ -83,6 +105,86 @@ namespace OpenSim.Region.ClientStack.LindenUDP
83 MeasuresOfInterest.AverageChangeOverTime, 105 MeasuresOfInterest.AverageChangeOverTime,
84 stat => stat.Value = m_udpServer.IncomingPacketsProcessed, 106 stat => stat.Value = m_udpServer.IncomingPacketsProcessed,
85 StatVerbosity.Debug)); 107 StatVerbosity.Debug));
108
109 StatsManager.RegisterStat(
110 new Stat(
111 "IncomingPacketsMalformedCount",
112 "Number of inbound UDP packets that could not be recognized as LL protocol packets.",
113 "",
114 "",
115 "clientstack",
116 scene.Name,
117 StatType.Pull,
118 MeasuresOfInterest.AverageChangeOverTime,
119 stat => stat.Value = m_udpServer.IncomingMalformedPacketCount,
120 StatVerbosity.Info));
121
122 StatsManager.RegisterStat(
123 new Stat(
124 "IncomingPacketsOrphanedCount",
125 "Number of inbound packets that were not initial connections packets and could not be associated with a viewer.",
126 "",
127 "",
128 "clientstack",
129 scene.Name,
130 StatType.Pull,
131 MeasuresOfInterest.AverageChangeOverTime,
132 stat => stat.Value = m_udpServer.IncomingOrphanedPacketCount,
133 StatVerbosity.Info));
134
135 StatsManager.RegisterStat(
136 new Stat(
137 "IncomingPacketsResentCount",
138 "Number of inbound packets that clients indicate are resends.",
139 "",
140 "",
141 "clientstack",
142 scene.Name,
143 StatType.Pull,
144 MeasuresOfInterest.AverageChangeOverTime,
145 stat => stat.Value = m_udpServer.IncomingPacketsResentCount,
146 StatVerbosity.Debug));
147
148 StatsManager.RegisterStat(
149 new Stat(
150 "OutgoingUDPSendsCount",
151 "Number of UDP sends performed",
152 "",
153 "",
154 "clientstack",
155 scene.Name,
156 StatType.Pull,
157 MeasuresOfInterest.AverageChangeOverTime,
158 stat => stat.Value = m_udpServer.UdpSends,
159 StatVerbosity.Debug));
160
161 StatsManager.RegisterStat(
162 new Stat(
163 "OutgoingPacketsResentCount",
164 "Number of packets resent because a client did not acknowledge receipt",
165 "",
166 "",
167 "clientstack",
168 scene.Name,
169 StatType.Pull,
170 MeasuresOfInterest.AverageChangeOverTime,
171 stat => stat.Value = m_udpServer.PacketsResentCount,
172 StatVerbosity.Debug));
173
174 StatsManager.RegisterStat(
175 new Stat(
176 "AverageUDPProcessTime",
177 "Average number of milliseconds taken to process each incoming UDP packet in a sample.",
178 "This is for initial receive processing which is separate from the later client LL packet processing stage.",
179 "ms",
180 "clientstack",
181 scene.Name,
182 StatType.Pull,
183 MeasuresOfInterest.None,
184 stat => stat.Value = m_udpServer.AverageReceiveTicksForLastSamplePeriod / TimeSpan.TicksPerMillisecond,
185// stat =>
186// stat.Value = Math.Round(m_udpServer.AverageReceiveTicksForLastSamplePeriod / TimeSpan.TicksPerMillisecond, 7),
187 StatVerbosity.Debug));
86 } 188 }
87 189
88 public bool HandlesRegion(Location x) 190 public bool HandlesRegion(Location x)
@@ -107,10 +209,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
107 /// </summary> 209 /// </summary>
108 public class LLUDPServer : OpenSimUDPBase 210 public class LLUDPServer : OpenSimUDPBase
109 { 211 {
212 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
213
110 /// <summary>Maximum transmission unit, or UDP packet size, for the LLUDP protocol</summary> 214 /// <summary>Maximum transmission unit, or UDP packet size, for the LLUDP protocol</summary>
111 public const int MTU = 1400; 215 public const int MTU = 1400;
112 216
113 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 217 /// <summary>Number of forced client logouts due to no receipt of packets before timeout.</summary>
218 public int ClientLogoutsDueToNoReceives { get; private set; }
219
220 /// <summary>
221 /// Default packet debug level given to new clients
222 /// </summary>
223 public int DefaultClientPacketDebugLevel { get; set; }
114 224
115 /// <summary>The measured resolution of Environment.TickCount</summary> 225 /// <summary>The measured resolution of Environment.TickCount</summary>
116 public readonly float TickCountResolution; 226 public readonly float TickCountResolution;
@@ -184,6 +294,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
184 protected bool m_sendPing; 294 protected bool m_sendPing;
185 295
186 private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>(); 296 private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>();
297
298 /// <summary>
299 /// Event used to signal when queued packets are available for sending.
300 /// </summary>
301 /// <remarks>
302 /// This allows the outbound loop to only operate when there is data to send rather than continuously polling.
303 /// Some data is sent immediately and not queued. That data would not trigger this event.
304 /// </remarks>
305 private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false);
306
187 private Pool<IncomingPacket> m_incomingPacketPool; 307 private Pool<IncomingPacket> m_incomingPacketPool;
188 308
189 /// <summary> 309 /// <summary>
@@ -204,7 +324,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP
204 324
205 public Socket Server { get { return null; } } 325 public Socket Server { get { return null; } }
206 326
207 private int m_malformedCount = 0; // Guard against a spamming attack 327 /// <summary>
328 /// Record how many packets have been resent
329 /// </summary>
330 internal int PacketsResentCount { get; set; }
331
332 /// <summary>
333 /// Record how many packets have been sent
334 /// </summary>
335 internal int PacketsSentCount { get; set; }
336
337 /// <summary>
338 /// Record how many incoming packets are indicated as resends by clients.
339 /// </summary>
340 internal int IncomingPacketsResentCount { get; set; }
341
342 /// <summary>
343 /// Record how many inbound packets could not be recognized as LLUDP packets.
344 /// </summary>
345 public int IncomingMalformedPacketCount { get; private set; }
346
347 /// <summary>
348 /// Record how many inbound packets could not be associated with a simulator circuit.
349 /// </summary>
350 public int IncomingOrphanedPacketCount { get; private set; }
208 351
209 /// <summary> 352 /// <summary>
210 /// Record current outgoing client for monitoring purposes. 353 /// Record current outgoing client for monitoring purposes.
@@ -461,6 +604,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
461 m_scene = (Scene)scene; 604 m_scene = (Scene)scene;
462 m_location = new Location(m_scene.RegionInfo.RegionHandle); 605 m_location = new Location(m_scene.RegionInfo.RegionHandle);
463 606
607 StatsManager.RegisterStat(
608 new Stat(
609 "InboxPacketsCount",
610 "Number of LL protocol packets waiting for the second stage of processing after initial receive.",
611 "Number of LL protocol packets waiting for the second stage of processing after initial receive.",
612 "",
613 "clientstack",
614 scene.Name,
615 StatType.Pull,
616 MeasuresOfInterest.AverageChangeOverTime,
617 stat => stat.Value = packetInbox.Count,
618 StatVerbosity.Debug));
619
464 // XXX: These stats are also pool stats but we register them separately since they are currently not 620 // XXX: These stats are also pool stats but we register them separately since they are currently not
465 // turned on and off by EnablePools()/DisablePools() 621 // turned on and off by EnablePools()/DisablePools()
466 StatsManager.RegisterStat( 622 StatsManager.RegisterStat(
@@ -521,6 +677,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
521 EnablePoolStats(); 677 EnablePoolStats();
522 678
523 MainConsole.Instance.Commands.AddCommand( 679 MainConsole.Instance.Commands.AddCommand(
680 "Debug", false, "debug lludp packet",
681 "debug lludp packet [--default] <level> [<avatar-first-name> <avatar-last-name>]",
682 "Turn on packet debugging",
683 "If level > 255 then all incoming and outgoing packets are logged.\n"
684 + "If level <= 255 then incoming AgentUpdate and outgoing SimStats and SimulatorViewerTimeMessage packets are not logged.\n"
685 + "If level <= 200 then incoming RequestImage and outgoing ImagePacket, ImageData, LayerData and CoarseLocationUpdate packets are not logged.\n"
686 + "If level <= 100 then incoming ViewerEffect and AgentAnimation and outgoing ViewerEffect and AvatarAnimation packets are not logged.\n"
687 + "If level <= 50 then outgoing ImprovedTerseObjectUpdate packets are not logged.\n"
688 + "If level <= 0 then no packets are logged.\n"
689 + "If --default is specified then the level becomes the default logging level for all subsequent agents.\n"
690 + "In this case, you cannot also specify an avatar name.\n"
691 + "If an avatar name is given then only packets from that avatar are logged.",
692 HandlePacketCommand);
693
694 MainConsole.Instance.Commands.AddCommand(
524 "Debug", 695 "Debug",
525 false, 696 false,
526 "debug lludp start", 697 "debug lludp start",
@@ -559,10 +730,78 @@ namespace OpenSim.Region.ClientStack.LindenUDP
559 "debug lludp status", 730 "debug lludp status",
560 "Return status of LLUDP packet processing.", 731 "Return status of LLUDP packet processing.",
561 HandleStatusCommand); 732 HandleStatusCommand);
733
734 MainConsole.Instance.Commands.AddCommand(
735 "Debug",
736 false,
737 "debug lludp toggle agentupdate",
738 "debug lludp toggle agentupdate",
739 "Toggle whether agentupdate packets are processed or simply discarded.",
740 HandleAgentUpdateCommand);
741 }
742
743 private void HandlePacketCommand(string module, string[] args)
744 {
745 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
746 return;
747
748 bool setAsDefaultLevel = false;
749 OptionSet optionSet = new OptionSet().Add("default", o => setAsDefaultLevel = o != null);
750 List<string> filteredArgs = optionSet.Parse(args);
751
752 string name = null;
753
754 if (filteredArgs.Count == 6)
755 {
756 if (!setAsDefaultLevel)
757 {
758 name = string.Format("{0} {1}", filteredArgs[4], filteredArgs[5]);
759 }
760 else
761 {
762 MainConsole.Instance.OutputFormat("ERROR: Cannot specify a user name when setting default logging level");
763 return;
764 }
765 }
766
767 if (filteredArgs.Count > 3)
768 {
769 int newDebug;
770 if (int.TryParse(filteredArgs[3], out newDebug))
771 {
772 if (setAsDefaultLevel)
773 {
774 DefaultClientPacketDebugLevel = newDebug;
775 MainConsole.Instance.OutputFormat(
776 "Debug packet debug for new clients set to {0} in {1}", DefaultClientPacketDebugLevel, m_scene.Name);
777 }
778 else
779 {
780 m_scene.ForEachScenePresence(sp =>
781 {
782 if (name == null || sp.Name == name)
783 {
784 MainConsole.Instance.OutputFormat(
785 "Packet debug for {0} ({1}) set to {2} in {3}",
786 sp.Name, sp.IsChildAgent ? "child" : "root", newDebug, m_scene.Name);
787
788 sp.ControllingClient.DebugPacketLevel = newDebug;
789 }
790 });
791 }
792 }
793 else
794 {
795 MainConsole.Instance.Output("Usage: debug lludp packet [--default] 0..255 [<first-name> <last-name>]");
796 }
797 }
562 } 798 }
563 799
564 private void HandleStartCommand(string module, string[] args) 800 private void HandleStartCommand(string module, string[] args)
565 { 801 {
802 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
803 return;
804
566 if (args.Length != 4) 805 if (args.Length != 4)
567 { 806 {
568 MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>"); 807 MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>");
@@ -580,6 +819,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
580 819
581 private void HandleStopCommand(string module, string[] args) 820 private void HandleStopCommand(string module, string[] args)
582 { 821 {
822 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
823 return;
824
583 if (args.Length != 4) 825 if (args.Length != 4)
584 { 826 {
585 MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>"); 827 MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>");
@@ -597,6 +839,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
597 839
598 private void HandlePoolCommand(string module, string[] args) 840 private void HandlePoolCommand(string module, string[] args)
599 { 841 {
842 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
843 return;
844
600 if (args.Length != 4) 845 if (args.Length != 4)
601 { 846 {
602 MainConsole.Instance.Output("Usage: debug lludp pool <on|off>"); 847 MainConsole.Instance.Output("Usage: debug lludp pool <on|off>");
@@ -627,8 +872,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP
627 } 872 }
628 } 873 }
629 874
875 bool m_discardAgentUpdates;
876
877 private void HandleAgentUpdateCommand(string module, string[] args)
878 {
879 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
880 return;
881
882 m_discardAgentUpdates = !m_discardAgentUpdates;
883
884 MainConsole.Instance.OutputFormat(
885 "Discard AgentUpdates now {0} for {1}", m_discardAgentUpdates, m_scene.Name);
886 }
887
630 private void HandleStatusCommand(string module, string[] args) 888 private void HandleStatusCommand(string module, string[] args)
631 { 889 {
890 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
891 return;
892
632 MainConsole.Instance.OutputFormat( 893 MainConsole.Instance.OutputFormat(
633 "IN LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningInbound ? "enabled" : "disabled"); 894 "IN LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningInbound ? "enabled" : "disabled");
634 895
@@ -636,6 +897,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
636 "OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled"); 897 "OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled");
637 898
638 MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_scene.Name, UsePools ? "on" : "off"); 899 MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_scene.Name, UsePools ? "on" : "off");
900
901 MainConsole.Instance.OutputFormat(
902 "Packet debug level for new clients is {0}", DefaultClientPacketDebugLevel);
639 } 903 }
640 904
641 public bool HandlesRegion(Location x) 905 public bool HandlesRegion(Location x)
@@ -643,44 +907,44 @@ namespace OpenSim.Region.ClientStack.LindenUDP
643 return x == m_location; 907 return x == m_location;
644 } 908 }
645 909
646 public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting) 910// public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting)
647 { 911// {
648 // CoarseLocationUpdate and AvatarGroupsReply packets cannot be split in an automated way 912// // CoarseLocationUpdate and AvatarGroupsReply packets cannot be split in an automated way
649 if ((packet.Type == PacketType.CoarseLocationUpdate || packet.Type == PacketType.AvatarGroupsReply) && allowSplitting) 913// if ((packet.Type == PacketType.CoarseLocationUpdate || packet.Type == PacketType.AvatarGroupsReply) && allowSplitting)
650 allowSplitting = false; 914// allowSplitting = false;
651 915//
652 if (allowSplitting && packet.HasVariableBlocks) 916// if (allowSplitting && packet.HasVariableBlocks)
653 { 917// {
654 byte[][] datas = packet.ToBytesMultiple(); 918// byte[][] datas = packet.ToBytesMultiple();
655 int packetCount = datas.Length; 919// int packetCount = datas.Length;
656 920//
657 if (packetCount < 1) 921// if (packetCount < 1)
658 m_log.Error("[LLUDPSERVER]: Failed to split " + packet.Type + " with estimated length " + packet.Length); 922// m_log.Error("[LLUDPSERVER]: Failed to split " + packet.Type + " with estimated length " + packet.Length);
659 923//
660 for (int i = 0; i < packetCount; i++) 924// for (int i = 0; i < packetCount; i++)
661 { 925// {
662 byte[] data = datas[i]; 926// byte[] data = datas[i];
663 m_scene.ForEachClient( 927// m_scene.ForEachClient(
664 delegate(IClientAPI client) 928// delegate(IClientAPI client)
665 { 929// {
666 if (client is LLClientView) 930// if (client is LLClientView)
667 SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null); 931// SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null);
668 } 932// }
669 ); 933// );
670 } 934// }
671 } 935// }
672 else 936// else
673 { 937// {
674 byte[] data = packet.ToBytes(); 938// byte[] data = packet.ToBytes();
675 m_scene.ForEachClient( 939// m_scene.ForEachClient(
676 delegate(IClientAPI client) 940// delegate(IClientAPI client)
677 { 941// {
678 if (client is LLClientView) 942// if (client is LLClientView)
679 SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null); 943// SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null);
680 } 944// }
681 ); 945// );
682 } 946// }
683 } 947// }
684 948
685 /// <summary> 949 /// <summary>
686 /// Start the process of sending a packet to the client. 950 /// Start the process of sending a packet to the client.
@@ -700,6 +964,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
700 if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting) 964 if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting)
701 allowSplitting = false; 965 allowSplitting = false;
702 966
967 bool packetQueued = false;
968
703 if (allowSplitting && packet.HasVariableBlocks) 969 if (allowSplitting && packet.HasVariableBlocks)
704 { 970 {
705 byte[][] datas = packet.ToBytesMultiple(); 971 byte[][] datas = packet.ToBytesMultiple();
@@ -711,16 +977,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
711 for (int i = 0; i < packetCount; i++) 977 for (int i = 0; i < packetCount; i++)
712 { 978 {
713 byte[] data = datas[i]; 979 byte[] data = datas[i];
714 SendPacketData(udpClient, data, packet.Type, category, method); 980
981 if (!SendPacketData(udpClient, data, packet.Type, category, method))
982 packetQueued = true;
715 } 983 }
716 } 984 }
717 else 985 else
718 { 986 {
719 byte[] data = packet.ToBytes(); 987 byte[] data = packet.ToBytes();
720 SendPacketData(udpClient, data, packet.Type, category, method); 988 packetQueued = SendPacketData(udpClient, data, packet.Type, category, method);
721 } 989 }
722 990
723 PacketPool.Instance.ReturnPacket(packet); 991 PacketPool.Instance.ReturnPacket(packet);
992
993 if (packetQueued)
994 m_dataPresentEvent.Set();
724 } 995 }
725 996
726 /// <summary> 997 /// <summary>
@@ -734,7 +1005,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
734 /// The method to call if the packet is not acked by the client. If null, then a standard 1005 /// The method to call if the packet is not acked by the client. If null, then a standard
735 /// resend of the packet is done. 1006 /// resend of the packet is done.
736 /// </param> 1007 /// </param>
737 public void SendPacketData( 1008 /// <returns>true if the data was sent immediately, false if it was queued for sending</returns>
1009 public bool SendPacketData(
738 LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category, UnackedPacketMethod method) 1010 LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category, UnackedPacketMethod method)
739 { 1011 {
740 int dataLength = data.Length; 1012 int dataLength = data.Length;
@@ -807,7 +1079,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
807 // packet so that it isn't sent before a queued update packet. 1079 // packet so that it isn't sent before a queued update packet.
808 bool requestQueue = type == PacketType.KillObject; 1080 bool requestQueue = type == PacketType.KillObject;
809 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue, highPriority)) 1081 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue, highPriority))
1082 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue))
1083 {
810 SendPacketFinal(outgoingPacket); 1084 SendPacketFinal(outgoingPacket);
1085 return true;
1086 }
1087
1088 return false;
811 1089
812 #endregion Queue or Send 1090 #endregion Queue or Send
813 } 1091 }
@@ -883,7 +1161,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
883 // Fire this out on a different thread so that we don't hold up outgoing packet processing for 1161 // Fire this out on a different thread so that we don't hold up outgoing packet processing for
884 // everybody else if this is being called due to an ack timeout. 1162 // everybody else if this is being called due to an ack timeout.
885 // This is the same as processing as the async process of a logout request. 1163 // This is the same as processing as the async process of a logout request.
886 Util.FireAndForget(o => DeactivateClientDueToTimeout(client)); 1164 Util.FireAndForget(o => DeactivateClientDueToTimeout(client, timeoutTicks));
887 1165
888 return; 1166 return;
889 } 1167 }
@@ -988,6 +1266,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
988 else 1266 else
989 { 1267 {
990 Interlocked.Increment(ref udpClient.PacketsResent); 1268 Interlocked.Increment(ref udpClient.PacketsResent);
1269
1270 // We're not going to worry about interlock yet since its not currently critical that this total count
1271 // is 100% correct
1272 PacketsResentCount++;
991 } 1273 }
992 1274
993 #endregion Sequence Number Assignment 1275 #endregion Sequence Number Assignment
@@ -995,6 +1277,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
995 // Stats tracking 1277 // Stats tracking
996 Interlocked.Increment(ref udpClient.PacketsSent); 1278 Interlocked.Increment(ref udpClient.PacketsSent);
997 1279
1280 // We're not going to worry about interlock yet since its not currently critical that this total count
1281 // is 100% correct
1282 PacketsSentCount++;
1283
998 // Put the UDP payload on the wire 1284 // Put the UDP payload on the wire
999 AsyncBeginSend(buffer); 1285 AsyncBeginSend(buffer);
1000 1286
@@ -1002,6 +1288,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1002 outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue; 1288 outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue;
1003 } 1289 }
1004 1290
1291 private void RecordMalformedInboundPacket(IPEndPoint endPoint)
1292 {
1293// if (m_malformedCount < 100)
1294// m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString());
1295
1296 IncomingMalformedPacketCount++;
1297
1298 if ((IncomingMalformedPacketCount % 10000) == 0)
1299 m_log.WarnFormat(
1300 "[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack. Last was from {1}",
1301 IncomingMalformedPacketCount, endPoint);
1302 }
1303
1005 public override void PacketReceived(UDPPacketBuffer buffer) 1304 public override void PacketReceived(UDPPacketBuffer buffer)
1006 { 1305 {
1007 // Debugging/Profiling 1306 // Debugging/Profiling
@@ -1023,6 +1322,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1023// "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}", 1322// "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}",
1024// buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); 1323// buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
1025 1324
1325 RecordMalformedInboundPacket(endPoint);
1326
1026 return; // Drop undersized packet 1327 return; // Drop undersized packet
1027 } 1328 }
1028 1329
@@ -1041,6 +1342,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1041// "[LLUDPSERVER]: Dropping packet with malformed header received from {0} in {1}", 1342// "[LLUDPSERVER]: Dropping packet with malformed header received from {0} in {1}",
1042// buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); 1343// buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
1043 1344
1345 RecordMalformedInboundPacket(endPoint);
1346
1044 return; // Malformed header 1347 return; // Malformed header
1045 } 1348 }
1046 1349
@@ -1056,34 +1359,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1056 // Only allocate a buffer for zerodecoding if the packet is zerocoded 1359 // Only allocate a buffer for zerodecoding if the packet is zerocoded
1057 ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null); 1360 ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
1058 } 1361 }
1059 catch (MalformedDataException)
1060 {
1061 }
1062 catch (IndexOutOfRangeException)
1063 {
1064// m_log.WarnFormat(
1065// "[LLUDPSERVER]: Dropping short packet received from {0} in {1}",
1066// buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
1067
1068 return; // Drop short packet
1069 }
1070 catch (Exception e) 1362 catch (Exception e)
1071 { 1363 {
1072 if (m_malformedCount < 100) 1364 if (IncomingMalformedPacketCount < 100)
1073 m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString()); 1365 m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString());
1074
1075 m_malformedCount++;
1076
1077 if ((m_malformedCount % 100000) == 0)
1078 m_log.DebugFormat("[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack.", m_malformedCount);
1079 } 1366 }
1080 1367
1081 // Fail-safe check 1368 // Fail-safe check
1082 if (packet == null) 1369 if (packet == null)
1083 { 1370 {
1084 m_log.ErrorFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}:", 1371 if (IncomingMalformedPacketCount < 100)
1085 buffer.DataLength, buffer.RemoteEndPoint); 1372 {
1086 m_log.Error(Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)); 1373 m_log.WarnFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}, data {2}:",
1374 buffer.DataLength, buffer.RemoteEndPoint, Utils.BytesToHexString(buffer.Data, buffer.DataLength, null));
1375 }
1376
1377 RecordMalformedInboundPacket(endPoint);
1378
1087 return; 1379 return;
1088 } 1380 }
1089 1381
@@ -1127,12 +1419,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1127 queue.Enqueue(buffer); 1419 queue.Enqueue(buffer);
1128 return; 1420 return;
1129 } 1421 }
1422 else if (packet.Type == PacketType.CompleteAgentMovement)
1423 {
1424 // Send ack straight away to let the viewer know that we got it.
1425 SendAckImmediate(endPoint, packet.Header.Sequence);
1426
1427 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the
1428 // buffer.
1429 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
1430
1431 Util.FireAndForget(HandleCompleteMovementIntoRegion, array);
1432
1433 return;
1434 }
1130 } 1435 }
1131 1436
1132 // Determine which agent this packet came from 1437 // Determine which agent this packet came from
1133 if (client == null || !(client is LLClientView)) 1438 if (client == null || !(client is LLClientView))
1134 { 1439 {
1135 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); 1440 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName);
1441
1442 IncomingOrphanedPacketCount++;
1443
1444 if ((IncomingOrphanedPacketCount % 10000) == 0)
1445 m_log.WarnFormat(
1446 "[LLUDPSERVER]: Received {0} orphaned packets so far. Last was from {1}",
1447 IncomingOrphanedPacketCount, endPoint);
1448
1136 return; 1449 return;
1137 } 1450 }
1138 1451
@@ -1211,6 +1524,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1211 1524
1212 #region Incoming Packet Accounting 1525 #region Incoming Packet Accounting
1213 1526
1527 // We're not going to worry about interlock yet since its not currently critical that this total count
1528 // is 100% correct
1529 if (packet.Header.Resent)
1530 IncomingPacketsResentCount++;
1531
1214 // Check the archive of received reliable packet IDs to see whether we already received this packet 1532 // Check the archive of received reliable packet IDs to see whether we already received this packet
1215 if (packet.Header.Reliable && !udpClient.PacketArchive.TryEnqueue(packet.Header.Sequence)) 1533 if (packet.Header.Reliable && !udpClient.PacketArchive.TryEnqueue(packet.Header.Sequence))
1216 { 1534 {
@@ -1233,6 +1551,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1233 LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length); 1551 LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length);
1234 #endregion BinaryStats 1552 #endregion BinaryStats
1235 1553
1554 if (packet.Type == PacketType.AgentUpdate)
1555 {
1556 if (m_discardAgentUpdates)
1557 return;
1558
1559 ((LLClientView)client).TotalAgentUpdates++;
1560
1561 AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
1562
1563 LLClientView llClient = client as LLClientView;
1564 if (agentUpdate.AgentData.SessionID != client.SessionId
1565 || agentUpdate.AgentData.AgentID != client.AgentId
1566 || !(llClient == null || llClient.CheckAgentUpdateSignificance(agentUpdate.AgentData)) )
1567 {
1568 PacketPool.Instance.ReturnPacket(packet);
1569 return;
1570 }
1571 }
1572
1236 #region Ping Check Handling 1573 #region Ping Check Handling
1237 1574
1238 if (packet.Type == PacketType.StartPingCheck) 1575 if (packet.Type == PacketType.StartPingCheck)
@@ -1421,7 +1758,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1421 1758
1422 // We only want to send initial data to new clients, not ones which are being converted from child to root. 1759 // We only want to send initial data to new clients, not ones which are being converted from child to root.
1423 if (client != null) 1760 if (client != null)
1424 client.SceneAgent.SendInitialDataToMe(); 1761 {
1762 AgentCircuitData aCircuit = m_scene.AuthenticateHandler.GetAgentCircuitData(uccp.CircuitCode.Code);
1763 bool tp = (aCircuit.teleportFlags > 0);
1764 // Let's delay this for TP agents, otherwise the viewer doesn't know where to get resources from
1765 if (!tp)
1766 client.SceneAgent.SendInitialDataToMe();
1767 }
1425 1768
1426 // Now we know we can handle more data 1769 // Now we know we can handle more data
1427 Thread.Sleep(200); 1770 Thread.Sleep(200);
@@ -1476,6 +1819,116 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1476 } 1819 }
1477 } 1820 }
1478 1821
1822 private void HandleCompleteMovementIntoRegion(object o)
1823 {
1824 IPEndPoint endPoint = null;
1825 IClientAPI client = null;
1826
1827 try
1828 {
1829 object[] array = (object[])o;
1830 endPoint = (IPEndPoint)array[0];
1831 CompleteAgentMovementPacket packet = (CompleteAgentMovementPacket)array[1];
1832
1833 m_log.DebugFormat(
1834 "[LLUDPSERVER]: Handling CompleteAgentMovement request from {0} in {1}", endPoint, m_scene.Name);
1835
1836 // Determine which agent this packet came from
1837 // We need to wait here because in when using the OpenSimulator V2 teleport protocol to travel to a destination
1838 // simulator with no existing child presence, the viewer (at least LL 3.3.4) will send UseCircuitCode
1839 // and then CompleteAgentMovement immediately without waiting for an ack. As we are now handling these
1840 // packets asynchronously, we need to account for this thread proceeding more quickly than the
1841 // UseCircuitCode thread.
1842 int count = 40;
1843 while (count-- > 0)
1844 {
1845 if (m_scene.TryGetClient(endPoint, out client))
1846 {
1847 if (!client.IsActive)
1848 {
1849 // This check exists to catch a condition where the client has been closed by another thread
1850 // but has not yet been removed from the client manager (and possibly a new connection has
1851 // not yet been established).
1852 m_log.DebugFormat(
1853 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client is not active yet. Waiting.",
1854 endPoint, client.Name, m_scene.Name);
1855 }
1856 else if (client.SceneAgent == null)
1857 {
1858 // This check exists to catch a condition where the new client has been added to the client
1859 // manager but the SceneAgent has not yet been set in Scene.AddNewAgent(). If we are too
1860 // eager, then the new ScenePresence may not have registered a listener for this messsage
1861 // before we try to process it.
1862 // XXX: A better long term fix may be to add the SceneAgent before the client is added to
1863 // the client manager
1864 m_log.DebugFormat(
1865 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client SceneAgent not set yet. Waiting.",
1866 endPoint, client.Name, m_scene.Name);
1867 }
1868 else
1869 {
1870 break;
1871 }
1872 }
1873 else
1874 {
1875 m_log.DebugFormat(
1876 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} in {1} but no client exists yet. Waiting.",
1877 endPoint, m_scene.Name);
1878 }
1879
1880 Thread.Sleep(200);
1881 }
1882
1883 if (client == null)
1884 {
1885 m_log.DebugFormat(
1886 "[LLUDPSERVER]: No client found for CompleteAgentMovement from {0} in {1} after wait. Dropping.",
1887 endPoint, m_scene.Name);
1888
1889 return;
1890 }
1891 else if (!client.IsActive || client.SceneAgent == null)
1892 {
1893 // This check exists to catch a condition where the client has been closed by another thread
1894 // but has not yet been removed from the client manager.
1895 // The packet could be simply ignored but it is useful to know if this condition occurred for other debugging
1896 // purposes.
1897 m_log.DebugFormat(
1898 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client is not active after wait. Dropping.",
1899 endPoint, client.Name, m_scene.Name);
1900
1901 return;
1902 }
1903
1904 IncomingPacket incomingPacket1;
1905
1906 // Inbox insertion
1907 if (UsePools)
1908 {
1909 incomingPacket1 = m_incomingPacketPool.GetObject();
1910 incomingPacket1.Client = (LLClientView)client;
1911 incomingPacket1.Packet = packet;
1912 }
1913 else
1914 {
1915 incomingPacket1 = new IncomingPacket((LLClientView)client, packet);
1916 }
1917
1918 packetInbox.Enqueue(incomingPacket1);
1919 }
1920 catch (Exception e)
1921 {
1922 m_log.ErrorFormat(
1923 "[LLUDPSERVER]: CompleteAgentMovement handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}",
1924 endPoint != null ? endPoint.ToString() : "n/a",
1925 client != null ? client.Name : "unknown",
1926 client != null ? client.AgentId.ToString() : "unknown",
1927 e.Message,
1928 e.StackTrace);
1929 }
1930 }
1931
1479 /// <summary> 1932 /// <summary>
1480 /// Send an ack immediately to the given endpoint. 1933 /// Send an ack immediately to the given endpoint.
1481 /// </summary> 1934 /// </summary>
@@ -1544,6 +1997,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1544 1997
1545 client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); 1998 client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
1546 client.OnLogout += LogoutHandler; 1999 client.OnLogout += LogoutHandler;
2000 client.DebugPacketLevel = DefaultClientPacketDebugLevel;
1547 2001
1548 ((LLClientView)client).DisableFacelights = m_disableFacelights; 2002 ((LLClientView)client).DisableFacelights = m_disableFacelights;
1549 2003
@@ -1562,21 +2016,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1562 /// regular client pings. 2016 /// regular client pings.
1563 /// </remarks> 2017 /// </remarks>
1564 /// <param name='client'></param> 2018 /// <param name='client'></param>
1565 private void DeactivateClientDueToTimeout(LLClientView client) 2019 /// <param name='timeoutTicks'></param>
2020 private void DeactivateClientDueToTimeout(LLClientView client, int timeoutTicks)
1566 { 2021 {
1567 lock (client.CloseSyncLock) 2022 lock (client.CloseSyncLock)
1568 { 2023 {
2024 ClientLogoutsDueToNoReceives++;
2025
1569 m_log.WarnFormat( 2026 m_log.WarnFormat(
1570 "[LLUDPSERVER]: Ack timeout, disconnecting {0} agent for {1} in {2}", 2027 "[LLUDPSERVER]: No packets received from {0} agent of {1} for {2}ms in {3}. Disconnecting.",
1571 client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, m_scene.RegionInfo.RegionName); 2028 client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, timeoutTicks, m_scene.Name);
1572
1573 StatsManager.SimExtraStats.AddAbnormalClientThreadTermination();
1574 2029
1575 if (!client.SceneAgent.IsChildAgent) 2030 if (!client.SceneAgent.IsChildAgent)
1576 client.Kick("Simulator logged you out due to connection timeout"); 2031 client.Kick("Simulator logged you out due to connection timeout.");
1577
1578 client.CloseWithoutChecks(true);
1579 } 2032 }
2033
2034 m_scene.CloseAgent(client.AgentId, true);
1580 } 2035 }
1581 2036
1582 private void IncomingPacketHandler() 2037 private void IncomingPacketHandler()
@@ -1592,6 +2047,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1592 { 2047 {
1593 IncomingPacket incomingPacket = null; 2048 IncomingPacket incomingPacket = null;
1594 2049
2050 /*
1595 // HACK: This is a test to try and rate limit packet handling on Mono. 2051 // HACK: This is a test to try and rate limit packet handling on Mono.
1596 // If it works, a more elegant solution can be devised 2052 // If it works, a more elegant solution can be devised
1597 if (Util.FireAndForgetCount() < 2) 2053 if (Util.FireAndForgetCount() < 2)
@@ -1599,6 +2055,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1599 //m_log.Debug("[LLUDPSERVER]: Incoming packet handler is sleeping"); 2055 //m_log.Debug("[LLUDPSERVER]: Incoming packet handler is sleeping");
1600 Thread.Sleep(30); 2056 Thread.Sleep(30);
1601 } 2057 }
2058 */
1602 2059
1603 if (packetInbox.Dequeue(100, ref incomingPacket)) 2060 if (packetInbox.Dequeue(100, ref incomingPacket))
1604 { 2061 {
@@ -1694,8 +2151,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1694 2151
1695 // If nothing was sent, sleep for the minimum amount of time before a 2152 // If nothing was sent, sleep for the minimum amount of time before a
1696 // token bucket could get more tokens 2153 // token bucket could get more tokens
2154 //if (!m_packetSent)
2155 // Thread.Sleep((int)TickCountResolution);
2156 //
2157 // Instead, now wait for data present to be explicitly signalled. Evidence so far is that with
2158 // modern mono it reduces CPU base load since there is no more continuous polling.
1697 if (!m_packetSent) 2159 if (!m_packetSent)
1698 Thread.Sleep((int)TickCountResolution); 2160 m_dataPresentEvent.WaitOne(100);
1699 2161
1700 Watchdog.UpdateThread(); 2162 Watchdog.UpdateThread();
1701 } 2163 }
@@ -1912,7 +2374,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1912 if (!client.IsLoggingOut) 2374 if (!client.IsLoggingOut)
1913 { 2375 {
1914 client.IsLoggingOut = true; 2376 client.IsLoggingOut = true;
1915 client.Close(false, false); 2377 m_scene.CloseAgent(client.AgentId, false);
1916 } 2378 }
1917 } 2379 }
1918 } 2380 }