aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs')
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs711
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;
34using System.Reflection; 34using System.Reflection;
35using System.Threading; 35using System.Threading;
36using log4net; 36using log4net;
37using NDesk.Options;
37using Nini.Config; 38using Nini.Config;
38using OpenMetaverse.Packets; 39using OpenMetaverse.Packets;
39using OpenSim.Framework; 40using OpenSim.Framework;
@@ -62,20 +63,41 @@ namespace OpenSim.Region.ClientStack.LindenUDP
62 m_udpServer = new LLUDPServer(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager); 63 m_udpServer = new LLUDPServer(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager);
63 } 64 }
64 65
65 public void NetworkStop()
66 {
67 m_udpServer.Stop();
68 }
69
70 public void AddScene(IScene scene) 66 public void AddScene(IScene scene)
71 { 67 {
72 m_udpServer.AddScene(scene); 68 m_udpServer.AddScene(scene);
73 69
74 StatsManager.RegisterStat( 70 StatsManager.RegisterStat(
75 new Stat( 71 new Stat(
72 "ClientLogoutsDueToNoReceives",
73 "Number of times a client has been logged out because no packets were received before the timeout.",
74 "",
75 "",
76 "clientstack",
77 scene.Name,
78 StatType.Pull,
79 MeasuresOfInterest.None,
80 stat => stat.Value = m_udpServer.ClientLogoutsDueToNoReceives,
81 StatVerbosity.Debug));
82
83 StatsManager.RegisterStat(
84 new Stat(
85 "IncomingUDPReceivesCount",
86 "Number of UDP receives performed",
87 "",
88 "",
89 "clientstack",
90 scene.Name,
91 StatType.Pull,
92 MeasuresOfInterest.AverageChangeOverTime,
93 stat => stat.Value = m_udpServer.UdpReceives,
94 StatVerbosity.Debug));
95
96 StatsManager.RegisterStat(
97 new Stat(
76 "IncomingPacketsProcessedCount", 98 "IncomingPacketsProcessedCount",
77 "Number of inbound UDP packets processed", 99 "Number of inbound LL protocol packets processed",
78 "Number of inbound UDP packets processed", 100 "",
79 "", 101 "",
80 "clientstack", 102 "clientstack",
81 scene.Name, 103 scene.Name,
@@ -83,6 +105,86 @@ namespace OpenSim.Region.ClientStack.LindenUDP
83 MeasuresOfInterest.AverageChangeOverTime, 105 MeasuresOfInterest.AverageChangeOverTime,
84 stat => stat.Value = m_udpServer.IncomingPacketsProcessed, 106 stat => stat.Value = m_udpServer.IncomingPacketsProcessed,
85 StatVerbosity.Debug)); 107 StatVerbosity.Debug));
108
109 StatsManager.RegisterStat(
110 new Stat(
111 "IncomingPacketsMalformedCount",
112 "Number of inbound UDP packets that could not be recognized as LL protocol packets.",
113 "",
114 "",
115 "clientstack",
116 scene.Name,
117 StatType.Pull,
118 MeasuresOfInterest.AverageChangeOverTime,
119 stat => stat.Value = m_udpServer.IncomingMalformedPacketCount,
120 StatVerbosity.Info));
121
122 StatsManager.RegisterStat(
123 new Stat(
124 "IncomingPacketsOrphanedCount",
125 "Number of inbound packets that were not initial connections packets and could not be associated with a viewer.",
126 "",
127 "",
128 "clientstack",
129 scene.Name,
130 StatType.Pull,
131 MeasuresOfInterest.AverageChangeOverTime,
132 stat => stat.Value = m_udpServer.IncomingOrphanedPacketCount,
133 StatVerbosity.Info));
134
135 StatsManager.RegisterStat(
136 new Stat(
137 "IncomingPacketsResentCount",
138 "Number of inbound packets that clients indicate are resends.",
139 "",
140 "",
141 "clientstack",
142 scene.Name,
143 StatType.Pull,
144 MeasuresOfInterest.AverageChangeOverTime,
145 stat => stat.Value = m_udpServer.IncomingPacketsResentCount,
146 StatVerbosity.Debug));
147
148 StatsManager.RegisterStat(
149 new Stat(
150 "OutgoingUDPSendsCount",
151 "Number of UDP sends performed",
152 "",
153 "",
154 "clientstack",
155 scene.Name,
156 StatType.Pull,
157 MeasuresOfInterest.AverageChangeOverTime,
158 stat => stat.Value = m_udpServer.UdpSends,
159 StatVerbosity.Debug));
160
161 StatsManager.RegisterStat(
162 new Stat(
163 "OutgoingPacketsResentCount",
164 "Number of packets resent because a client did not acknowledge receipt",
165 "",
166 "",
167 "clientstack",
168 scene.Name,
169 StatType.Pull,
170 MeasuresOfInterest.AverageChangeOverTime,
171 stat => stat.Value = m_udpServer.PacketsResentCount,
172 StatVerbosity.Debug));
173
174 StatsManager.RegisterStat(
175 new Stat(
176 "AverageUDPProcessTime",
177 "Average number of milliseconds taken to process each incoming UDP packet in a sample.",
178 "This is for initial receive processing which is separate from the later client LL packet processing stage.",
179 "ms",
180 "clientstack",
181 scene.Name,
182 StatType.Pull,
183 MeasuresOfInterest.None,
184 stat => stat.Value = m_udpServer.AverageReceiveTicksForLastSamplePeriod / TimeSpan.TicksPerMillisecond,
185// stat =>
186// stat.Value = Math.Round(m_udpServer.AverageReceiveTicksForLastSamplePeriod / TimeSpan.TicksPerMillisecond, 7),
187 StatVerbosity.Debug));
86 } 188 }
87 189
88 public bool HandlesRegion(Location x) 190 public bool HandlesRegion(Location x)
@@ -107,10 +209,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
107 /// </summary> 209 /// </summary>
108 public class LLUDPServer : OpenSimUDPBase 210 public class LLUDPServer : OpenSimUDPBase
109 { 211 {
212 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
213
110 /// <summary>Maximum transmission unit, or UDP packet size, for the LLUDP protocol</summary> 214 /// <summary>Maximum transmission unit, or UDP packet size, for the LLUDP protocol</summary>
111 public const int MTU = 1400; 215 public const int MTU = 1400;
112 216
113 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 217 /// <summary>Number of forced client logouts due to no receipt of packets before timeout.</summary>
218 public int ClientLogoutsDueToNoReceives { get; private set; }
219
220 /// <summary>
221 /// Default packet debug level given to new clients
222 /// </summary>
223 public int DefaultClientPacketDebugLevel { get; set; }
114 224
115 /// <summary>The measured resolution of Environment.TickCount</summary> 225 /// <summary>The measured resolution of Environment.TickCount</summary>
116 public readonly float TickCountResolution; 226 public readonly float TickCountResolution;
@@ -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 }