diff options
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs')
-rw-r--r-- | OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | 436 |
1 files changed, 394 insertions, 42 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 4154ef2..ad3f715 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; | |||
34 | using System.Reflection; | 34 | using System.Reflection; |
35 | using System.Threading; | 35 | using System.Threading; |
36 | using log4net; | 36 | using log4net; |
37 | using NDesk.Options; | ||
37 | using Nini.Config; | 38 | using Nini.Config; |
38 | using OpenMetaverse.Packets; | 39 | using OpenMetaverse.Packets; |
39 | using OpenSim.Framework; | 40 | using 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,60 @@ 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 | "OutgoingUDPSendsCount", | ||
138 | "Number of UDP sends performed", | ||
139 | "", | ||
140 | "", | ||
141 | "clientstack", | ||
142 | scene.Name, | ||
143 | StatType.Pull, | ||
144 | MeasuresOfInterest.AverageChangeOverTime, | ||
145 | stat => stat.Value = m_udpServer.UdpSends, | ||
146 | StatVerbosity.Debug)); | ||
147 | |||
148 | StatsManager.RegisterStat( | ||
149 | new Stat( | ||
150 | "AverageUDPProcessTime", | ||
151 | "Average number of milliseconds taken to process each incoming UDP packet in a sample.", | ||
152 | "This is for initial receive processing which is separate from the later client LL packet processing stage.", | ||
153 | "ms", | ||
154 | "clientstack", | ||
155 | scene.Name, | ||
156 | StatType.Pull, | ||
157 | MeasuresOfInterest.None, | ||
158 | stat => stat.Value = m_udpServer.AverageReceiveTicksForLastSamplePeriod / TimeSpan.TicksPerMillisecond, | ||
159 | // stat => | ||
160 | // stat.Value = Math.Round(m_udpServer.AverageReceiveTicksForLastSamplePeriod / TimeSpan.TicksPerMillisecond, 7), | ||
161 | StatVerbosity.Debug)); | ||
86 | } | 162 | } |
87 | 163 | ||
88 | public bool HandlesRegion(Location x) | 164 | public bool HandlesRegion(Location x) |
@@ -107,10 +183,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
107 | /// </summary> | 183 | /// </summary> |
108 | public class LLUDPServer : OpenSimUDPBase | 184 | public class LLUDPServer : OpenSimUDPBase |
109 | { | 185 | { |
186 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
187 | |||
110 | /// <summary>Maximum transmission unit, or UDP packet size, for the LLUDP protocol</summary> | 188 | /// <summary>Maximum transmission unit, or UDP packet size, for the LLUDP protocol</summary> |
111 | public const int MTU = 1400; | 189 | public const int MTU = 1400; |
112 | 190 | ||
113 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 191 | /// <summary>Number of forced client logouts due to no receipt of packets before timeout.</summary> |
192 | public int ClientLogoutsDueToNoReceives { get; private set; } | ||
193 | |||
194 | /// <summary> | ||
195 | /// Default packet debug level given to new clients | ||
196 | /// </summary> | ||
197 | public int DefaultClientPacketDebugLevel { get; set; } | ||
114 | 198 | ||
115 | /// <summary>The measured resolution of Environment.TickCount</summary> | 199 | /// <summary>The measured resolution of Environment.TickCount</summary> |
116 | public readonly float TickCountResolution; | 200 | public readonly float TickCountResolution; |
@@ -184,6 +268,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
184 | protected bool m_sendPing; | 268 | protected bool m_sendPing; |
185 | 269 | ||
186 | private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>(); | 270 | private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>(); |
271 | |||
272 | /// <summary> | ||
273 | /// Event used to signal when queued packets are available for sending. | ||
274 | /// </summary> | ||
275 | /// <remarks> | ||
276 | /// This allows the outbound loop to only operate when there is data to send rather than continuously polling. | ||
277 | /// Some data is sent immediately and not queued. That data would not trigger this event. | ||
278 | /// </remarks> | ||
279 | private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false); | ||
280 | |||
187 | private Pool<IncomingPacket> m_incomingPacketPool; | 281 | private Pool<IncomingPacket> m_incomingPacketPool; |
188 | 282 | ||
189 | /// <summary> | 283 | /// <summary> |
@@ -204,7 +298,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
204 | 298 | ||
205 | public Socket Server { get { return null; } } | 299 | public Socket Server { get { return null; } } |
206 | 300 | ||
207 | private int m_malformedCount = 0; // Guard against a spamming attack | 301 | /// <summary> |
302 | /// Record how many inbound packets could not be recognized as LLUDP packets. | ||
303 | /// </summary> | ||
304 | public int IncomingMalformedPacketCount { get; private set; } | ||
305 | |||
306 | /// <summary> | ||
307 | /// Record how many inbound packets could not be associated with a simulator circuit. | ||
308 | /// </summary> | ||
309 | public int IncomingOrphanedPacketCount { get; private set; } | ||
208 | 310 | ||
209 | /// <summary> | 311 | /// <summary> |
210 | /// Record current outgoing client for monitoring purposes. | 312 | /// Record current outgoing client for monitoring purposes. |
@@ -461,6 +563,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
461 | m_scene = (Scene)scene; | 563 | m_scene = (Scene)scene; |
462 | m_location = new Location(m_scene.RegionInfo.RegionHandle); | 564 | m_location = new Location(m_scene.RegionInfo.RegionHandle); |
463 | 565 | ||
566 | StatsManager.RegisterStat( | ||
567 | new Stat( | ||
568 | "InboxPacketsCount", | ||
569 | "Number of LL protocol packets waiting for the second stage of processing after initial receive.", | ||
570 | "Number of LL protocol packets waiting for the second stage of processing after initial receive.", | ||
571 | "", | ||
572 | "clientstack", | ||
573 | scene.Name, | ||
574 | StatType.Pull, | ||
575 | MeasuresOfInterest.AverageChangeOverTime, | ||
576 | stat => stat.Value = packetInbox.Count, | ||
577 | StatVerbosity.Debug)); | ||
578 | |||
464 | // XXX: These stats are also pool stats but we register them separately since they are currently not | 579 | // 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() | 580 | // turned on and off by EnablePools()/DisablePools() |
466 | StatsManager.RegisterStat( | 581 | StatsManager.RegisterStat( |
@@ -521,6 +636,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
521 | EnablePoolStats(); | 636 | EnablePoolStats(); |
522 | 637 | ||
523 | MainConsole.Instance.Commands.AddCommand( | 638 | MainConsole.Instance.Commands.AddCommand( |
639 | "Debug", false, "debug lludp packet", | ||
640 | "debug lludp packet [--default] <level> [<avatar-first-name> <avatar-last-name>]", | ||
641 | "Turn on packet debugging", | ||
642 | "If level > 255 then all incoming and outgoing packets are logged.\n" | ||
643 | + "If level <= 255 then incoming AgentUpdate and outgoing SimStats and SimulatorViewerTimeMessage packets are not logged.\n" | ||
644 | + "If level <= 200 then incoming RequestImage and outgoing ImagePacket, ImageData, LayerData and CoarseLocationUpdate packets are not logged.\n" | ||
645 | + "If level <= 100 then incoming ViewerEffect and AgentAnimation and outgoing ViewerEffect and AvatarAnimation packets are not logged.\n" | ||
646 | + "If level <= 50 then outgoing ImprovedTerseObjectUpdate packets are not logged.\n" | ||
647 | + "If level <= 0 then no packets are logged.\n" | ||
648 | + "If --default is specified then the level becomes the default logging level for all subsequent agents.\n" | ||
649 | + "In this case, you cannot also specify an avatar name.\n" | ||
650 | + "If an avatar name is given then only packets from that avatar are logged.", | ||
651 | HandlePacketCommand); | ||
652 | |||
653 | MainConsole.Instance.Commands.AddCommand( | ||
524 | "Debug", | 654 | "Debug", |
525 | false, | 655 | false, |
526 | "debug lludp start", | 656 | "debug lludp start", |
@@ -559,10 +689,78 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
559 | "debug lludp status", | 689 | "debug lludp status", |
560 | "Return status of LLUDP packet processing.", | 690 | "Return status of LLUDP packet processing.", |
561 | HandleStatusCommand); | 691 | HandleStatusCommand); |
692 | |||
693 | MainConsole.Instance.Commands.AddCommand( | ||
694 | "Debug", | ||
695 | false, | ||
696 | "debug lludp toggle agentupdate", | ||
697 | "debug lludp toggle agentupdate", | ||
698 | "Toggle whether agentupdate packets are processed or simply discarded.", | ||
699 | HandleAgentUpdateCommand); | ||
700 | } | ||
701 | |||
702 | private void HandlePacketCommand(string module, string[] args) | ||
703 | { | ||
704 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) | ||
705 | return; | ||
706 | |||
707 | bool setAsDefaultLevel = false; | ||
708 | OptionSet optionSet = new OptionSet().Add("default", o => setAsDefaultLevel = o != null); | ||
709 | List<string> filteredArgs = optionSet.Parse(args); | ||
710 | |||
711 | string name = null; | ||
712 | |||
713 | if (filteredArgs.Count == 6) | ||
714 | { | ||
715 | if (!setAsDefaultLevel) | ||
716 | { | ||
717 | name = string.Format("{0} {1}", filteredArgs[4], filteredArgs[5]); | ||
718 | } | ||
719 | else | ||
720 | { | ||
721 | MainConsole.Instance.OutputFormat("ERROR: Cannot specify a user name when setting default logging level"); | ||
722 | return; | ||
723 | } | ||
724 | } | ||
725 | |||
726 | if (filteredArgs.Count > 3) | ||
727 | { | ||
728 | int newDebug; | ||
729 | if (int.TryParse(filteredArgs[3], out newDebug)) | ||
730 | { | ||
731 | if (setAsDefaultLevel) | ||
732 | { | ||
733 | DefaultClientPacketDebugLevel = newDebug; | ||
734 | MainConsole.Instance.OutputFormat( | ||
735 | "Debug packet debug for new clients set to {0} in {1}", DefaultClientPacketDebugLevel, m_scene.Name); | ||
736 | } | ||
737 | else | ||
738 | { | ||
739 | m_scene.ForEachScenePresence(sp => | ||
740 | { | ||
741 | if (name == null || sp.Name == name) | ||
742 | { | ||
743 | MainConsole.Instance.OutputFormat( | ||
744 | "Packet debug for {0} ({1}) set to {2} in {3}", | ||
745 | sp.Name, sp.IsChildAgent ? "child" : "root", newDebug, m_scene.Name); | ||
746 | |||
747 | sp.ControllingClient.DebugPacketLevel = newDebug; | ||
748 | } | ||
749 | }); | ||
750 | } | ||
751 | } | ||
752 | else | ||
753 | { | ||
754 | MainConsole.Instance.Output("Usage: debug lludp packet [--default] 0..255 [<first-name> <last-name>]"); | ||
755 | } | ||
756 | } | ||
562 | } | 757 | } |
563 | 758 | ||
564 | private void HandleStartCommand(string module, string[] args) | 759 | private void HandleStartCommand(string module, string[] args) |
565 | { | 760 | { |
761 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) | ||
762 | return; | ||
763 | |||
566 | if (args.Length != 4) | 764 | if (args.Length != 4) |
567 | { | 765 | { |
568 | MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>"); | 766 | MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>"); |
@@ -580,6 +778,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
580 | 778 | ||
581 | private void HandleStopCommand(string module, string[] args) | 779 | private void HandleStopCommand(string module, string[] args) |
582 | { | 780 | { |
781 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) | ||
782 | return; | ||
783 | |||
583 | if (args.Length != 4) | 784 | if (args.Length != 4) |
584 | { | 785 | { |
585 | MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>"); | 786 | MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>"); |
@@ -597,6 +798,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
597 | 798 | ||
598 | private void HandlePoolCommand(string module, string[] args) | 799 | private void HandlePoolCommand(string module, string[] args) |
599 | { | 800 | { |
801 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) | ||
802 | return; | ||
803 | |||
600 | if (args.Length != 4) | 804 | if (args.Length != 4) |
601 | { | 805 | { |
602 | MainConsole.Instance.Output("Usage: debug lludp pool <on|off>"); | 806 | MainConsole.Instance.Output("Usage: debug lludp pool <on|off>"); |
@@ -627,8 +831,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
627 | } | 831 | } |
628 | } | 832 | } |
629 | 833 | ||
834 | bool m_discardAgentUpdates; | ||
835 | |||
836 | private void HandleAgentUpdateCommand(string module, string[] args) | ||
837 | { | ||
838 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) | ||
839 | return; | ||
840 | |||
841 | m_discardAgentUpdates = !m_discardAgentUpdates; | ||
842 | |||
843 | MainConsole.Instance.OutputFormat( | ||
844 | "Discard AgentUpdates now {0} for {1}", m_discardAgentUpdates, m_scene.Name); | ||
845 | } | ||
846 | |||
630 | private void HandleStatusCommand(string module, string[] args) | 847 | private void HandleStatusCommand(string module, string[] args) |
631 | { | 848 | { |
849 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) | ||
850 | return; | ||
851 | |||
632 | MainConsole.Instance.OutputFormat( | 852 | MainConsole.Instance.OutputFormat( |
633 | "IN LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningInbound ? "enabled" : "disabled"); | 853 | "IN LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningInbound ? "enabled" : "disabled"); |
634 | 854 | ||
@@ -636,6 +856,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
636 | "OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled"); | 856 | "OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled"); |
637 | 857 | ||
638 | MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_scene.Name, UsePools ? "on" : "off"); | 858 | MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_scene.Name, UsePools ? "on" : "off"); |
859 | |||
860 | MainConsole.Instance.OutputFormat( | ||
861 | "Packet debug level for new clients is {0}", DefaultClientPacketDebugLevel); | ||
639 | } | 862 | } |
640 | 863 | ||
641 | public bool HandlesRegion(Location x) | 864 | public bool HandlesRegion(Location x) |
@@ -721,6 +944,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
721 | } | 944 | } |
722 | 945 | ||
723 | PacketPool.Instance.ReturnPacket(packet); | 946 | PacketPool.Instance.ReturnPacket(packet); |
947 | |||
948 | m_dataPresentEvent.Set(); | ||
724 | } | 949 | } |
725 | 950 | ||
726 | /// <summary> | 951 | /// <summary> |
@@ -883,7 +1108,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 | 1108 | // 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. | 1109 | // 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. | 1110 | // This is the same as processing as the async process of a logout request. |
886 | Util.FireAndForget(o => DeactivateClientDueToTimeout(client)); | 1111 | Util.FireAndForget(o => DeactivateClientDueToTimeout(client, timeoutTicks)); |
887 | 1112 | ||
888 | return; | 1113 | return; |
889 | } | 1114 | } |
@@ -1002,6 +1227,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1002 | outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue; | 1227 | outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue; |
1003 | } | 1228 | } |
1004 | 1229 | ||
1230 | private void RecordMalformedInboundPacket(IPEndPoint endPoint) | ||
1231 | { | ||
1232 | // if (m_malformedCount < 100) | ||
1233 | // m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString()); | ||
1234 | |||
1235 | IncomingMalformedPacketCount++; | ||
1236 | |||
1237 | if ((IncomingMalformedPacketCount % 10000) == 0) | ||
1238 | m_log.WarnFormat( | ||
1239 | "[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack. Last was from {1}", | ||
1240 | IncomingMalformedPacketCount, endPoint); | ||
1241 | } | ||
1242 | |||
1005 | public override void PacketReceived(UDPPacketBuffer buffer) | 1243 | public override void PacketReceived(UDPPacketBuffer buffer) |
1006 | { | 1244 | { |
1007 | // Debugging/Profiling | 1245 | // Debugging/Profiling |
@@ -1023,6 +1261,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1023 | // "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}", | 1261 | // "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}", |
1024 | // buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); | 1262 | // buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); |
1025 | 1263 | ||
1264 | RecordMalformedInboundPacket(endPoint); | ||
1265 | |||
1026 | return; // Drop undersized packet | 1266 | return; // Drop undersized packet |
1027 | } | 1267 | } |
1028 | 1268 | ||
@@ -1041,6 +1281,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1041 | // "[LLUDPSERVER]: Dropping packet with malformed header received from {0} in {1}", | 1281 | // "[LLUDPSERVER]: Dropping packet with malformed header received from {0} in {1}", |
1042 | // buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); | 1282 | // buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); |
1043 | 1283 | ||
1284 | RecordMalformedInboundPacket(endPoint); | ||
1285 | |||
1044 | return; // Malformed header | 1286 | return; // Malformed header |
1045 | } | 1287 | } |
1046 | 1288 | ||
@@ -1056,34 +1298,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1056 | // Only allocate a buffer for zerodecoding if the packet is zerocoded | 1298 | // Only allocate a buffer for zerodecoding if the packet is zerocoded |
1057 | ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null); | 1299 | ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null); |
1058 | } | 1300 | } |
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) | 1301 | catch (Exception e) |
1071 | { | 1302 | { |
1072 | if (m_malformedCount < 100) | 1303 | if (IncomingMalformedPacketCount < 100) |
1073 | m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString()); | 1304 | 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 | } | 1305 | } |
1080 | 1306 | ||
1081 | // Fail-safe check | 1307 | // Fail-safe check |
1082 | if (packet == null) | 1308 | if (packet == null) |
1083 | { | 1309 | { |
1084 | m_log.ErrorFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}:", | 1310 | if (IncomingMalformedPacketCount < 100) |
1085 | buffer.DataLength, buffer.RemoteEndPoint); | 1311 | { |
1086 | m_log.Error(Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)); | 1312 | m_log.WarnFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}, data {2}:", |
1313 | buffer.DataLength, buffer.RemoteEndPoint, Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)); | ||
1314 | } | ||
1315 | |||
1316 | RecordMalformedInboundPacket(endPoint); | ||
1317 | |||
1087 | return; | 1318 | return; |
1088 | } | 1319 | } |
1089 | 1320 | ||
@@ -1127,12 +1358,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1127 | queue.Enqueue(buffer); | 1358 | queue.Enqueue(buffer); |
1128 | return; | 1359 | return; |
1129 | } | 1360 | } |
1361 | else if (packet.Type == PacketType.CompleteAgentMovement) | ||
1362 | { | ||
1363 | // Send ack straight away to let the viewer know that we got it. | ||
1364 | SendAckImmediate(endPoint, packet.Header.Sequence); | ||
1365 | |||
1366 | // We need to copy the endpoint so that it doesn't get changed when another thread reuses the | ||
1367 | // buffer. | ||
1368 | object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; | ||
1369 | |||
1370 | Util.FireAndForget(HandleCompleteMovementIntoRegion, array); | ||
1371 | |||
1372 | return; | ||
1373 | } | ||
1130 | } | 1374 | } |
1131 | 1375 | ||
1132 | // Determine which agent this packet came from | 1376 | // Determine which agent this packet came from |
1133 | if (client == null || !(client is LLClientView)) | 1377 | if (client == null || !(client is LLClientView)) |
1134 | { | 1378 | { |
1135 | //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); | 1379 | //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); |
1380 | |||
1381 | IncomingOrphanedPacketCount++; | ||
1382 | |||
1383 | if ((IncomingOrphanedPacketCount % 10000) == 0) | ||
1384 | m_log.WarnFormat( | ||
1385 | "[LLUDPSERVER]: Received {0} orphaned packets so far. Last was from {1}", | ||
1386 | IncomingOrphanedPacketCount, endPoint); | ||
1387 | |||
1136 | return; | 1388 | return; |
1137 | } | 1389 | } |
1138 | 1390 | ||
@@ -1233,6 +1485,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1233 | LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length); | 1485 | LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length); |
1234 | #endregion BinaryStats | 1486 | #endregion BinaryStats |
1235 | 1487 | ||
1488 | if (packet.Type == PacketType.AgentUpdate) | ||
1489 | { | ||
1490 | if (m_discardAgentUpdates) | ||
1491 | return; | ||
1492 | |||
1493 | ((LLClientView)client).TotalAgentUpdates++; | ||
1494 | |||
1495 | AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet; | ||
1496 | |||
1497 | LLClientView llClient = client as LLClientView; | ||
1498 | if (agentUpdate.AgentData.SessionID != client.SessionId | ||
1499 | || agentUpdate.AgentData.AgentID != client.AgentId | ||
1500 | || !(llClient == null || llClient.CheckAgentUpdateSignificance(agentUpdate.AgentData)) ) | ||
1501 | { | ||
1502 | PacketPool.Instance.ReturnPacket(packet); | ||
1503 | return; | ||
1504 | } | ||
1505 | } | ||
1506 | |||
1236 | #region Ping Check Handling | 1507 | #region Ping Check Handling |
1237 | 1508 | ||
1238 | if (packet.Type == PacketType.StartPingCheck) | 1509 | if (packet.Type == PacketType.StartPingCheck) |
@@ -1421,7 +1692,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1421 | 1692 | ||
1422 | // We only want to send initial data to new clients, not ones which are being converted from child to root. | 1693 | // We only want to send initial data to new clients, not ones which are being converted from child to root. |
1423 | if (client != null) | 1694 | if (client != null) |
1424 | client.SceneAgent.SendInitialDataToMe(); | 1695 | { |
1696 | AgentCircuitData aCircuit = m_scene.AuthenticateHandler.GetAgentCircuitData(uccp.CircuitCode.Code); | ||
1697 | bool tp = (aCircuit.teleportFlags > 0); | ||
1698 | // Let's delay this for TP agents, otherwise the viewer doesn't know where to get resources from | ||
1699 | if (!tp) | ||
1700 | client.SceneAgent.SendInitialDataToMe(); | ||
1701 | } | ||
1425 | 1702 | ||
1426 | // Now we know we can handle more data | 1703 | // Now we know we can handle more data |
1427 | Thread.Sleep(200); | 1704 | Thread.Sleep(200); |
@@ -1476,6 +1753,72 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1476 | } | 1753 | } |
1477 | } | 1754 | } |
1478 | 1755 | ||
1756 | private void HandleCompleteMovementIntoRegion(object o) | ||
1757 | { | ||
1758 | IPEndPoint endPoint = null; | ||
1759 | IClientAPI client = null; | ||
1760 | |||
1761 | try | ||
1762 | { | ||
1763 | object[] array = (object[])o; | ||
1764 | endPoint = (IPEndPoint)array[0]; | ||
1765 | CompleteAgentMovementPacket packet = (CompleteAgentMovementPacket)array[1]; | ||
1766 | |||
1767 | // Determine which agent this packet came from | ||
1768 | int count = 20; | ||
1769 | bool ready = false; | ||
1770 | while (!ready && count-- > 0) | ||
1771 | { | ||
1772 | if (m_scene.TryGetClient(endPoint, out client) && client.IsActive && client.SceneAgent != null) | ||
1773 | { | ||
1774 | LLClientView llClientView = (LLClientView)client; | ||
1775 | LLUDPClient udpClient = llClientView.UDPClient; | ||
1776 | if (udpClient != null && udpClient.IsConnected) | ||
1777 | ready = true; | ||
1778 | else | ||
1779 | { | ||
1780 | m_log.Debug("[LLUDPSERVER]: Received a CompleteMovementIntoRegion in " + m_scene.RegionInfo.RegionName + " (not ready yet)"); | ||
1781 | Thread.Sleep(200); | ||
1782 | } | ||
1783 | } | ||
1784 | else | ||
1785 | { | ||
1786 | m_log.Debug("[LLUDPSERVER]: Received a CompleteMovementIntoRegion in " + m_scene.RegionInfo.RegionName + " (not ready yet)"); | ||
1787 | Thread.Sleep(200); | ||
1788 | } | ||
1789 | } | ||
1790 | |||
1791 | if (client == null) | ||
1792 | return; | ||
1793 | |||
1794 | IncomingPacket incomingPacket1; | ||
1795 | |||
1796 | // Inbox insertion | ||
1797 | if (UsePools) | ||
1798 | { | ||
1799 | incomingPacket1 = m_incomingPacketPool.GetObject(); | ||
1800 | incomingPacket1.Client = (LLClientView)client; | ||
1801 | incomingPacket1.Packet = packet; | ||
1802 | } | ||
1803 | else | ||
1804 | { | ||
1805 | incomingPacket1 = new IncomingPacket((LLClientView)client, packet); | ||
1806 | } | ||
1807 | |||
1808 | packetInbox.Enqueue(incomingPacket1); | ||
1809 | } | ||
1810 | catch (Exception e) | ||
1811 | { | ||
1812 | m_log.ErrorFormat( | ||
1813 | "[LLUDPSERVER]: CompleteMovementIntoRegion handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}", | ||
1814 | endPoint != null ? endPoint.ToString() : "n/a", | ||
1815 | client != null ? client.Name : "unknown", | ||
1816 | client != null ? client.AgentId.ToString() : "unknown", | ||
1817 | e.Message, | ||
1818 | e.StackTrace); | ||
1819 | } | ||
1820 | } | ||
1821 | |||
1479 | /// <summary> | 1822 | /// <summary> |
1480 | /// Send an ack immediately to the given endpoint. | 1823 | /// Send an ack immediately to the given endpoint. |
1481 | /// </summary> | 1824 | /// </summary> |
@@ -1544,6 +1887,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1544 | 1887 | ||
1545 | client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); | 1888 | client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); |
1546 | client.OnLogout += LogoutHandler; | 1889 | client.OnLogout += LogoutHandler; |
1890 | client.DebugPacketLevel = DefaultClientPacketDebugLevel; | ||
1547 | 1891 | ||
1548 | ((LLClientView)client).DisableFacelights = m_disableFacelights; | 1892 | ((LLClientView)client).DisableFacelights = m_disableFacelights; |
1549 | 1893 | ||
@@ -1562,21 +1906,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1562 | /// regular client pings. | 1906 | /// regular client pings. |
1563 | /// </remarks> | 1907 | /// </remarks> |
1564 | /// <param name='client'></param> | 1908 | /// <param name='client'></param> |
1565 | private void DeactivateClientDueToTimeout(LLClientView client) | 1909 | /// <param name='timeoutTicks'></param> |
1910 | private void DeactivateClientDueToTimeout(LLClientView client, int timeoutTicks) | ||
1566 | { | 1911 | { |
1567 | lock (client.CloseSyncLock) | 1912 | lock (client.CloseSyncLock) |
1568 | { | 1913 | { |
1914 | ClientLogoutsDueToNoReceives++; | ||
1915 | |||
1569 | m_log.WarnFormat( | 1916 | m_log.WarnFormat( |
1570 | "[LLUDPSERVER]: Ack timeout, disconnecting {0} agent for {1} in {2}", | 1917 | "[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); | 1918 | client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, timeoutTicks, m_scene.Name); |
1572 | |||
1573 | StatsManager.SimExtraStats.AddAbnormalClientThreadTermination(); | ||
1574 | 1919 | ||
1575 | if (!client.SceneAgent.IsChildAgent) | 1920 | if (!client.SceneAgent.IsChildAgent) |
1576 | client.Kick("Simulator logged you out due to connection timeout"); | 1921 | client.Kick("Simulator logged you out due to connection timeout."); |
1577 | |||
1578 | client.CloseWithoutChecks(true); | ||
1579 | } | 1922 | } |
1923 | |||
1924 | m_scene.IncomingCloseAgent(client.AgentId, true); | ||
1580 | } | 1925 | } |
1581 | 1926 | ||
1582 | private void IncomingPacketHandler() | 1927 | private void IncomingPacketHandler() |
@@ -1592,6 +1937,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1592 | { | 1937 | { |
1593 | IncomingPacket incomingPacket = null; | 1938 | IncomingPacket incomingPacket = null; |
1594 | 1939 | ||
1940 | /* | ||
1595 | // HACK: This is a test to try and rate limit packet handling on Mono. | 1941 | // 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 | 1942 | // If it works, a more elegant solution can be devised |
1597 | if (Util.FireAndForgetCount() < 2) | 1943 | if (Util.FireAndForgetCount() < 2) |
@@ -1599,6 +1945,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1599 | //m_log.Debug("[LLUDPSERVER]: Incoming packet handler is sleeping"); | 1945 | //m_log.Debug("[LLUDPSERVER]: Incoming packet handler is sleeping"); |
1600 | Thread.Sleep(30); | 1946 | Thread.Sleep(30); |
1601 | } | 1947 | } |
1948 | */ | ||
1602 | 1949 | ||
1603 | if (packetInbox.Dequeue(100, ref incomingPacket)) | 1950 | if (packetInbox.Dequeue(100, ref incomingPacket)) |
1604 | { | 1951 | { |
@@ -1694,8 +2041,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1694 | 2041 | ||
1695 | // If nothing was sent, sleep for the minimum amount of time before a | 2042 | // If nothing was sent, sleep for the minimum amount of time before a |
1696 | // token bucket could get more tokens | 2043 | // token bucket could get more tokens |
2044 | //if (!m_packetSent) | ||
2045 | // Thread.Sleep((int)TickCountResolution); | ||
2046 | // | ||
2047 | // Instead, now wait for data present to be explicitly signalled. Evidence so far is that with | ||
2048 | // modern mono it reduces CPU base load since there is no more continuous polling. | ||
1697 | if (!m_packetSent) | 2049 | if (!m_packetSent) |
1698 | Thread.Sleep((int)TickCountResolution); | 2050 | m_dataPresentEvent.WaitOne(100); |
1699 | 2051 | ||
1700 | Watchdog.UpdateThread(); | 2052 | Watchdog.UpdateThread(); |
1701 | } | 2053 | } |
@@ -1912,7 +2264,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1912 | if (!client.IsLoggingOut) | 2264 | if (!client.IsLoggingOut) |
1913 | { | 2265 | { |
1914 | client.IsLoggingOut = true; | 2266 | client.IsLoggingOut = true; |
1915 | client.Close(false, false); | 2267 | m_scene.IncomingCloseAgent(client.AgentId, false); |
1916 | } | 2268 | } |
1917 | } | 2269 | } |
1918 | } | 2270 | } |