diff options
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs')
-rw-r--r-- | OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | 711 |
1 files changed, 604 insertions, 107 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 4154ef2..f66534d 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,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; |
@@ -183,7 +293,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
183 | /// <summary>Flag to signal when clients should send pings</summary> | 293 | /// <summary>Flag to signal when clients should send pings</summary> |
184 | protected bool m_sendPing; | 294 | protected bool m_sendPing; |
185 | 295 | ||
296 | private int m_animationSequenceNumber; | ||
297 | |||
298 | public int NextAnimationSequenceNumber | ||
299 | { | ||
300 | get | ||
301 | { | ||
302 | m_animationSequenceNumber++; | ||
303 | if (m_animationSequenceNumber > 2147482624) | ||
304 | m_animationSequenceNumber = 1; | ||
305 | return m_animationSequenceNumber; | ||
306 | } | ||
307 | } | ||
308 | |||
309 | |||
310 | |||
186 | private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>(); | 311 | private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>(); |
312 | |||
313 | /// <summary> | ||
314 | /// Event used to signal when queued packets are available for sending. | ||
315 | /// </summary> | ||
316 | /// <remarks> | ||
317 | /// This allows the outbound loop to only operate when there is data to send rather than continuously polling. | ||
318 | /// Some data is sent immediately and not queued. That data would not trigger this event. | ||
319 | /// WRONG use. May be usefull in future revision | ||
320 | /// </remarks> | ||
321 | // private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false); | ||
322 | |||
187 | private Pool<IncomingPacket> m_incomingPacketPool; | 323 | private Pool<IncomingPacket> m_incomingPacketPool; |
188 | 324 | ||
189 | /// <summary> | 325 | /// <summary> |
@@ -204,7 +340,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
204 | 340 | ||
205 | public Socket Server { get { return null; } } | 341 | public Socket Server { get { return null; } } |
206 | 342 | ||
207 | private int m_malformedCount = 0; // Guard against a spamming attack | 343 | /// <summary> |
344 | /// Record how many packets have been resent | ||
345 | /// </summary> | ||
346 | internal int PacketsResentCount { get; set; } | ||
347 | |||
348 | /// <summary> | ||
349 | /// Record how many packets have been sent | ||
350 | /// </summary> | ||
351 | internal int PacketsSentCount { get; set; } | ||
352 | |||
353 | /// <summary> | ||
354 | /// Record how many incoming packets are indicated as resends by clients. | ||
355 | /// </summary> | ||
356 | internal int IncomingPacketsResentCount { get; set; } | ||
357 | |||
358 | /// <summary> | ||
359 | /// Record how many inbound packets could not be recognized as LLUDP packets. | ||
360 | /// </summary> | ||
361 | public int IncomingMalformedPacketCount { get; private set; } | ||
362 | |||
363 | /// <summary> | ||
364 | /// Record how many inbound packets could not be associated with a simulator circuit. | ||
365 | /// </summary> | ||
366 | public int IncomingOrphanedPacketCount { get; private set; } | ||
208 | 367 | ||
209 | /// <summary> | 368 | /// <summary> |
210 | /// Record current outgoing client for monitoring purposes. | 369 | /// Record current outgoing client for monitoring purposes. |
@@ -225,16 +384,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
225 | 384 | ||
226 | // Measure the resolution of Environment.TickCount | 385 | // Measure the resolution of Environment.TickCount |
227 | TickCountResolution = 0f; | 386 | TickCountResolution = 0f; |
228 | for (int i = 0; i < 5; i++) | 387 | for (int i = 0; i < 10; i++) |
229 | { | 388 | { |
230 | int start = Environment.TickCount; | 389 | int start = Environment.TickCount; |
231 | int now = start; | 390 | int now = start; |
232 | while (now == start) | 391 | while (now == start) |
233 | now = Environment.TickCount; | 392 | now = Environment.TickCount; |
234 | TickCountResolution += (float)(now - start) * 0.2f; | 393 | TickCountResolution += (float)(now - start) * 0.1f; |
235 | } | 394 | } |
236 | m_log.Info("[LLUDPSERVER]: Average Environment.TickCount resolution: " + TickCountResolution + "ms"); | ||
237 | TickCountResolution = (float)Math.Ceiling(TickCountResolution); | 395 | TickCountResolution = (float)Math.Ceiling(TickCountResolution); |
396 | m_log.Info("[LLUDPSERVER]: Average Environment.TickCount resolution: " + TickCountResolution + "ms"); | ||
238 | 397 | ||
239 | #endregion Environment.TickCount Measurement | 398 | #endregion Environment.TickCount Measurement |
240 | 399 | ||
@@ -242,6 +401,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
242 | int sceneThrottleBps = 0; | 401 | int sceneThrottleBps = 0; |
243 | bool usePools = false; | 402 | bool usePools = false; |
244 | 403 | ||
404 | |||
405 | |||
245 | IConfig config = configSource.Configs["ClientStack.LindenUDP"]; | 406 | IConfig config = configSource.Configs["ClientStack.LindenUDP"]; |
246 | if (config != null) | 407 | if (config != null) |
247 | { | 408 | { |
@@ -288,9 +449,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
288 | } | 449 | } |
289 | #endregion BinaryStats | 450 | #endregion BinaryStats |
290 | 451 | ||
291 | m_throttle = new TokenBucket(null, sceneThrottleBps); | 452 | m_throttle = new TokenBucket(null, sceneThrottleBps, sceneThrottleBps * 10e-3f); |
292 | ThrottleRates = new ThrottleRates(configSource); | 453 | ThrottleRates = new ThrottleRates(configSource); |
293 | 454 | ||
455 | Random rnd = new Random(Util.EnvironmentTickCount()); | ||
456 | m_animationSequenceNumber = rnd.Next(11474826); | ||
457 | |||
294 | if (usePools) | 458 | if (usePools) |
295 | EnablePools(); | 459 | EnablePools(); |
296 | } | 460 | } |
@@ -461,6 +625,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
461 | m_scene = (Scene)scene; | 625 | m_scene = (Scene)scene; |
462 | m_location = new Location(m_scene.RegionInfo.RegionHandle); | 626 | m_location = new Location(m_scene.RegionInfo.RegionHandle); |
463 | 627 | ||
628 | StatsManager.RegisterStat( | ||
629 | new Stat( | ||
630 | "InboxPacketsCount", | ||
631 | "Number of LL protocol packets waiting for the second stage of processing after initial receive.", | ||
632 | "Number of LL protocol packets waiting for the second stage of processing after initial receive.", | ||
633 | "", | ||
634 | "clientstack", | ||
635 | scene.Name, | ||
636 | StatType.Pull, | ||
637 | MeasuresOfInterest.AverageChangeOverTime, | ||
638 | stat => stat.Value = packetInbox.Count, | ||
639 | StatVerbosity.Debug)); | ||
640 | |||
464 | // XXX: These stats are also pool stats but we register them separately since they are currently not | 641 | // 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() | 642 | // turned on and off by EnablePools()/DisablePools() |
466 | StatsManager.RegisterStat( | 643 | StatsManager.RegisterStat( |
@@ -521,6 +698,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
521 | EnablePoolStats(); | 698 | EnablePoolStats(); |
522 | 699 | ||
523 | MainConsole.Instance.Commands.AddCommand( | 700 | MainConsole.Instance.Commands.AddCommand( |
701 | "Debug", false, "debug lludp packet", | ||
702 | "debug lludp packet [--default] <level> [<avatar-first-name> <avatar-last-name>]", | ||
703 | "Turn on packet debugging", | ||
704 | "If level > 255 then all incoming and outgoing packets are logged.\n" | ||
705 | + "If level <= 255 then incoming AgentUpdate and outgoing SimStats and SimulatorViewerTimeMessage packets are not logged.\n" | ||
706 | + "If level <= 200 then incoming RequestImage and outgoing ImagePacket, ImageData, LayerData and CoarseLocationUpdate packets are not logged.\n" | ||
707 | + "If level <= 100 then incoming ViewerEffect and AgentAnimation and outgoing ViewerEffect and AvatarAnimation packets are not logged.\n" | ||
708 | + "If level <= 50 then outgoing ImprovedTerseObjectUpdate packets are not logged.\n" | ||
709 | + "If level <= 0 then no packets are logged.\n" | ||
710 | + "If --default is specified then the level becomes the default logging level for all subsequent agents.\n" | ||
711 | + "In this case, you cannot also specify an avatar name.\n" | ||
712 | + "If an avatar name is given then only packets from that avatar are logged.", | ||
713 | HandlePacketCommand); | ||
714 | |||
715 | MainConsole.Instance.Commands.AddCommand( | ||
524 | "Debug", | 716 | "Debug", |
525 | false, | 717 | false, |
526 | "debug lludp start", | 718 | "debug lludp start", |
@@ -559,10 +751,79 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
559 | "debug lludp status", | 751 | "debug lludp status", |
560 | "Return status of LLUDP packet processing.", | 752 | "Return status of LLUDP packet processing.", |
561 | HandleStatusCommand); | 753 | HandleStatusCommand); |
754 | /* disabled | ||
755 | MainConsole.Instance.Commands.AddCommand( | ||
756 | "Debug", | ||
757 | false, | ||
758 | "debug lludp toggle agentupdate", | ||
759 | "debug lludp toggle agentupdate", | ||
760 | "Toggle whether agentupdate packets are processed or simply discarded.", | ||
761 | HandleAgentUpdateCommand); | ||
762 | */ | ||
763 | } | ||
764 | |||
765 | private void HandlePacketCommand(string module, string[] args) | ||
766 | { | ||
767 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) | ||
768 | return; | ||
769 | |||
770 | bool setAsDefaultLevel = false; | ||
771 | OptionSet optionSet = new OptionSet().Add("default", o => setAsDefaultLevel = o != null); | ||
772 | List<string> filteredArgs = optionSet.Parse(args); | ||
773 | |||
774 | string name = null; | ||
775 | |||
776 | if (filteredArgs.Count == 6) | ||
777 | { | ||
778 | if (!setAsDefaultLevel) | ||
779 | { | ||
780 | name = string.Format("{0} {1}", filteredArgs[4], filteredArgs[5]); | ||
781 | } | ||
782 | else | ||
783 | { | ||
784 | MainConsole.Instance.OutputFormat("ERROR: Cannot specify a user name when setting default logging level"); | ||
785 | return; | ||
786 | } | ||
787 | } | ||
788 | |||
789 | if (filteredArgs.Count > 3) | ||
790 | { | ||
791 | int newDebug; | ||
792 | if (int.TryParse(filteredArgs[3], out newDebug)) | ||
793 | { | ||
794 | if (setAsDefaultLevel) | ||
795 | { | ||
796 | DefaultClientPacketDebugLevel = newDebug; | ||
797 | MainConsole.Instance.OutputFormat( | ||
798 | "Debug packet debug for new clients set to {0} in {1}", DefaultClientPacketDebugLevel, m_scene.Name); | ||
799 | } | ||
800 | else | ||
801 | { | ||
802 | m_scene.ForEachScenePresence(sp => | ||
803 | { | ||
804 | if (name == null || sp.Name == name) | ||
805 | { | ||
806 | MainConsole.Instance.OutputFormat( | ||
807 | "Packet debug for {0} ({1}) set to {2} in {3}", | ||
808 | sp.Name, sp.IsChildAgent ? "child" : "root", newDebug, m_scene.Name); | ||
809 | |||
810 | sp.ControllingClient.DebugPacketLevel = newDebug; | ||
811 | } | ||
812 | }); | ||
813 | } | ||
814 | } | ||
815 | else | ||
816 | { | ||
817 | MainConsole.Instance.Output("Usage: debug lludp packet [--default] 0..255 [<first-name> <last-name>]"); | ||
818 | } | ||
819 | } | ||
562 | } | 820 | } |
563 | 821 | ||
564 | private void HandleStartCommand(string module, string[] args) | 822 | private void HandleStartCommand(string module, string[] args) |
565 | { | 823 | { |
824 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) | ||
825 | return; | ||
826 | |||
566 | if (args.Length != 4) | 827 | if (args.Length != 4) |
567 | { | 828 | { |
568 | MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>"); | 829 | MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>"); |
@@ -580,6 +841,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
580 | 841 | ||
581 | private void HandleStopCommand(string module, string[] args) | 842 | private void HandleStopCommand(string module, string[] args) |
582 | { | 843 | { |
844 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) | ||
845 | return; | ||
846 | |||
583 | if (args.Length != 4) | 847 | if (args.Length != 4) |
584 | { | 848 | { |
585 | MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>"); | 849 | MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>"); |
@@ -597,6 +861,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
597 | 861 | ||
598 | private void HandlePoolCommand(string module, string[] args) | 862 | private void HandlePoolCommand(string module, string[] args) |
599 | { | 863 | { |
864 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) | ||
865 | return; | ||
866 | |||
600 | if (args.Length != 4) | 867 | if (args.Length != 4) |
601 | { | 868 | { |
602 | MainConsole.Instance.Output("Usage: debug lludp pool <on|off>"); | 869 | MainConsole.Instance.Output("Usage: debug lludp pool <on|off>"); |
@@ -627,8 +894,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
627 | } | 894 | } |
628 | } | 895 | } |
629 | 896 | ||
897 | bool m_discardAgentUpdates; | ||
898 | |||
899 | private void HandleAgentUpdateCommand(string module, string[] args) | ||
900 | { | ||
901 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) | ||
902 | return; | ||
903 | |||
904 | m_discardAgentUpdates = !m_discardAgentUpdates; | ||
905 | |||
906 | MainConsole.Instance.OutputFormat( | ||
907 | "Discard AgentUpdates now {0} for {1}", m_discardAgentUpdates, m_scene.Name); | ||
908 | } | ||
909 | |||
630 | private void HandleStatusCommand(string module, string[] args) | 910 | private void HandleStatusCommand(string module, string[] args) |
631 | { | 911 | { |
912 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) | ||
913 | return; | ||
914 | |||
632 | MainConsole.Instance.OutputFormat( | 915 | MainConsole.Instance.OutputFormat( |
633 | "IN LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningInbound ? "enabled" : "disabled"); | 916 | "IN LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningInbound ? "enabled" : "disabled"); |
634 | 917 | ||
@@ -636,6 +919,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
636 | "OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled"); | 919 | "OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled"); |
637 | 920 | ||
638 | MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_scene.Name, UsePools ? "on" : "off"); | 921 | MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_scene.Name, UsePools ? "on" : "off"); |
922 | |||
923 | MainConsole.Instance.OutputFormat( | ||
924 | "Packet debug level for new clients is {0}", DefaultClientPacketDebugLevel); | ||
639 | } | 925 | } |
640 | 926 | ||
641 | public bool HandlesRegion(Location x) | 927 | public bool HandlesRegion(Location x) |
@@ -643,44 +929,44 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
643 | return x == m_location; | 929 | return x == m_location; |
644 | } | 930 | } |
645 | 931 | ||
646 | public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting) | 932 | // public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting) |
647 | { | 933 | // { |
648 | // CoarseLocationUpdate and AvatarGroupsReply packets cannot be split in an automated way | 934 | // // CoarseLocationUpdate and AvatarGroupsReply packets cannot be split in an automated way |
649 | if ((packet.Type == PacketType.CoarseLocationUpdate || packet.Type == PacketType.AvatarGroupsReply) && allowSplitting) | 935 | // if ((packet.Type == PacketType.CoarseLocationUpdate || packet.Type == PacketType.AvatarGroupsReply) && allowSplitting) |
650 | allowSplitting = false; | 936 | // allowSplitting = false; |
651 | 937 | // | |
652 | if (allowSplitting && packet.HasVariableBlocks) | 938 | // if (allowSplitting && packet.HasVariableBlocks) |
653 | { | 939 | // { |
654 | byte[][] datas = packet.ToBytesMultiple(); | 940 | // byte[][] datas = packet.ToBytesMultiple(); |
655 | int packetCount = datas.Length; | 941 | // int packetCount = datas.Length; |
656 | 942 | // | |
657 | if (packetCount < 1) | 943 | // if (packetCount < 1) |
658 | m_log.Error("[LLUDPSERVER]: Failed to split " + packet.Type + " with estimated length " + packet.Length); | 944 | // m_log.Error("[LLUDPSERVER]: Failed to split " + packet.Type + " with estimated length " + packet.Length); |
659 | 945 | // | |
660 | for (int i = 0; i < packetCount; i++) | 946 | // for (int i = 0; i < packetCount; i++) |
661 | { | 947 | // { |
662 | byte[] data = datas[i]; | 948 | // byte[] data = datas[i]; |
663 | m_scene.ForEachClient( | 949 | // m_scene.ForEachClient( |
664 | delegate(IClientAPI client) | 950 | // delegate(IClientAPI client) |
665 | { | 951 | // { |
666 | if (client is LLClientView) | 952 | // if (client is LLClientView) |
667 | SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null); | 953 | // SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null); |
668 | } | 954 | // } |
669 | ); | 955 | // ); |
670 | } | 956 | // } |
671 | } | 957 | // } |
672 | else | 958 | // else |
673 | { | 959 | // { |
674 | byte[] data = packet.ToBytes(); | 960 | // byte[] data = packet.ToBytes(); |
675 | m_scene.ForEachClient( | 961 | // m_scene.ForEachClient( |
676 | delegate(IClientAPI client) | 962 | // delegate(IClientAPI client) |
677 | { | 963 | // { |
678 | if (client is LLClientView) | 964 | // if (client is LLClientView) |
679 | SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null); | 965 | // SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null); |
680 | } | 966 | // } |
681 | ); | 967 | // ); |
682 | } | 968 | // } |
683 | } | 969 | // } |
684 | 970 | ||
685 | /// <summary> | 971 | /// <summary> |
686 | /// Start the process of sending a packet to the client. | 972 | /// Start the process of sending a packet to the client. |
@@ -700,6 +986,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
700 | if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting) | 986 | if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting) |
701 | allowSplitting = false; | 987 | allowSplitting = false; |
702 | 988 | ||
989 | bool packetQueued = false; | ||
990 | |||
703 | if (allowSplitting && packet.HasVariableBlocks) | 991 | if (allowSplitting && packet.HasVariableBlocks) |
704 | { | 992 | { |
705 | byte[][] datas = packet.ToBytesMultiple(); | 993 | byte[][] datas = packet.ToBytesMultiple(); |
@@ -711,16 +999,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
711 | for (int i = 0; i < packetCount; i++) | 999 | for (int i = 0; i < packetCount; i++) |
712 | { | 1000 | { |
713 | byte[] data = datas[i]; | 1001 | byte[] data = datas[i]; |
714 | SendPacketData(udpClient, data, packet.Type, category, method); | 1002 | |
1003 | if (!SendPacketData(udpClient, data, packet.Type, category, method)) | ||
1004 | packetQueued = true; | ||
715 | } | 1005 | } |
716 | } | 1006 | } |
717 | else | 1007 | else |
718 | { | 1008 | { |
719 | byte[] data = packet.ToBytes(); | 1009 | byte[] data = packet.ToBytes(); |
720 | SendPacketData(udpClient, data, packet.Type, category, method); | 1010 | packetQueued = SendPacketData(udpClient, data, packet.Type, category, method); |
721 | } | 1011 | } |
722 | 1012 | ||
723 | PacketPool.Instance.ReturnPacket(packet); | 1013 | PacketPool.Instance.ReturnPacket(packet); |
1014 | |||
1015 | /// WRONG use. May be usefull in future revision | ||
1016 | // if (packetQueued) | ||
1017 | // m_dataPresentEvent.Set(); | ||
724 | } | 1018 | } |
725 | 1019 | ||
726 | /// <summary> | 1020 | /// <summary> |
@@ -734,7 +1028,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 | 1028 | /// 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. | 1029 | /// resend of the packet is done. |
736 | /// </param> | 1030 | /// </param> |
737 | public void SendPacketData( | 1031 | /// <returns>true if the data was sent immediately, false if it was queued for sending</returns> |
1032 | public bool SendPacketData( | ||
738 | LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category, UnackedPacketMethod method) | 1033 | LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category, UnackedPacketMethod method) |
739 | { | 1034 | { |
740 | int dataLength = data.Length; | 1035 | int dataLength = data.Length; |
@@ -807,7 +1102,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
807 | // packet so that it isn't sent before a queued update packet. | 1102 | // packet so that it isn't sent before a queued update packet. |
808 | bool requestQueue = type == PacketType.KillObject; | 1103 | bool requestQueue = type == PacketType.KillObject; |
809 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue, highPriority)) | 1104 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue, highPriority)) |
1105 | { | ||
810 | SendPacketFinal(outgoingPacket); | 1106 | SendPacketFinal(outgoingPacket); |
1107 | return true; | ||
1108 | } | ||
1109 | |||
1110 | return false; | ||
811 | 1111 | ||
812 | #endregion Queue or Send | 1112 | #endregion Queue or Send |
813 | } | 1113 | } |
@@ -848,6 +1148,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
848 | pc.PingID.OldestUnacked = 0; | 1148 | pc.PingID.OldestUnacked = 0; |
849 | 1149 | ||
850 | SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false, null); | 1150 | SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false, null); |
1151 | udpClient.m_lastStartpingTimeMS = Util.EnvironmentTickCount(); | ||
851 | } | 1152 | } |
852 | 1153 | ||
853 | public void CompletePing(LLUDPClient udpClient, byte pingID) | 1154 | public void CompletePing(LLUDPClient udpClient, byte pingID) |
@@ -883,7 +1184,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 | 1184 | // 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. | 1185 | // 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. | 1186 | // This is the same as processing as the async process of a logout request. |
886 | Util.FireAndForget(o => DeactivateClientDueToTimeout(client)); | 1187 | Util.FireAndForget(o => DeactivateClientDueToTimeout(client, timeoutTicks)); |
887 | 1188 | ||
888 | return; | 1189 | return; |
889 | } | 1190 | } |
@@ -944,7 +1245,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
944 | int dataLength = buffer.DataLength; | 1245 | int dataLength = buffer.DataLength; |
945 | 1246 | ||
946 | // NOTE: I'm seeing problems with some viewers when ACKs are appended to zerocoded packets so I've disabled that here | 1247 | // NOTE: I'm seeing problems with some viewers when ACKs are appended to zerocoded packets so I've disabled that here |
947 | if (!isZerocoded) | 1248 | if (!isZerocoded && !isResend && outgoingPacket.UnackedMethod == null) |
948 | { | 1249 | { |
949 | // Keep appending ACKs until there is no room left in the buffer or there are | 1250 | // Keep appending ACKs until there is no room left in the buffer or there are |
950 | // no more ACKs to append | 1251 | // no more ACKs to append |
@@ -988,6 +1289,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
988 | else | 1289 | else |
989 | { | 1290 | { |
990 | Interlocked.Increment(ref udpClient.PacketsResent); | 1291 | Interlocked.Increment(ref udpClient.PacketsResent); |
1292 | |||
1293 | // We're not going to worry about interlock yet since its not currently critical that this total count | ||
1294 | // is 100% correct | ||
1295 | PacketsResentCount++; | ||
991 | } | 1296 | } |
992 | 1297 | ||
993 | #endregion Sequence Number Assignment | 1298 | #endregion Sequence Number Assignment |
@@ -995,6 +1300,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
995 | // Stats tracking | 1300 | // Stats tracking |
996 | Interlocked.Increment(ref udpClient.PacketsSent); | 1301 | Interlocked.Increment(ref udpClient.PacketsSent); |
997 | 1302 | ||
1303 | // We're not going to worry about interlock yet since its not currently critical that this total count | ||
1304 | // is 100% correct | ||
1305 | PacketsSentCount++; | ||
1306 | |||
998 | // Put the UDP payload on the wire | 1307 | // Put the UDP payload on the wire |
999 | AsyncBeginSend(buffer); | 1308 | AsyncBeginSend(buffer); |
1000 | 1309 | ||
@@ -1002,6 +1311,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1002 | outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue; | 1311 | outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue; |
1003 | } | 1312 | } |
1004 | 1313 | ||
1314 | private void RecordMalformedInboundPacket(IPEndPoint endPoint) | ||
1315 | { | ||
1316 | // if (m_malformedCount < 100) | ||
1317 | // m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString()); | ||
1318 | |||
1319 | IncomingMalformedPacketCount++; | ||
1320 | |||
1321 | if ((IncomingMalformedPacketCount % 10000) == 0) | ||
1322 | m_log.WarnFormat( | ||
1323 | "[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack. Last was from {1}", | ||
1324 | IncomingMalformedPacketCount, endPoint); | ||
1325 | } | ||
1326 | |||
1005 | public override void PacketReceived(UDPPacketBuffer buffer) | 1327 | public override void PacketReceived(UDPPacketBuffer buffer) |
1006 | { | 1328 | { |
1007 | // Debugging/Profiling | 1329 | // Debugging/Profiling |
@@ -1023,6 +1345,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1023 | // "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}", | 1345 | // "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}", |
1024 | // buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); | 1346 | // buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); |
1025 | 1347 | ||
1348 | RecordMalformedInboundPacket(endPoint); | ||
1349 | |||
1026 | return; // Drop undersized packet | 1350 | return; // Drop undersized packet |
1027 | } | 1351 | } |
1028 | 1352 | ||
@@ -1041,6 +1365,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1041 | // "[LLUDPSERVER]: Dropping packet with malformed header received from {0} in {1}", | 1365 | // "[LLUDPSERVER]: Dropping packet with malformed header received from {0} in {1}", |
1042 | // buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); | 1366 | // buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); |
1043 | 1367 | ||
1368 | RecordMalformedInboundPacket(endPoint); | ||
1369 | |||
1044 | return; // Malformed header | 1370 | return; // Malformed header |
1045 | } | 1371 | } |
1046 | 1372 | ||
@@ -1056,34 +1382,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1056 | // Only allocate a buffer for zerodecoding if the packet is zerocoded | 1382 | // Only allocate a buffer for zerodecoding if the packet is zerocoded |
1057 | ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null); | 1383 | ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null); |
1058 | } | 1384 | } |
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) | 1385 | catch (Exception e) |
1071 | { | 1386 | { |
1072 | if (m_malformedCount < 100) | 1387 | if (IncomingMalformedPacketCount < 100) |
1073 | m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString()); | 1388 | 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 | } | 1389 | } |
1080 | 1390 | ||
1081 | // Fail-safe check | 1391 | // Fail-safe check |
1082 | if (packet == null) | 1392 | if (packet == null) |
1083 | { | 1393 | { |
1084 | m_log.ErrorFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}:", | 1394 | if (IncomingMalformedPacketCount < 100) |
1085 | buffer.DataLength, buffer.RemoteEndPoint); | 1395 | { |
1086 | m_log.Error(Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)); | 1396 | m_log.WarnFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}, data {2}:", |
1397 | buffer.DataLength, buffer.RemoteEndPoint, Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)); | ||
1398 | } | ||
1399 | |||
1400 | RecordMalformedInboundPacket(endPoint); | ||
1401 | |||
1087 | return; | 1402 | return; |
1088 | } | 1403 | } |
1089 | 1404 | ||
@@ -1127,12 +1442,36 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1127 | queue.Enqueue(buffer); | 1442 | queue.Enqueue(buffer); |
1128 | return; | 1443 | return; |
1129 | } | 1444 | } |
1445 | |||
1446 | /* | ||
1447 | else if (packet.Type == PacketType.CompleteAgentMovement) | ||
1448 | { | ||
1449 | // Send ack straight away to let the viewer know that we got it. | ||
1450 | SendAckImmediate(endPoint, packet.Header.Sequence); | ||
1451 | |||
1452 | // We need to copy the endpoint so that it doesn't get changed when another thread reuses the | ||
1453 | // buffer. | ||
1454 | object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; | ||
1455 | |||
1456 | Util.FireAndForget(HandleCompleteMovementIntoRegion, array); | ||
1457 | |||
1458 | return; | ||
1459 | } | ||
1460 | */ | ||
1130 | } | 1461 | } |
1131 | 1462 | ||
1132 | // Determine which agent this packet came from | 1463 | // Determine which agent this packet came from |
1133 | if (client == null || !(client is LLClientView)) | 1464 | if (client == null || !(client is LLClientView)) |
1134 | { | 1465 | { |
1135 | //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); | 1466 | //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); |
1467 | |||
1468 | IncomingOrphanedPacketCount++; | ||
1469 | |||
1470 | if ((IncomingOrphanedPacketCount % 10000) == 0) | ||
1471 | m_log.WarnFormat( | ||
1472 | "[LLUDPSERVER]: Received {0} orphaned packets so far. Last was from {1}", | ||
1473 | IncomingOrphanedPacketCount, endPoint); | ||
1474 | |||
1136 | return; | 1475 | return; |
1137 | } | 1476 | } |
1138 | 1477 | ||
@@ -1211,6 +1550,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1211 | 1550 | ||
1212 | #region Incoming Packet Accounting | 1551 | #region Incoming Packet Accounting |
1213 | 1552 | ||
1553 | // We're not going to worry about interlock yet since its not currently critical that this total count | ||
1554 | // is 100% correct | ||
1555 | if (packet.Header.Resent) | ||
1556 | IncomingPacketsResentCount++; | ||
1557 | |||
1214 | // Check the archive of received reliable packet IDs to see whether we already received this packet | 1558 | // 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)) | 1559 | if (packet.Header.Reliable && !udpClient.PacketArchive.TryEnqueue(packet.Header.Sequence)) |
1216 | { | 1560 | { |
@@ -1233,6 +1577,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1233 | LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length); | 1577 | LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length); |
1234 | #endregion BinaryStats | 1578 | #endregion BinaryStats |
1235 | 1579 | ||
1580 | // AgentUpdate mess removed from here | ||
1581 | |||
1236 | #region Ping Check Handling | 1582 | #region Ping Check Handling |
1237 | 1583 | ||
1238 | if (packet.Type == PacketType.StartPingCheck) | 1584 | if (packet.Type == PacketType.StartPingCheck) |
@@ -1242,7 +1588,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1242 | // We don't need to do anything else with ping checks | 1588 | // We don't need to do anything else with ping checks |
1243 | StartPingCheckPacket startPing = (StartPingCheckPacket)packet; | 1589 | StartPingCheckPacket startPing = (StartPingCheckPacket)packet; |
1244 | CompletePing(udpClient, startPing.PingID.PingID); | 1590 | CompletePing(udpClient, startPing.PingID.PingID); |
1245 | 1591 | ||
1246 | if ((Environment.TickCount - m_elapsedMSSinceLastStatReport) >= 3000) | 1592 | if ((Environment.TickCount - m_elapsedMSSinceLastStatReport) >= 3000) |
1247 | { | 1593 | { |
1248 | udpClient.SendPacketStats(); | 1594 | udpClient.SendPacketStats(); |
@@ -1252,7 +1598,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1252 | } | 1598 | } |
1253 | else if (packet.Type == PacketType.CompletePingCheck) | 1599 | else if (packet.Type == PacketType.CompletePingCheck) |
1254 | { | 1600 | { |
1255 | // We don't currently track client ping times | 1601 | int t = Util.EnvironmentTickCountSubtract(udpClient.m_lastStartpingTimeMS); |
1602 | int c = udpClient.m_pingMS; | ||
1603 | c = 800 * c + 200 * t; | ||
1604 | c /= 1000; | ||
1605 | udpClient.m_pingMS = c; | ||
1256 | return; | 1606 | return; |
1257 | } | 1607 | } |
1258 | 1608 | ||
@@ -1272,11 +1622,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1272 | incomingPacket = new IncomingPacket((LLClientView)client, packet); | 1622 | incomingPacket = new IncomingPacket((LLClientView)client, packet); |
1273 | } | 1623 | } |
1274 | 1624 | ||
1275 | if (incomingPacket.Packet.Type == PacketType.AgentUpdate || | 1625 | // if (incomingPacket.Packet.Type == PacketType.AgentUpdate || |
1276 | incomingPacket.Packet.Type == PacketType.ChatFromViewer) | 1626 | // incomingPacket.Packet.Type == PacketType.ChatFromViewer) |
1627 | if (incomingPacket.Packet.Type == PacketType.ChatFromViewer) | ||
1277 | packetInbox.EnqueueHigh(incomingPacket); | 1628 | packetInbox.EnqueueHigh(incomingPacket); |
1278 | else | 1629 | else |
1279 | packetInbox.EnqueueLow(incomingPacket); | 1630 | packetInbox.EnqueueLow(incomingPacket); |
1631 | |||
1280 | } | 1632 | } |
1281 | 1633 | ||
1282 | #region BinaryStats | 1634 | #region BinaryStats |
@@ -1393,7 +1745,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1393 | 1745 | ||
1394 | try | 1746 | try |
1395 | { | 1747 | { |
1396 | // DateTime startTime = DateTime.Now; | 1748 | // DateTime startTime = DateTime.Now; |
1397 | object[] array = (object[])o; | 1749 | object[] array = (object[])o; |
1398 | endPoint = (IPEndPoint)array[0]; | 1750 | endPoint = (IPEndPoint)array[0]; |
1399 | UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1]; | 1751 | UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1]; |
@@ -1413,20 +1765,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1413 | uccp.CircuitCode.SessionID, | 1765 | uccp.CircuitCode.SessionID, |
1414 | endPoint, | 1766 | endPoint, |
1415 | sessionInfo); | 1767 | sessionInfo); |
1416 | |||
1417 | // Send ack straight away to let the viewer know that the connection is active. | ||
1418 | // The client will be null if it already exists (e.g. if on a region crossing the client sends a use | ||
1419 | // circuit code to the existing child agent. This is not particularly obvious. | ||
1420 | SendAckImmediate(endPoint, uccp.Header.Sequence); | ||
1421 | |||
1422 | // We only want to send initial data to new clients, not ones which are being converted from child to root. | ||
1423 | if (client != null) | ||
1424 | client.SceneAgent.SendInitialDataToMe(); | ||
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); |
1428 | 1771 | ||
1429 | // Obtain the queue and remove it from the cache | 1772 | // Obtain the pending queue and remove it from the cache |
1430 | Queue<UDPPacketBuffer> queue = null; | 1773 | Queue<UDPPacketBuffer> queue = null; |
1431 | 1774 | ||
1432 | lock (m_pendingCache) | 1775 | lock (m_pendingCache) |
@@ -1435,6 +1778,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1435 | { | 1778 | { |
1436 | m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present"); | 1779 | m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present"); |
1437 | return; | 1780 | return; |
1781 | |||
1438 | } | 1782 | } |
1439 | m_pendingCache.Remove(endPoint); | 1783 | m_pendingCache.Remove(endPoint); |
1440 | } | 1784 | } |
@@ -1442,12 +1786,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1442 | m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count); | 1786 | m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count); |
1443 | 1787 | ||
1444 | // Reinject queued packets | 1788 | // Reinject queued packets |
1445 | while(queue.Count > 0) | 1789 | while (queue.Count > 0) |
1446 | { | 1790 | { |
1447 | UDPPacketBuffer buf = queue.Dequeue(); | 1791 | UDPPacketBuffer buf = queue.Dequeue(); |
1448 | PacketReceived(buf); | 1792 | PacketReceived(buf); |
1449 | } | 1793 | } |
1794 | |||
1450 | queue = null; | 1795 | queue = null; |
1796 | |||
1797 | // Send ack straight away to let the viewer know that the connection is active. | ||
1798 | // The client will be null if it already exists (e.g. if on a region crossing the client sends a use | ||
1799 | // circuit code to the existing child agent. This is not particularly obvious. | ||
1800 | SendAckImmediate(endPoint, uccp.Header.Sequence); | ||
1801 | |||
1802 | // We only want to send initial data to new clients, not ones which are being converted from child to root. | ||
1803 | if (client != null) | ||
1804 | { | ||
1805 | AgentCircuitData aCircuit = m_scene.AuthenticateHandler.GetAgentCircuitData(uccp.CircuitCode.Code); | ||
1806 | bool tp = (aCircuit.teleportFlags > 0); | ||
1807 | // Let's delay this for TP agents, otherwise the viewer doesn't know where to get resources from | ||
1808 | if (!tp) | ||
1809 | client.SceneAgent.SendInitialDataToMe(); | ||
1810 | } | ||
1451 | } | 1811 | } |
1452 | else | 1812 | else |
1453 | { | 1813 | { |
@@ -1455,10 +1815,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1455 | m_log.WarnFormat( | 1815 | m_log.WarnFormat( |
1456 | "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", | 1816 | "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", |
1457 | uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint); | 1817 | uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint); |
1818 | |||
1458 | lock (m_pendingCache) | 1819 | lock (m_pendingCache) |
1459 | m_pendingCache.Remove(endPoint); | 1820 | m_pendingCache.Remove(endPoint); |
1460 | } | 1821 | } |
1461 | |||
1462 | // m_log.DebugFormat( | 1822 | // m_log.DebugFormat( |
1463 | // "[LLUDPSERVER]: Handling UseCircuitCode request from {0} took {1}ms", | 1823 | // "[LLUDPSERVER]: Handling UseCircuitCode request from {0} took {1}ms", |
1464 | // buffer.RemoteEndPoint, (DateTime.Now - startTime).Milliseconds); | 1824 | // buffer.RemoteEndPoint, (DateTime.Now - startTime).Milliseconds); |
@@ -1475,6 +1835,117 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1475 | e.StackTrace); | 1835 | e.StackTrace); |
1476 | } | 1836 | } |
1477 | } | 1837 | } |
1838 | /* | ||
1839 | private void HandleCompleteMovementIntoRegion(object o) | ||
1840 | { | ||
1841 | IPEndPoint endPoint = null; | ||
1842 | IClientAPI client = null; | ||
1843 | |||
1844 | try | ||
1845 | { | ||
1846 | object[] array = (object[])o; | ||
1847 | endPoint = (IPEndPoint)array[0]; | ||
1848 | CompleteAgentMovementPacket packet = (CompleteAgentMovementPacket)array[1]; | ||
1849 | |||
1850 | m_log.DebugFormat( | ||
1851 | "[LLUDPSERVER]: Handling CompleteAgentMovement request from {0} in {1}", endPoint, m_scene.Name); | ||
1852 | |||
1853 | // Determine which agent this packet came from | ||
1854 | // We need to wait here because in when using the OpenSimulator V2 teleport protocol to travel to a destination | ||
1855 | // simulator with no existing child presence, the viewer (at least LL 3.3.4) will send UseCircuitCode | ||
1856 | // and then CompleteAgentMovement immediately without waiting for an ack. As we are now handling these | ||
1857 | // packets asynchronously, we need to account for this thread proceeding more quickly than the | ||
1858 | // UseCircuitCode thread. | ||
1859 | int count = 40; | ||
1860 | while (count-- > 0) | ||
1861 | { | ||
1862 | if (m_scene.TryGetClient(endPoint, out client)) | ||
1863 | { | ||
1864 | if (!client.IsActive) | ||
1865 | { | ||
1866 | // This check exists to catch a condition where the client has been closed by another thread | ||
1867 | // but has not yet been removed from the client manager (and possibly a new connection has | ||
1868 | // not yet been established). | ||
1869 | m_log.DebugFormat( | ||
1870 | "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client is not active yet. Waiting.", | ||
1871 | endPoint, client.Name, m_scene.Name); | ||
1872 | } | ||
1873 | else if (client.SceneAgent == null) | ||
1874 | { | ||
1875 | // This check exists to catch a condition where the new client has been added to the client | ||
1876 | // manager but the SceneAgent has not yet been set in Scene.AddNewAgent(). If we are too | ||
1877 | // eager, then the new ScenePresence may not have registered a listener for this messsage | ||
1878 | // before we try to process it. | ||
1879 | // XXX: A better long term fix may be to add the SceneAgent before the client is added to | ||
1880 | // the client manager | ||
1881 | m_log.DebugFormat( | ||
1882 | "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client SceneAgent not set yet. Waiting.", | ||
1883 | endPoint, client.Name, m_scene.Name); | ||
1884 | } | ||
1885 | else | ||
1886 | { | ||
1887 | break; | ||
1888 | } | ||
1889 | } | ||
1890 | else | ||
1891 | { | ||
1892 | m_log.DebugFormat( | ||
1893 | "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} in {1} but no client exists yet. Waiting.", | ||
1894 | endPoint, m_scene.Name); | ||
1895 | } | ||
1896 | |||
1897 | Thread.Sleep(200); | ||
1898 | } | ||
1899 | |||
1900 | if (client == null) | ||
1901 | { | ||
1902 | m_log.DebugFormat( | ||
1903 | "[LLUDPSERVER]: No client found for CompleteAgentMovement from {0} in {1} after wait. Dropping.", | ||
1904 | endPoint, m_scene.Name); | ||
1905 | |||
1906 | return; | ||
1907 | } | ||
1908 | else if (!client.IsActive || client.SceneAgent == null) | ||
1909 | { | ||
1910 | // This check exists to catch a condition where the client has been closed by another thread | ||
1911 | // but has not yet been removed from the client manager. | ||
1912 | // The packet could be simply ignored but it is useful to know if this condition occurred for other debugging | ||
1913 | // purposes. | ||
1914 | m_log.DebugFormat( | ||
1915 | "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client is not active after wait. Dropping.", | ||
1916 | endPoint, client.Name, m_scene.Name); | ||
1917 | |||
1918 | return; | ||
1919 | } | ||
1920 | |||
1921 | IncomingPacket incomingPacket1; | ||
1922 | |||
1923 | // Inbox insertion | ||
1924 | if (UsePools) | ||
1925 | { | ||
1926 | incomingPacket1 = m_incomingPacketPool.GetObject(); | ||
1927 | incomingPacket1.Client = (LLClientView)client; | ||
1928 | incomingPacket1.Packet = packet; | ||
1929 | } | ||
1930 | else | ||
1931 | { | ||
1932 | incomingPacket1 = new IncomingPacket((LLClientView)client, packet); | ||
1933 | } | ||
1934 | |||
1935 | packetInbox.Enqueue(incomingPacket1); | ||
1936 | } | ||
1937 | catch (Exception e) | ||
1938 | { | ||
1939 | m_log.ErrorFormat( | ||
1940 | "[LLUDPSERVER]: CompleteAgentMovement handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}", | ||
1941 | endPoint != null ? endPoint.ToString() : "n/a", | ||
1942 | client != null ? client.Name : "unknown", | ||
1943 | client != null ? client.AgentId.ToString() : "unknown", | ||
1944 | e.Message, | ||
1945 | e.StackTrace); | ||
1946 | } | ||
1947 | } | ||
1948 | */ | ||
1478 | 1949 | ||
1479 | /// <summary> | 1950 | /// <summary> |
1480 | /// Send an ack immediately to the given endpoint. | 1951 | /// Send an ack immediately to the given endpoint. |
@@ -1532,6 +2003,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1532 | uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo) | 2003 | uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo) |
1533 | { | 2004 | { |
1534 | IClientAPI client = null; | 2005 | IClientAPI client = null; |
2006 | bool createNew = false; | ||
1535 | 2007 | ||
1536 | // We currently synchronize this code across the whole scene to avoid issues such as | 2008 | // We currently synchronize this code across the whole scene to avoid issues such as |
1537 | // http://opensimulator.org/mantis/view.php?id=5365 However, once locking per agent circuit can be done | 2009 | // http://opensimulator.org/mantis/view.php?id=5365 However, once locking per agent circuit can be done |
@@ -1540,10 +2012,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1540 | { | 2012 | { |
1541 | if (!m_scene.TryGetClient(agentID, out client)) | 2013 | if (!m_scene.TryGetClient(agentID, out client)) |
1542 | { | 2014 | { |
2015 | createNew = true; | ||
2016 | } | ||
2017 | else | ||
2018 | { | ||
2019 | if (client.SceneAgent == null) | ||
2020 | { | ||
2021 | m_scene.CloseAgent(agentID, true); | ||
2022 | createNew = true; | ||
2023 | } | ||
2024 | } | ||
2025 | |||
2026 | if (createNew) | ||
2027 | { | ||
1543 | LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, m_throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO); | 2028 | LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, m_throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO); |
1544 | 2029 | ||
1545 | client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); | 2030 | client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); |
1546 | client.OnLogout += LogoutHandler; | 2031 | client.OnLogout += LogoutHandler; |
2032 | client.DebugPacketLevel = DefaultClientPacketDebugLevel; | ||
1547 | 2033 | ||
1548 | ((LLClientView)client).DisableFacelights = m_disableFacelights; | 2034 | ((LLClientView)client).DisableFacelights = m_disableFacelights; |
1549 | 2035 | ||
@@ -1562,21 +2048,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1562 | /// regular client pings. | 2048 | /// regular client pings. |
1563 | /// </remarks> | 2049 | /// </remarks> |
1564 | /// <param name='client'></param> | 2050 | /// <param name='client'></param> |
1565 | private void DeactivateClientDueToTimeout(LLClientView client) | 2051 | /// <param name='timeoutTicks'></param> |
2052 | private void DeactivateClientDueToTimeout(LLClientView client, int timeoutTicks) | ||
1566 | { | 2053 | { |
1567 | lock (client.CloseSyncLock) | 2054 | lock (client.CloseSyncLock) |
1568 | { | 2055 | { |
1569 | m_log.WarnFormat( | 2056 | ClientLogoutsDueToNoReceives++; |
1570 | "[LLUDPSERVER]: Ack timeout, disconnecting {0} agent for {1} in {2}", | 2057 | |
1571 | client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, m_scene.RegionInfo.RegionName); | 2058 | if (client.SceneAgent != null) |
1572 | 2059 | { | |
1573 | StatsManager.SimExtraStats.AddAbnormalClientThreadTermination(); | 2060 | m_log.WarnFormat( |
1574 | 2061 | "[LLUDPSERVER]: No packets received from {0} agent of {1} for {2}ms in {3}. Disconnecting.", | |
1575 | if (!client.SceneAgent.IsChildAgent) | 2062 | client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, timeoutTicks, m_scene.Name); |
1576 | client.Kick("Simulator logged you out due to connection timeout"); | ||
1577 | 2063 | ||
1578 | client.CloseWithoutChecks(true); | 2064 | if (!client.SceneAgent.IsChildAgent) |
2065 | client.Kick("Simulator logged you out due to connection timeout."); | ||
2066 | } | ||
1579 | } | 2067 | } |
2068 | |||
2069 | if (!m_scene.CloseAgent(client.AgentId, true)) | ||
2070 | client.Close(true,true); | ||
1580 | } | 2071 | } |
1581 | 2072 | ||
1582 | private void IncomingPacketHandler() | 2073 | private void IncomingPacketHandler() |
@@ -1592,6 +2083,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1592 | { | 2083 | { |
1593 | IncomingPacket incomingPacket = null; | 2084 | IncomingPacket incomingPacket = null; |
1594 | 2085 | ||
2086 | /* | ||
1595 | // HACK: This is a test to try and rate limit packet handling on Mono. | 2087 | // 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 | 2088 | // If it works, a more elegant solution can be devised |
1597 | if (Util.FireAndForgetCount() < 2) | 2089 | if (Util.FireAndForgetCount() < 2) |
@@ -1599,6 +2091,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1599 | //m_log.Debug("[LLUDPSERVER]: Incoming packet handler is sleeping"); | 2091 | //m_log.Debug("[LLUDPSERVER]: Incoming packet handler is sleeping"); |
1600 | Thread.Sleep(30); | 2092 | Thread.Sleep(30); |
1601 | } | 2093 | } |
2094 | */ | ||
1602 | 2095 | ||
1603 | if (packetInbox.Dequeue(100, ref incomingPacket)) | 2096 | if (packetInbox.Dequeue(100, ref incomingPacket)) |
1604 | { | 2097 | { |
@@ -1608,7 +2101,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1608 | m_incomingPacketPool.ReturnObject(incomingPacket); | 2101 | m_incomingPacketPool.ReturnObject(incomingPacket); |
1609 | } | 2102 | } |
1610 | } | 2103 | } |
1611 | catch (Exception ex) | 2104 | catch(Exception ex) |
1612 | { | 2105 | { |
1613 | m_log.Error("[LLUDPSERVER]: Error in the incoming packet handler loop: " + ex.Message, ex); | 2106 | m_log.Error("[LLUDPSERVER]: Error in the incoming packet handler loop: " + ex.Message, ex); |
1614 | } | 2107 | } |
@@ -1694,9 +2187,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1694 | 2187 | ||
1695 | // If nothing was sent, sleep for the minimum amount of time before a | 2188 | // If nothing was sent, sleep for the minimum amount of time before a |
1696 | // token bucket could get more tokens | 2189 | // token bucket could get more tokens |
2190 | |||
1697 | if (!m_packetSent) | 2191 | if (!m_packetSent) |
1698 | Thread.Sleep((int)TickCountResolution); | 2192 | Thread.Sleep((int)TickCountResolution); |
1699 | 2193 | ||
2194 | // .... wrong core code removed | ||
2195 | |||
2196 | |||
1700 | Watchdog.UpdateThread(); | 2197 | Watchdog.UpdateThread(); |
1701 | } | 2198 | } |
1702 | catch (Exception ex) | 2199 | catch (Exception ex) |
@@ -1912,7 +2409,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1912 | if (!client.IsLoggingOut) | 2409 | if (!client.IsLoggingOut) |
1913 | { | 2410 | { |
1914 | client.IsLoggingOut = true; | 2411 | client.IsLoggingOut = true; |
1915 | client.Close(false, false); | 2412 | m_scene.CloseAgent(client.AgentId, false); |
1916 | } | 2413 | } |
1917 | } | 2414 | } |
1918 | } | 2415 | } |